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);
}
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);
}
}
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();
}
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());
}
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());
}
Aggregations