use of com.linkedin.r2.message.stream.entitystream.EntityStream 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);
}
use of com.linkedin.r2.message.stream.entitystream.EntityStream 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);
}
}
use of com.linkedin.r2.message.stream.entitystream.EntityStream in project rest.li by linkedin.
the class TestMIMEReaderStateTransitions method testDrainAllPartsMultiPartMIMEReader.
@Test
public void testDrainAllPartsMultiPartMIMEReader() {
final EntityStream entityStream = mock(EntityStream.class);
final StreamRequest streamRequest = mock(StreamRequest.class);
when(streamRequest.getEntityStream()).thenReturn(entityStream);
when(streamRequest.getHeader(MultiPartMIMEUtils.CONTENT_TYPE_HEADER)).thenReturn("multipart/mixed; boundary=\"--123\"");
MultiPartMIMEReader reader = MultiPartMIMEReader.createAndAcquireStream(streamRequest);
// Test each possible exception:
reader.setState(MultiPartMIMEReader.MultiPartReaderState.FINISHED);
try {
reader.drainAllParts();
Assert.fail();
} catch (MultiPartReaderFinishedException multiPartReaderFinishedException) {
}
reader.setState(MultiPartMIMEReader.MultiPartReaderState.READING_EPILOGUE);
try {
reader.drainAllParts();
Assert.fail();
} catch (MultiPartReaderFinishedException multiPartReaderFinishedException) {
}
reader.setState(MultiPartMIMEReader.MultiPartReaderState.CALLBACK_BOUND_AND_READING_PREAMBLE);
try {
reader.drainAllParts();
Assert.fail();
} catch (StreamBusyException streamBusyException) {
}
reader.setState(MultiPartMIMEReader.MultiPartReaderState.DRAINING);
try {
reader.drainAllParts();
Assert.fail();
} catch (StreamBusyException streamBusyException) {
}
// This is the desired top level reader state
reader.setState(MultiPartMIMEReader.MultiPartReaderState.READING_PARTS);
final MultiPartMIMEReader.SinglePartMIMEReader singlePartMIMEReader = reader.new SinglePartMIMEReader(Collections.<String, String>emptyMap());
// This is a undesired single part state
singlePartMIMEReader.setState(MultiPartMIMEReader.SingleReaderState.REQUESTED_DATA);
reader.setCurrentSinglePartMIMEReader(singlePartMIMEReader);
try {
reader.drainAllParts();
Assert.fail();
} catch (StreamBusyException streamBusyException) {
}
}
use of com.linkedin.r2.message.stream.entitystream.EntityStream in project rest.li by linkedin.
the class TestMIMEReaderStateTransitions method testRegisterSinglePartMIMEReaderCallbackTwice.
// /////////////////////////////////////////////////////////////////////////////////////
// SinglePartMIMEReader exceptions:
@Test
public void testRegisterSinglePartMIMEReaderCallbackTwice() {
final EntityStream entityStream = mock(EntityStream.class);
final StreamRequest streamRequest = mock(StreamRequest.class);
when(streamRequest.getEntityStream()).thenReturn(entityStream);
when(streamRequest.getHeader(MultiPartMIMEUtils.CONTENT_TYPE_HEADER)).thenReturn("multipart/mixed; boundary=\"--123\"");
MultiPartMIMEReader reader = MultiPartMIMEReader.createAndAcquireStream(streamRequest);
final MultiPartMIMEReader.SinglePartMIMEReader singlePartMIMEReader = reader.new SinglePartMIMEReader(Collections.<String, String>emptyMap());
// This is a undesired single part state
singlePartMIMEReader.setState(MultiPartMIMEReader.SingleReaderState.REQUESTED_DATA);
try {
singlePartMIMEReader.registerReaderCallback(EMPTY_SINGLE_PART_MIME_READER_CALLBACK);
Assert.fail();
} catch (SinglePartBindException singlePartBindException) {
}
}
use of com.linkedin.r2.message.stream.entitystream.EntityStream in project rest.li by linkedin.
the class TestMIMEReaderStateTransitions method testSinglePartMIMEReaderRequestData.
@Test
public void testSinglePartMIMEReaderRequestData() {
final EntityStream entityStream = mock(EntityStream.class);
final StreamRequest streamRequest = mock(StreamRequest.class);
when(streamRequest.getEntityStream()).thenReturn(entityStream);
when(streamRequest.getHeader(MultiPartMIMEUtils.CONTENT_TYPE_HEADER)).thenReturn("multipart/mixed; boundary=\"--123\"");
MultiPartMIMEReader reader = MultiPartMIMEReader.createAndAcquireStream(streamRequest);
final MultiPartMIMEReader.SinglePartMIMEReader singlePartMIMEReader = reader.new SinglePartMIMEReader(Collections.<String, String>emptyMap());
singlePartMIMEReader.setState(MultiPartMIMEReader.SingleReaderState.CREATED);
try {
singlePartMIMEReader.requestPartData();
Assert.fail();
} catch (SinglePartNotInitializedException singlePartNotInitializedException) {
}
}
Aggregations