private static Predicate[] getCompressionPredicates(Compression compression) { List<Predicate> predicates = new ArrayList<>(); predicates.add( new MaxSizePredicate((int) compression.getMinResponseSize().toBytes())); predicates.add(new CompressibleMimeTypePredicate(compression.getMimeTypes())); if (compression.getExcludedUserAgents() != null) { for (String agent : compression.getExcludedUserAgents()) { RequestHeaderAttribute agentHeader = new RequestHeaderAttribute( new HttpString(HttpHeaders.USER_AGENT)); predicates.add(Predicates.not(Predicates.regex(agentHeader, agent))); } } return predicates.toArray(new Predicate[0]); }
@Test public void shouldReturnCompressedResponse() { final ArmeriaReactiveWebServerFactory factory = factory(); final Compression compression = new Compression(); compression.setEnabled(true); compression.setMinResponseSize(DataSize.ofBytes(1)); compression.setMimeTypes(new String[] { "text/plain" }); compression.setExcludedUserAgents(new String[] { "unknown-agent/[0-9]+\\.[0-9]+\\.[0-9]+$" }); factory.setCompression(compression); runEchoServer(factory, server -> { final AggregatedHttpMessage res = sendPostRequest(httpClient(server)); assertThat(res.status()).isEqualTo(com.linecorp.armeria.common.HttpStatus.OK); assertThat(res.headers().get(HttpHeaderNames.CONTENT_ENCODING)).isEqualTo("gzip"); assertThat(res.content().toStringUtf8()).isNotEqualTo("hello"); }); }
@Override public void customize(Connector connector) { if (this.compression != null && this.compression.getEnabled()) { ProtocolHandler handler = connector.getProtocolHandler(); if (handler instanceof AbstractHttp11Protocol) { customize((AbstractHttp11Protocol<?>) handler); } for (UpgradeProtocol upgradeProtocol : connector.findUpgradeProtocols()) { if (upgradeProtocol instanceof Http2Protocol) { customize((Http2Protocol) upgradeProtocol); } } } }
private String getExcludedUserAgents() { return StringUtils .arrayToCommaDelimitedString(this.compression.getExcludedUserAgents()); }
private String getMimeTypes(Compression compression) { return StringUtils.arrayToCommaDelimitedString(compression.getMimeTypes()); }
private int getMinResponseSize(Compression compression) { return (int) compression.getMinResponseSize().toBytes(); }
@Test public void shouldReturnNonCompressedResponse_dueToUserAgent() { final ArmeriaReactiveWebServerFactory factory = factory(); final Compression compression = new Compression(); compression.setEnabled(true); compression.setMinResponseSize(DataSize.ofBytes(1)); compression.setExcludedUserAgents(new String[] { "test-agent/[0-9]+\\.[0-9]+\\.[0-9]+$" }); factory.setCompression(compression); runEchoServer(factory, server -> { final AggregatedHttpMessage res = sendPostRequest(httpClient(server)); validateEchoResponse(res); assertThat(res.headers().get(HttpHeaderNames.CONTENT_ENCODING)).isNull(); }); }
private Handler addHandlerWrappers(Handler handler) { if (getCompression() != null && getCompression().getEnabled()) { handler = applyWrapper(handler, JettyHandlerWrappers.createGzipHandlerWrapper(getCompression())); } if (StringUtils.hasText(getServerHeader())) { handler = applyWrapper(handler, JettyHandlerWrappers .createServerHeaderHandlerWrapper(getServerHeader())); } return handler; }
private void customize(Http2Protocol protocol) { Compression compression = this.compression; protocol.setCompression("on"); protocol.setCompressionMinSize(getMinResponseSize(compression)); protocol.setCompressibleMimeType(getMimeTypes(compression)); if (this.compression.getExcludedUserAgents() != null) { protocol.setNoCompressionUserAgents(getExcludedUserAgents()); } }
@Override public HttpServer apply(HttpServer server) { if (!this.compression.getMinResponseSize().isNegative()) { server = server .compress((int) this.compression.getMinResponseSize().toBytes()); } CompressionPredicate mimeTypes = getMimeTypesPredicate( this.compression.getMimeTypes()); CompressionPredicate excludedUserAgents = getExcludedUserAgentsPredicate( this.compression.getExcludedUserAgents()); server = server.compress(mimeTypes.and(excludedUserAgents)); return server; }
@Test public void shouldReturnNonCompressedResponse_dueToContentType() { final ArmeriaReactiveWebServerFactory factory = factory(); final Compression compression = new Compression(); compression.setEnabled(true); compression.setMinResponseSize(DataSize.ofBytes(1)); compression.setMimeTypes(new String[] { "text/html" }); factory.setCompression(compression); runEchoServer(factory, server -> { final AggregatedHttpMessage res = sendPostRequest(httpClient(server)); validateEchoResponse(res); assertThat(res.headers().get(HttpHeaderNames.CONTENT_ENCODING)).isNull(); }); }
private Handler addHandlerWrappers(Handler handler) { if (getCompression() != null && getCompression().getEnabled()) { handler = applyWrapper(handler, JettyHandlerWrappers.createGzipHandlerWrapper(getCompression())); } if (StringUtils.hasText(getServerHeader())) { handler = applyWrapper(handler, JettyHandlerWrappers .createServerHeaderHandlerWrapper(getServerHeader())); } return handler; }
private void customize(AbstractHttp11Protocol<?> protocol) { Compression compression = this.compression; protocol.setCompression("on"); protocol.setCompressionMinSize(getMinResponseSize(compression)); protocol.setCompressibleMimeType(getMimeTypes(compression)); if (this.compression.getExcludedUserAgents() != null) { protocol.setNoCompressionUserAgents(getExcludedUserAgents()); } }
static HandlerWrapper createGzipHandlerWrapper(Compression compression) { GzipHandler handler = new GzipHandler(); handler.setMinGzipSize((int) compression.getMinResponseSize().toBytes()); handler.setIncludedMimeTypes(compression.getMimeTypes()); for (HttpMethod httpMethod : HttpMethod.values()) { handler.addIncludedMethods(httpMethod.name()); } if (compression.getExcludedUserAgents() != null) { handler.setExcludedAgentPatterns(compression.getExcludedUserAgents()); } return handler; }
/** * Optionally wrap the given {@link HttpHandler} for HTTP compression support. * @param compression the HTTP compression configuration * @param httpHandler the HTTP handler to wrap * @return the wrapped HTTP handler if compression is enabled, or the handler itself */ public static HttpHandler configureCompression(Compression compression, HttpHandler httpHandler) { if (compression == null || !compression.getEnabled()) { return httpHandler; } ContentEncodingRepository repository = new ContentEncodingRepository(); repository.addEncodingHandler("gzip", new GzipEncodingProvider(), 50, Predicates.and(getCompressionPredicates(compression))); return new EncodingHandler(repository).setNext(httpHandler); }
private static Function<Service<HttpRequest, HttpResponse>, HttpEncodingService> contentEncodingDecorator(Compression compression) { final Predicate<MediaType> encodableContentTypePredicate; final String[] mimeTypes = compression.getMimeTypes(); if (mimeTypes == null || mimeTypes.length == 0) { encodableContentTypePredicate = contentType -> true; } else { final List<MediaType> encodableContentTypes = Arrays.stream(mimeTypes).map(MediaType::parse).collect(toImmutableList()); encodableContentTypePredicate = contentType -> encodableContentTypes.stream().anyMatch(contentType::is); } final Predicate<HttpHeaders> encodableRequestHeadersPredicate; final String[] excludedUserAgents = compression.getExcludedUserAgents(); if (excludedUserAgents == null || excludedUserAgents.length == 0) { encodableRequestHeadersPredicate = headers -> true; } else { final List<Pattern> patterns = Arrays.stream(excludedUserAgents).map(Pattern::compile).collect(toImmutableList()); encodableRequestHeadersPredicate = headers -> { // No User-Agent header will be converted to an empty string. final String userAgent = headers.get(HttpHeaderNames.USER_AGENT, ""); return patterns.stream().noneMatch(pattern -> pattern.matcher(userAgent).matches()); }; } return delegate -> new HttpEncodingService(delegate, encodableContentTypePredicate, encodableRequestHeadersPredicate, compression.getMinResponseSize().toBytes()); }
if (compression != null && compression.getEnabled()) { sb.decorator(contentEncodingDecorator(compression));
private HttpServer createHttpServer() { HttpServer server = HttpServer.create(); if (this.resourceFactory != null) { LoopResources resources = this.resourceFactory.getLoopResources(); Assert.notNull(resources, "No LoopResources: is ReactorResourceFactory not initialized yet?"); server = server.tcpConfiguration((tcpServer) -> tcpServer.runOn(resources) .addressSupplier(this::getListenAddress)); } else { server = server.tcpConfiguration( (tcpServer) -> tcpServer.addressSupplier(this::getListenAddress)); } if (getSsl() != null && getSsl().isEnabled()) { SslServerCustomizer sslServerCustomizer = new SslServerCustomizer(getSsl(), getHttp2(), getSslStoreProvider()); server = sslServerCustomizer.apply(server); } if (getCompression() != null && getCompression().getEnabled()) { CompressionCustomizer compressionCustomizer = new CompressionCustomizer( getCompression()); server = compressionCustomizer.apply(server); } server = server.protocol(listProtocols()).forwarded(this.useForwardHeaders); return applyCustomizers(server); }