Search in sources :

Example 21 with NextFilter

use of com.linkedin.r2.filter.NextFilter 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()) {
                byte[] decompressedContent = encoding.getCompressor().inflate(req.getEntity().asInputStream());
                Map<String, String> headers = new HashMap<String, String>(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) RestResponse(com.linkedin.r2.message.rest.RestResponse) RestResponseBuilder(com.linkedin.r2.message.rest.RestResponseBuilder) RestException(com.linkedin.r2.message.rest.RestException)

Example 22 with NextFilter

use of com.linkedin.r2.filter.NextFilter 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();
                    byte[] compressed = compressor.deflate(res.getEntity().asInputStream());
                    if (compressed.length < res.getEntity().length()) {
                        RestResponseBuilder resCompress = res.builder();
                        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 : RestResponseBuilder(com.linkedin.r2.message.rest.RestResponseBuilder)

Example 23 with NextFilter

use of com.linkedin.r2.filter.NextFilter in project rest.li by linkedin.

the class ServerStreamCompressionFilter method onStreamResponse.

/**
   * Optionally compresses outgoing response
   * */
@Override
public void onStreamResponse(final StreamResponse res, final RequestContext requestContext, final Map<String, String> wireAttrs, final NextFilter<StreamRequest, StreamResponse> nextFilter) {
    StreamResponse response = res;
    try {
        String responseCompression = (String) requestContext.getLocalAttr(HttpConstants.ACCEPT_ENCODING);
        if (responseCompression == null) {
            throw new CompressionException(HttpConstants.ACCEPT_ENCODING + " not in local attribute.");
        }
        List<AcceptEncoding> parsedEncodings = AcceptEncoding.parseAcceptEncodingHeader(responseCompression, _supportedEncoding);
        StreamEncodingType selectedEncoding = AcceptEncoding.chooseBest(parsedEncodings);
        //Check if there exists an acceptable encoding
        if (selectedEncoding == null) {
            //Not acceptable encoding status
            response = new StreamResponseBuilder().setStatus(HttpConstants.NOT_ACCEPTABLE).build(EntityStreams.emptyStream());
        } else if (selectedEncoding != StreamEncodingType.IDENTITY) {
            final int threshold = (Integer) requestContext.getLocalAttr(HttpConstants.HEADER_RESPONSE_COMPRESSION_THRESHOLD);
            final StreamingCompressor compressor = selectedEncoding.getCompressor(_executor);
            PartialReader reader = new PartialReader(threshold, new Callback<EntityStream[]>() {

                @Override
                public void onError(Throwable ex) {
                    nextFilter.onError(ex, requestContext, wireAttrs);
                }

                @Override
                public void onSuccess(EntityStream[] results) {
                    if (// entity stream is less than threshold
                    results.length == 1) {
                        StreamResponse response = res.builder().build(results[0]);
                        nextFilter.onResponse(response, requestContext, wireAttrs);
                    } else {
                        EntityStream compressedStream = compressor.deflate(EntityStreams.newEntityStream(new CompositeWriter(results)));
                        StreamResponseBuilder builder = res.builder();
                        // remove original content-length header if presents.
                        if (builder.getHeader(HttpConstants.CONTENT_LENGTH) != null) {
                            Map<String, String> headers = stripHeaders(builder.getHeaders(), HttpConstants.CONTENT_LENGTH);
                            builder.setHeaders(headers);
                        }
                        StreamResponse response = builder.addHeaderValue(HttpConstants.CONTENT_ENCODING, compressor.getContentEncodingName()).build(compressedStream);
                        nextFilter.onResponse(response, requestContext, wireAttrs);
                    }
                }
            });
            res.getEntityStream().setReader(reader);
            return;
        }
    } catch (CompressionException e) {
        LOG.error(e.getMessage(), e.getCause());
    }
    nextFilter.onResponse(response, requestContext, wireAttrs);
}
Also used : StreamResponseBuilder(com.linkedin.r2.message.stream.StreamResponseBuilder) StreamResponse(com.linkedin.r2.message.stream.StreamResponse) CompositeWriter(com.linkedin.r2.message.stream.entitystream.CompositeWriter) PartialReader(com.linkedin.r2.filter.compression.streaming.PartialReader) StreamEncodingType(com.linkedin.r2.filter.compression.streaming.StreamEncodingType) EntityStream(com.linkedin.r2.message.stream.entitystream.EntityStream) Callback(com.linkedin.common.callback.Callback) StreamingCompressor(com.linkedin.r2.filter.compression.streaming.StreamingCompressor) AcceptEncoding(com.linkedin.r2.filter.compression.streaming.AcceptEncoding)

Example 24 with NextFilter

use of com.linkedin.r2.filter.NextFilter in project rest.li by linkedin.

the class ServerStreamCompressionFilter method onStreamRequest.

/**
   * Handles compression tasks for incoming requests
   */
@Override
public void onStreamRequest(StreamRequest req, RequestContext requestContext, Map<String, String> wireAttrs, NextFilter<StreamRequest, StreamResponse> 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 *
            StreamEncodingType encoding = StreamEncodingType.get(requestContentEncoding.trim().toLowerCase());
            if (encoding == null || encoding == StreamEncodingType.ANY) {
                throw new CompressionException(CompressionConstants.UNSUPPORTED_ENCODING + requestContentEncoding);
            }
            //Process the correct content-encoding types only
            StreamingCompressor compressor = encoding.getCompressor(_executor);
            if (compressor == null) {
                throw new CompressionException(CompressionConstants.UNKNOWN_ENCODING + encoding);
            }
            EntityStream uncompressedStream = compressor.inflate(req.getEntityStream());
            Map<String, String> headers = stripHeaders(req.getHeaders(), HttpConstants.CONTENT_ENCODING, HttpConstants.CONTENT_LENGTH);
            req = req.builder().setHeaders(headers).build(uncompressedStream);
        }
        //Get client support for compression and flag compress if need be
        String responseCompression = req.getHeader(HttpConstants.ACCEPT_ENCODING);
        if (responseCompression == null) {
            // per RFC 2616, section 14.3, if no Accept-Encoding field is present in a request,
            // server SHOULD use "identity" content-encoding if it is available.
            responseCompression = StreamEncodingType.IDENTITY.getHttpName();
        }
        if (!responseCompression.equalsIgnoreCase(StreamEncodingType.IDENTITY.getHttpName())) {
            requestContext.putLocalAttr(HttpConstants.HEADER_RESPONSE_COMPRESSION_THRESHOLD, _serverCompressionHelper.getResponseCompressionThreshold(req));
        }
        requestContext.putLocalAttr(HttpConstants.ACCEPT_ENCODING, responseCompression);
        nextFilter.onRequest(req, requestContext, wireAttrs);
    } catch (CompressionException ex) {
        LOG.error(ex.getMessage(), ex.getCause());
        StreamResponse streamResponse = new StreamResponseBuilder().setStatus(HttpConstants.UNSUPPORTED_MEDIA_TYPE).build(EntityStreams.emptyStream());
        nextFilter.onError(new StreamException(streamResponse, ex), requestContext, wireAttrs);
    }
}
Also used : EntityStream(com.linkedin.r2.message.stream.entitystream.EntityStream) StreamResponseBuilder(com.linkedin.r2.message.stream.StreamResponseBuilder) StreamResponse(com.linkedin.r2.message.stream.StreamResponse) StreamingCompressor(com.linkedin.r2.filter.compression.streaming.StreamingCompressor) StreamEncodingType(com.linkedin.r2.filter.compression.streaming.StreamEncodingType) StreamException(com.linkedin.r2.message.stream.StreamException)

Example 25 with NextFilter

use of com.linkedin.r2.filter.NextFilter in project rest.li by linkedin.

the class ReplayFilter method replayResponse.

private boolean replayResponse(RestRequest req, RequestContext requestContext, NextFilter<RestRequest, RestResponse> nextFilter) {
    final RestResponse res = _db.replay(req);
    if (res != null) {
        _log.debug("Using cached response for request: " + req.getURI());
        // We create an empty map instead of Collections.emptyMap, because upstream filters may
        // try to modify the map.
        final Map<String, String> wireAttrs = new HashMap<String, String>();
        // exception.
        if (!RestStatus.isOK(res.getStatus())) {
            nextFilter.onError(new RestException(res), requestContext, wireAttrs);
        } else {
            nextFilter.onResponse(res, requestContext, wireAttrs);
        }
        return true;
    }
    return false;
}
Also used : HashMap(java.util.HashMap) RestResponse(com.linkedin.r2.message.rest.RestResponse) RestException(com.linkedin.r2.message.rest.RestException)

Aggregations

RequestContext (com.linkedin.r2.message.RequestContext)23 Test (org.testng.annotations.Test)22 Map (java.util.Map)18 NextFilter (com.linkedin.r2.filter.NextFilter)17 FilterChain (com.linkedin.r2.filter.FilterChain)15 RestResponse (com.linkedin.r2.message.rest.RestResponse)15 RestFilter (com.linkedin.r2.filter.message.rest.RestFilter)14 RestRequest (com.linkedin.r2.message.rest.RestRequest)14 StreamResponse (com.linkedin.r2.message.stream.StreamResponse)13 Callback (com.linkedin.common.callback.Callback)10 HashMap (java.util.HashMap)10 ByteString (com.linkedin.data.ByteString)9 StreamRequest (com.linkedin.r2.message.stream.StreamRequest)9 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)9 FullEntityReader (com.linkedin.r2.message.stream.entitystream.FullEntityReader)8 URI (java.net.URI)8 CountDownLatch (java.util.concurrent.CountDownLatch)8 StreamException (com.linkedin.r2.message.stream.StreamException)7 EntityStream (com.linkedin.r2.message.stream.entitystream.EntityStream)7 RestException (com.linkedin.r2.message.rest.RestException)6