Search in sources :

Example 1 with ContentTypedEntity

use of org.eclipse.californium.proxy2.http.ContentTypedEntity in project californium by eclipse.

the class Http2CoapTranslator method getCoapRequest.

/**
 * Gets the coap request.
 *
 * Creates the CoAP request from the HTTP method and mapping it through the
 * properties file. The URI is translated by extracting the part after the
 * provided httpResource.
 * (http://proxyname.domain:80/proxy/coap://coapserver:5683/resource
 * converted in coap://coapserver:5683/resource.) It support proxy requests
 * or request mapped to a local coap-server. It also support http-request
 * send to this proxy using the http-proxy function itself. Though the
 * primary scheme maybe tested to be http/https, the destination scheme must
 * The method uses a decoder to translate the
 * application/x-www-form-urlencoded format of the uri. The CoAP options are
 * set translating the headers. If the HTTP message has an enclosing entity,
 * it is converted to create the payload of the CoAP message; finally the
 * content-type is set accordingly to the header and to the entity type.
 *
 * @param httpRequest the http request
 * @param httpResource the http resource, if present in the uri, indicates
 *            the need of forwarding for the current request
 * @param proxyingEnabled {@code true} to forward the request using the
 *            sub-path as URI, {@code false} to access a local coap
 *            resource.
 * @return the coap request
 * @throws TranslationException the translation exception
 * @throws NullPointerException if one of the provided arguments is
 *             {@code null}.
 */
public Request getCoapRequest(Message<HttpRequest, ContentTypedEntity> httpRequest, String httpResource, boolean proxyingEnabled) throws TranslationException {
    if (httpRequest == null) {
        throw new NullPointerException("httpRequest must not be null!");
    }
    if (httpResource == null) {
        throw new NullPointerException("httpResource must not be null!");
    }
    // get the http method
    String httpMethod = httpRequest.getHead().getMethod();
    // get the coap method
    Code code = httpTranslator.getCoapCode(httpMethod);
    // create the request -- since HTTP is reliable use CON
    Request coapRequest = new Request(code, Type.CON);
    // get the uri
    URI uri;
    try {
        uri = httpRequest.getHead().getUri();
        LOGGER.debug("URI <= '{}'", uri);
    } catch (URISyntaxException ex) {
        throw new TranslationException("Malformed uri: " + ex.getMessage());
    }
    if (!httpResource.startsWith("/")) {
        httpResource = "/" + httpResource;
    }
    // if the uri contains the proxy resource name, the request should be
    // forwarded and it is needed to get the real requested coap server's
    // uri e.g.:
    // /proxy/coap://vslab-dhcp-17.inf.ethz.ch:5684/helloWorld
    // proxy resource: /proxy
    // coap server: coap://vslab-dhcp-17.inf.ethz.ch:5684
    // coap resource: helloWorld
    String path = uri.getPath();
    LOGGER.debug("URI path => '{}'", path);
    if (path.startsWith(httpResource + "/")) {
        path = path.substring(httpResource.length() + 1);
        String target = path;
        if (uri.getQuery() != null) {
            target = path + "?" + uri.getQuery();
        }
        int index = target.indexOf(":/");
        if (index > 0) {
            // "coap://host" may have been normalized to "coap:/host"
            index += 2;
            if (target.charAt(index) != '/') {
                // add /
                target = target.substring(0, index) + "/" + target.substring(index);
            }
        }
        try {
            uri = new URI(target);
            if (proxyingEnabled) {
                // if the uri hasn't the indication of the scheme, add it
                if (uri.getScheme() == null) {
                    throw new InvalidFieldException("Malformed uri: destination scheme missing! Use http://<proxy-host>" + httpResource + "/coap://<destination-host>/<path>");
                }
                // the uri will be set as a proxy-uri option
                LOGGER.debug("URI destination => '{}'", target);
                coapRequest.getOptions().setProxyUri(target);
            } else {
                if (uri.getScheme() != null) {
                    throw new InvalidFieldException("Malformed uri: local destination doesn't support scheme! Use http://<proxy-host>" + httpResource + "/<path>");
                }
                // the uri will be set as a coap-uri
                target = "coap://localhost/" + target;
                LOGGER.debug("URI local => '{}'", target);
                coapRequest.setURI(target);
            }
        } catch (URISyntaxException e) {
            LOGGER.warn("Malformed destination uri", e);
            throw new InvalidFieldException("Malformed destination uri: " + target + "!");
        }
    } else if (proxyingEnabled && path.equals(httpResource)) {
        String target = null;
        if (uri.getQuery() != null) {
            List<NameValuePair> query = WWWFormCodec.parse(uri.getQuery(), StandardCharsets.UTF_8);
            for (NameValuePair arg : query) {
                if (arg.getName().equalsIgnoreCase("target_uri")) {
                    target = arg.getValue();
                    break;
                }
            }
        }
        if (target == null) {
            throw new InvalidFieldException("Malformed uri: target_uri is missing! Use http://<proxy-host>" + httpResource + "?target_uri=coap://<destination-host>/<path>");
        }
        try {
            uri = new URI(target);
            // if the uri hasn't the indication of the scheme, add it
            if (uri.getScheme() == null) {
                throw new InvalidFieldException("Malformed uri: destination scheme missing! Use http://<proxy-host>" + httpResource + "?target_uri=coap://<destination-host>/<path>");
            }
            // the uri will be set as a proxy-uri option
            LOGGER.debug("URI destination => '{}'", target);
            coapRequest.getOptions().setProxyUri(target);
        } catch (URISyntaxException e) {
            LOGGER.warn("Malformed destination uri", e);
            throw new InvalidFieldException("Malformed destination uri: " + target + "!");
        }
    } else if (proxyingEnabled && uri.getScheme() != null) {
        // http-server configured as http-proxy
        int index = path.lastIndexOf('/');
        if (0 < index) {
            String scheme = path.substring(index + 1);
            if (scheme.matches("\\w+:$")) {
                scheme = scheme.substring(0, scheme.length() - 1);
                path = path.substring(0, index);
                try {
                    URI destination = new URI(scheme, null, uri.getHost(), uri.getPort(), path, uri.getQuery(), null);
                    coapRequest.getOptions().setProxyUri(destination.toASCIIString());
                } catch (URISyntaxException e) {
                    LOGGER.debug("Malformed proxy uri", e);
                    throw new TranslationException("Malformed proxy uri: '" + uri + "' " + e.getMessage());
                }
            } else {
                throw new TranslationException("Malformed proxy uri: target scheme missing! Use http://<destination-host>/<path>/<target-scheme>:");
            }
        } else {
            throw new TranslationException("Malformed proxy uri: target scheme missing! Use http://<destination-host>/<path>/<target-scheme>:");
        }
    } else {
        throw new IllegalArgumentException("URI '" + uri + "' doesn't match handler '" + httpResource + "'!");
    }
    // translate the http headers in coap options
    List<Option> coapOptions = httpTranslator.getCoapOptions(httpRequest.getHead().getHeaders(), etagTranslator);
    coapRequest.getOptions().addOptions(coapOptions);
    // set the payload if the http entity is present
    ContentTypedEntity entity = httpRequest.getBody();
    httpTranslator.setCoapPayload(entity, coapRequest);
    return coapRequest;
}
Also used : NameValuePair(org.apache.hc.core5.http.NameValuePair) Request(org.eclipse.californium.core.coap.Request) HttpRequest(org.apache.hc.core5.http.HttpRequest) TranslationException(org.eclipse.californium.proxy2.TranslationException) URISyntaxException(java.net.URISyntaxException) ResponseCode(org.eclipse.californium.core.coap.CoAP.ResponseCode) Code(org.eclipse.californium.core.coap.CoAP.Code) URI(java.net.URI) List(java.util.List) Option(org.eclipse.californium.core.coap.Option) InvalidFieldException(org.eclipse.californium.proxy2.InvalidFieldException)

Example 2 with ContentTypedEntity

use of org.eclipse.californium.proxy2.http.ContentTypedEntity in project californium by eclipse.

the class ProxyHttpClientResource method handleRequest.

@Override
public void handleRequest(final Exchange exchange) {
    final Request incomingCoapRequest = exchange.getRequest();
    URI destination;
    try {
        InetSocketAddress exposedInterface = translator.getExposedInterface(incomingCoapRequest);
        destination = translator.getDestinationURI(incomingCoapRequest, exposedInterface);
    } catch (TranslationException ex) {
        LOGGER.debug("URI error.", ex);
        Response response = new Response(Coap2CoapTranslator.STATUS_FIELD_MALFORMED);
        response.setPayload(ex.getMessage());
        exchange.sendResponse(response);
        return;
    }
    final CacheKey cacheKey;
    final CacheResource cache = getCache();
    if (cache != null) {
        cacheKey = new CacheKey(incomingCoapRequest.getCode(), destination, incomingCoapRequest.getOptions().getAccept(), incomingCoapRequest.getPayload());
        Response response = cache.getResponse(cacheKey);
        StatsResource statsResource = getStatsResource();
        if (statsResource != null) {
            statsResource.updateStatistics(destination, response != null);
        }
        if (response != null) {
            LOGGER.info("Cache returned {}", response);
            exchange.sendResponse(response);
            return;
        }
    } else {
        cacheKey = null;
    }
    ProxyRequestProducer httpRequest = null;
    try {
        // get the mapping to http for the incoming coap request
        httpRequest = translator.getHttpRequest(destination, incomingCoapRequest);
        LOGGER.debug("Outgoing http request: {}", httpRequest.getRequestLine());
    } catch (InvalidFieldException e) {
        LOGGER.debug("Problems during the http/coap translation: {}", e.getMessage());
        exchange.sendResponse(new Response(Coap2CoapTranslator.STATUS_FIELD_MALFORMED));
        return;
    } catch (TranslationException e) {
        LOGGER.debug("Problems during the http/coap translation: {}", e.getMessage());
        exchange.sendResponse(new Response(Coap2CoapTranslator.STATUS_TRANSLATION_ERROR));
        return;
    }
    if (accept) {
        exchange.sendAccept();
    }
    asyncClient.execute(httpRequest, new BasicResponseConsumer<ContentTypedEntity>(new ContentTypedEntityConsumer()), new BasicHttpContext(), new FutureCallback<Message<HttpResponse, ContentTypedEntity>>() {

        @Override
        public void completed(Message<HttpResponse, ContentTypedEntity> result) {
            StatusLine status = new StatusLine(result.getHead());
            try {
                long timestamp = ClockUtil.nanoRealtime();
                LOGGER.debug("Incoming http response: {}", status);
                // the entity of the response, if non repeatable,
                // could be
                // consumed only one time, so do not debug it!
                // System.out.println(EntityUtils.toString(httpResponse.getEntity()));
                // translate the received http response in a coap
                // response
                Response coapResponse = translator.getCoapResponse(result, incomingCoapRequest);
                coapResponse.setNanoTimestamp(timestamp);
                if (cache != null) {
                    cache.cacheResponse(cacheKey, coapResponse);
                }
                exchange.sendResponse(coapResponse);
            } catch (InvalidFieldException e) {
                LOGGER.debug("Problems during the http/coap translation: {}", e.getMessage());
                exchange.sendResponse(new Response(Coap2CoapTranslator.STATUS_FIELD_MALFORMED));
            } catch (TranslationException e) {
                LOGGER.debug("Problems during the http/coap translation: {}", e.getMessage());
                exchange.sendResponse(new Response(Coap2CoapTranslator.STATUS_TRANSLATION_ERROR));
            } catch (Throwable e) {
                LOGGER.debug("Error during the http/coap translation: {}", e.getMessage(), e);
                exchange.sendResponse(new Response(Coap2CoapTranslator.STATUS_FIELD_MALFORMED));
            }
            LOGGER.debug("Incoming http response: {} processed!", status);
        }

        @Override
        public void failed(Exception ex) {
            LOGGER.debug("Failed to get the http response: {}", ex.getMessage(), ex);
            if (ex instanceof SocketTimeoutException) {
                exchange.sendResponse(new Response(ResponseCode.GATEWAY_TIMEOUT));
            } else {
                exchange.sendResponse(new Response(ResponseCode.BAD_GATEWAY));
            }
        }

        @Override
        public void cancelled() {
            LOGGER.debug("Request canceled");
            exchange.sendResponse(new Response(ResponseCode.SERVICE_UNAVAILABLE));
        }
    });
}
Also used : ContentTypedEntity(org.eclipse.californium.proxy2.http.ContentTypedEntity) Message(org.apache.hc.core5.http.Message) InetSocketAddress(java.net.InetSocketAddress) ProxyRequestProducer(org.eclipse.californium.proxy2.http.ProxyRequestProducer) BasicHttpContext(org.apache.hc.core5.http.protocol.BasicHttpContext) Request(org.eclipse.californium.core.coap.Request) HttpResponse(org.apache.hc.core5.http.HttpResponse) TranslationException(org.eclipse.californium.proxy2.TranslationException) URI(java.net.URI) InvalidFieldException(org.eclipse.californium.proxy2.InvalidFieldException) SocketTimeoutException(java.net.SocketTimeoutException) TranslationException(org.eclipse.californium.proxy2.TranslationException) Response(org.eclipse.californium.core.coap.Response) HttpResponse(org.apache.hc.core5.http.HttpResponse) ContentTypedEntityConsumer(org.eclipse.californium.proxy2.http.ContentTypedEntityConsumer) StatusLine(org.apache.hc.core5.http.message.StatusLine) SocketTimeoutException(java.net.SocketTimeoutException) InvalidFieldException(org.eclipse.californium.proxy2.InvalidFieldException)

Example 3 with ContentTypedEntity

use of org.eclipse.californium.proxy2.http.ContentTypedEntity in project californium by eclipse.

the class CrossProtocolTranslator method setCoapPayload.

/**
 * Method to map the http entity in a coherent payload for the coap message.
 *
 * The method simply gets the bytes from the entity and, if needed changes
 * the charset of the obtained bytes to UTF-8.
 *
 * @param httpBody the http entity. May be {@code null} or empty.
 * @param coapMessage the coap message
 * @throws TranslationException the translation exception
 * @throws NullPointerException if the coap-message is {@code null}
 */
public void setCoapPayload(ContentTypedEntity httpBody, Message coapMessage) throws TranslationException {
    if (coapMessage == null) {
        throw new NullPointerException("coap message must not be null!");
    }
    if (httpBody != null) {
        byte[] payload = httpBody.getContent();
        if (payload != null) {
            ContentType contentType = httpBody.getContentType();
            int coapContentType = getCoapMediaType(contentType.getMimeType());
            coapMessage.getOptions().setContentFormat(coapContentType);
            if (MediaTypeRegistry.isCharsetConvertible(coapContentType)) {
                try {
                    // get the charset for the http entity
                    Charset httpCharset = contentType.getCharset();
                    // coap
                    if (httpCharset != null && !httpCharset.equals(UTF_8)) {
                        // translate the payload to the utf-8 charset
                        payload = convertCharset(payload, httpCharset, UTF_8);
                    }
                } catch (UnsupportedCharsetException e) {
                    LOGGER.debug("Cannot get the content of the http entity: " + e.getMessage());
                    throw new TranslationException("Cannot get the content of the http entity", e);
                }
            }
            coapMessage.setPayload(payload);
        }
    }
}
Also used : ContentType(org.apache.hc.core5.http.ContentType) UnsupportedCharsetException(java.nio.charset.UnsupportedCharsetException) Charset(java.nio.charset.Charset) TranslationException(org.eclipse.californium.proxy2.TranslationException)

Aggregations

TranslationException (org.eclipse.californium.proxy2.TranslationException)3 URI (java.net.URI)2 Request (org.eclipse.californium.core.coap.Request)2 InvalidFieldException (org.eclipse.californium.proxy2.InvalidFieldException)2 InetSocketAddress (java.net.InetSocketAddress)1 SocketTimeoutException (java.net.SocketTimeoutException)1 URISyntaxException (java.net.URISyntaxException)1 Charset (java.nio.charset.Charset)1 UnsupportedCharsetException (java.nio.charset.UnsupportedCharsetException)1 List (java.util.List)1 ContentType (org.apache.hc.core5.http.ContentType)1 HttpRequest (org.apache.hc.core5.http.HttpRequest)1 HttpResponse (org.apache.hc.core5.http.HttpResponse)1 Message (org.apache.hc.core5.http.Message)1 NameValuePair (org.apache.hc.core5.http.NameValuePair)1 StatusLine (org.apache.hc.core5.http.message.StatusLine)1 BasicHttpContext (org.apache.hc.core5.http.protocol.BasicHttpContext)1 Code (org.eclipse.californium.core.coap.CoAP.Code)1 ResponseCode (org.eclipse.californium.core.coap.CoAP.ResponseCode)1 Option (org.eclipse.californium.core.coap.Option)1