Search in sources :

Example 81 with RestResponseBuilder

use of com.linkedin.r2.message.rest.RestResponseBuilder in project rest.li by linkedin.

the class ServerCompressionFilter method onRestResponse.

/**
 * Optionally compresses outgoing response
 */
@Override
public void onRestResponse(RestResponse res, RequestContext requestContext, Map<String, String> wireAttrs, NextFilter<RestRequest, RestResponse> nextFilter) {
    try {
        if (res.getEntity().length() > 0) {
            String responseAcceptedEncodings = (String) requestContext.getLocalAttr(HttpConstants.ACCEPT_ENCODING);
            if (responseAcceptedEncodings == null) {
                throw new CompressionException(HttpConstants.ACCEPT_ENCODING + " not in local attribute.");
            }
            List<AcceptEncoding> parsedEncodings = AcceptEncoding.parseAcceptEncodingHeader(responseAcceptedEncodings, _supportedEncoding);
            EncodingType selectedEncoding = AcceptEncoding.chooseBest(parsedEncodings);
            // Check if there exists an acceptable encoding
            if (selectedEncoding != null) {
                if (selectedEncoding.hasCompressor() && res.getEntity().length() > (Integer) requestContext.getLocalAttr(HttpConstants.HEADER_RESPONSE_COMPRESSION_THRESHOLD)) {
                    Compressor compressor = selectedEncoding.getCompressor();
                    ByteString compressed = compressor.deflate(res.getEntity());
                    if (compressed.length() < res.getEntity().length()) {
                        RestResponseBuilder resCompress = res.builder();
                        resCompress.removeHeader(HttpConstants.CONTENT_LENGTH);
                        resCompress.addHeaderValue(HttpConstants.CONTENT_ENCODING, compressor.getContentEncodingName());
                        resCompress.setEntity(compressed);
                        res = resCompress.build();
                    }
                }
            } else {
                // Not acceptable encoding status
                res = res.builder().setStatus(HttpConstants.NOT_ACCEPTABLE).setEntity(new byte[0]).build();
            }
        }
    } catch (CompressionException e) {
        LOG.error(e.getMessage(), e.getCause());
    }
    nextFilter.onResponse(res, requestContext, wireAttrs);
}
Also used : ByteString(com.linkedin.data.ByteString) RestResponseBuilder(com.linkedin.r2.message.rest.RestResponseBuilder) ByteString(com.linkedin.data.ByteString)

Example 82 with RestResponseBuilder

use of com.linkedin.r2.message.rest.RestResponseBuilder in project rest.li by linkedin.

the class ServerCompressionFilter method onRestRequest.

/**
 * Handles compression tasks for incoming requests
 */
@Override
public void onRestRequest(RestRequest req, RequestContext requestContext, Map<String, String> wireAttrs, NextFilter<RestRequest, RestResponse> nextFilter) {
    try {
        // Check if the request is compressed, if so, decompress
        String requestContentEncoding = req.getHeader(HttpConstants.CONTENT_ENCODING);
        if (requestContentEncoding != null) {
            // This must be a specific compression type other than *
            EncodingType encoding;
            try {
                encoding = EncodingType.get(requestContentEncoding.trim().toLowerCase());
            } catch (IllegalArgumentException ex) {
                throw new CompressionException(CompressionConstants.UNSUPPORTED_ENCODING + requestContentEncoding);
            }
            if (encoding == EncodingType.ANY) {
                throw new CompressionException(CompressionConstants.REQUEST_ANY_ERROR + requestContentEncoding);
            }
            // Process the correct compression types only
            if (encoding.hasCompressor()) {
                ByteString decompressedContent = encoding.getCompressor().inflate(req.getEntity());
                Map<String, String> headers = new HashMap<>(req.getHeaders());
                headers.remove(HttpConstants.CONTENT_ENCODING);
                headers.put(HttpConstants.CONTENT_LENGTH, Integer.toString(decompressedContent.length()));
                req = req.builder().setEntity(decompressedContent).setHeaders(headers).build();
            }
        }
        // Get client support for compression and flag compress if need be
        String responseAcceptedEncodings = req.getHeader(HttpConstants.ACCEPT_ENCODING);
        if (responseAcceptedEncodings == null) {
            // Only permit identity
            responseAcceptedEncodings = EMPTY;
        }
        requestContext.putLocalAttr(HttpConstants.ACCEPT_ENCODING, responseAcceptedEncodings);
        if (!responseAcceptedEncodings.isEmpty()) {
            requestContext.putLocalAttr(HttpConstants.HEADER_RESPONSE_COMPRESSION_THRESHOLD, _serverCompressionHelper.getResponseCompressionThreshold(req));
        }
        nextFilter.onRequest(req, requestContext, wireAttrs);
    } catch (CompressionException e) {
        // If we can't decompress the client's request, we can't do much more with it
        LOG.error(e.getMessage(), e.getCause());
        RestResponse restResponse = new RestResponseBuilder().setStatus(HttpConstants.UNSUPPORTED_MEDIA_TYPE).build();
        nextFilter.onError(new RestException(restResponse, e), requestContext, wireAttrs);
    }
}
Also used : HashMap(java.util.HashMap) ByteString(com.linkedin.data.ByteString) RestResponse(com.linkedin.r2.message.rest.RestResponse) RestResponseBuilder(com.linkedin.r2.message.rest.RestResponseBuilder) RestException(com.linkedin.r2.message.rest.RestException) ByteString(com.linkedin.data.ByteString)

Example 83 with RestResponseBuilder

use of com.linkedin.r2.message.rest.RestResponseBuilder in project rest.li by linkedin.

the class DefaultDocumentationRequestHandler method processDocumentationRequest.

@SuppressWarnings("fallthrough")
private RestResponse processDocumentationRequest(Request request) {
    final String path = request.getURI().getRawPath();
    final List<UriComponent.PathSegment> pathSegments = UriComponent.decodePath(path, true);
    String prefixSegment = null;
    String actionSegment = null;
    String typeSegment = null;
    String objectSegment = null;
    switch(pathSegments.size()) {
        case 5:
            objectSegment = pathSegments.get(4).getPath();
        case 4:
            typeSegment = pathSegments.get(3).getPath();
        case 3:
            actionSegment = pathSegments.get(2).getPath();
        case 2:
            prefixSegment = pathSegments.get(1).getPath();
    }
    assert (DOC_PREFIX.equals(prefixSegment) || (HttpMethod.valueOf(request.getMethod()) == HttpMethod.OPTIONS));
    final ByteArrayOutputStream out = new ByteArrayOutputStream(BAOS_BUFFER_SIZE);
    final RenderContext renderContext = new RenderContext(out, request.getHeaders());
    final RestLiDocumentationRenderer renderer;
    if (HttpMethod.valueOf(request.getMethod()) == HttpMethod.OPTIONS) {
        renderer = _jsonRenderer;
        renderer.renderResource(prefixSegment, renderContext);
    } else if (HttpMethod.valueOf(request.getMethod()) == HttpMethod.GET) {
        if (!DOC_VIEW_DOCS_ACTION.equals(actionSegment)) {
            throw createRoutingError(path);
        }
        final MultivaluedMap queryMap = UriComponent.decodeQuery(request.getURI().getQuery(), false);
        final List<String> formatList = queryMap.get("format");
        if (formatList == null) {
            renderer = _htmlRenderer;
        } else if (formatList.size() > 1) {
            throw new RoutingException(String.format("\"format\" query parameter must be unique, where multiple are specified: %s", Arrays.toString(formatList.toArray())), HttpStatus.S_400_BAD_REQUEST.getCode());
        } else {
            renderer = (formatList.contains(DOC_JSON_FORMAT) ? _jsonRenderer : _htmlRenderer);
        }
        if (renderer == _htmlRenderer) {
            _htmlRenderer.setFormatUriProvider(docFormat -> {
                if (RestLiDocumentationRenderer.DocumentationFormat.JSON.equals(docFormat)) {
                    return UriBuilder.fromUri(_config.getServerNodeUri()).path(request.getURI().getPath()).queryParam("format", DOC_JSON_FORMAT).build();
                }
                return null;
            });
        }
        try {
            if (typeSegment == null || typeSegment.isEmpty()) {
                renderer.renderHome(renderContext);
            } else {
                if (DOC_RESOURCE_TYPE.equals(typeSegment)) {
                    if (objectSegment == null || objectSegment.isEmpty()) {
                        renderer.renderResourceHome(renderContext);
                    } else {
                        renderer.renderResource(objectSegment, renderContext);
                    }
                } else if (DOC_DATA_TYPE.equals(typeSegment)) {
                    if (objectSegment == null || objectSegment.isEmpty()) {
                        renderer.renderDataModelHome(renderContext);
                    } else {
                        renderer.renderDataModel(objectSegment, renderContext);
                    }
                } else {
                    throw createRoutingError(path);
                }
            }
        } catch (RuntimeException e) {
            if (!renderer.handleException(e, renderContext)) {
                throw e;
            }
        }
    } else {
        throw new RoutingException(HttpStatus.S_405_METHOD_NOT_ALLOWED.getCode());
    }
    return new RestResponseBuilder().setStatus(HttpStatus.S_200_OK.getCode()).setHeader(RestConstants.HEADER_CONTENT_TYPE, renderer.getMIMEType()).setEntity(out.toByteArray()).build();
}
Also used : RestRequest(com.linkedin.r2.message.rest.RestRequest) Arrays(java.util.Arrays) ClasspathResourceDataSchemaResolver(com.linkedin.data.schema.resolver.ClasspathResourceDataSchemaResolver) UriBuilder(com.linkedin.jersey.api.uri.UriBuilder) ByteArrayOutputStream(java.io.ByteArrayOutputStream) RoutingException(com.linkedin.restli.server.RoutingException) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Callback(com.linkedin.common.callback.Callback) RestLiConfig(com.linkedin.restli.server.RestLiConfig) RestLiDocumentationRequestHandler(com.linkedin.restli.server.RestLiDocumentationRequestHandler) DataSchemaResolver(com.linkedin.data.schema.DataSchemaResolver) RestResponse(com.linkedin.r2.message.rest.RestResponse) ResourceModel(com.linkedin.restli.internal.server.model.ResourceModel) List(java.util.List) Request(com.linkedin.r2.message.Request) RequestContext(com.linkedin.r2.message.RequestContext) RestConstants(com.linkedin.restli.common.RestConstants) HttpStatus(com.linkedin.restli.common.HttpStatus) RestLiServiceException(com.linkedin.restli.server.RestLiServiceException) Map(java.util.Map) UriComponent(com.linkedin.jersey.api.uri.UriComponent) RestResponseBuilder(com.linkedin.r2.message.rest.RestResponseBuilder) MultivaluedMap(com.linkedin.jersey.core.util.MultivaluedMap) HttpMethod(com.linkedin.restli.common.HttpMethod) RoutingException(com.linkedin.restli.server.RoutingException) RestResponseBuilder(com.linkedin.r2.message.rest.RestResponseBuilder) List(java.util.List) ByteArrayOutputStream(java.io.ByteArrayOutputStream) MultivaluedMap(com.linkedin.jersey.core.util.MultivaluedMap)

Example 84 with RestResponseBuilder

use of com.linkedin.r2.message.rest.RestResponseBuilder in project rest.li by linkedin.

the class TestChannelPoolHandler method testConnectionClose.

@Test(dataProvider = "connectionClose")
public void testConnectionClose(String headerName, String headerValue) {
    EmbeddedChannel ch = new EmbeddedChannel(new ChannelPoolHandler());
    FakePool pool = new FakePool();
    ch.attr(ChannelPoolHandler.CHANNEL_POOL_ATTR_KEY).set(pool);
    RestResponse response = new RestResponseBuilder().setHeader(headerName, headerValue).build();
    ch.writeInbound(response);
    Assert.assertTrue(pool.isDisposeCalled());
    Assert.assertFalse(pool.isPutCalled());
}
Also used : RestResponse(com.linkedin.r2.message.rest.RestResponse) RestResponseBuilder(com.linkedin.r2.message.rest.RestResponseBuilder) EmbeddedChannel(io.netty.channel.embedded.EmbeddedChannel) Test(org.testng.annotations.Test)

Example 85 with RestResponseBuilder

use of com.linkedin.r2.message.rest.RestResponseBuilder in project rest.li by linkedin.

the class TestChannelPoolHandler method testConnectionKeepAlive.

@Test(dataProvider = "connectionKeepAlive")
public void testConnectionKeepAlive(String headerName, String headerValue) {
    EmbeddedChannel ch = new EmbeddedChannel(new ChannelPoolHandler());
    FakePool pool = new FakePool();
    ch.attr(ChannelPoolHandler.CHANNEL_POOL_ATTR_KEY).set(pool);
    RestResponse response = new RestResponseBuilder().setHeader(headerName, headerValue).build();
    ch.writeInbound(response);
    Assert.assertFalse(pool.isDisposeCalled());
    Assert.assertTrue(pool.isPutCalled());
}
Also used : RestResponse(com.linkedin.r2.message.rest.RestResponse) RestResponseBuilder(com.linkedin.r2.message.rest.RestResponseBuilder) EmbeddedChannel(io.netty.channel.embedded.EmbeddedChannel) Test(org.testng.annotations.Test)

Aggregations

RestResponseBuilder (com.linkedin.r2.message.rest.RestResponseBuilder)87 RestResponse (com.linkedin.r2.message.rest.RestResponse)55 Test (org.testng.annotations.Test)53 RestRequest (com.linkedin.r2.message.rest.RestRequest)22 RestException (com.linkedin.r2.message.rest.RestException)18 RestRequestBuilder (com.linkedin.r2.message.rest.RestRequestBuilder)17 RequestContext (com.linkedin.r2.message.RequestContext)15 ByteString (com.linkedin.data.ByteString)13 Map (java.util.Map)10 RestLiServiceException (com.linkedin.restli.server.RestLiServiceException)8 HashMap (java.util.HashMap)8 TransportCallback (com.linkedin.r2.transport.common.bridge.common.TransportCallback)6 RoutingException (com.linkedin.restli.server.RoutingException)6 DataMap (com.linkedin.data.DataMap)5 FilterChain (com.linkedin.r2.filter.FilterChain)5 CaptureLastCallFilter (com.linkedin.r2.testutils.filter.CaptureLastCallFilter)5 FilterRequestContext (com.linkedin.restli.server.filter.FilterRequestContext)5 FilterResponseContext (com.linkedin.restli.server.filter.FilterResponseContext)5 IOException (java.io.IOException)5 URI (java.net.URI)5