diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/HttpContentCompressor.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpContentCompressor.java index fcf22e011a..e80469f26e 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/HttpContentCompressor.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpContentCompressor.java @@ -32,6 +32,7 @@ public class HttpContentCompressor extends HttpContentEncoder { private final int compressionLevel; private final int windowBits; private final int memLevel; + private final int contentSizeThreshold; private ChannelHandlerContext ctx; /** @@ -52,7 +53,7 @@ public class HttpContentCompressor extends HttpContentEncoder { * compression level is {@code 6}. */ public HttpContentCompressor(int compressionLevel) { - this(compressionLevel, 15, 8); + this(compressionLevel, 15, 8, 0); } /** @@ -75,6 +76,33 @@ public class HttpContentCompressor extends HttpContentEncoder { * at the expense of memory usage. The default value is {@code 8} */ public HttpContentCompressor(int compressionLevel, int windowBits, int memLevel) { + this(compressionLevel, windowBits, memLevel, 0); + } + + /** + * Creates a new handler with the specified compression level, window size, + * and memory level.. + * + * @param compressionLevel + * {@code 1} yields the fastest compression and {@code 9} yields the + * best compression. {@code 0} means no compression. The default + * compression level is {@code 6}. + * @param windowBits + * The base two logarithm of the size of the history buffer. The + * value should be in the range {@code 9} to {@code 15} inclusive. + * Larger values result in better compression at the expense of + * memory usage. The default value is {@code 15}. + * @param memLevel + * How much memory should be allocated for the internal compression + * state. {@code 1} uses minimum memory and {@code 9} uses maximum + * memory. Larger values result in better and faster compression + * at the expense of memory usage. The default value is {@code 8} + * @param contentSizeThreshold + * The response body is compressed when the size of the response + * body exceeds the threshold. The value should be a non negative + * number. {@code 0} will enable compression for all responses. + */ + public HttpContentCompressor(int compressionLevel, int windowBits, int memLevel, int contentSizeThreshold) { if (compressionLevel < 0 || compressionLevel > 9) { throw new IllegalArgumentException( "compressionLevel: " + compressionLevel + @@ -88,9 +116,14 @@ public class HttpContentCompressor extends HttpContentEncoder { throw new IllegalArgumentException( "memLevel: " + memLevel + " (expected: 1-9)"); } + if (contentSizeThreshold < 0) { + throw new IllegalArgumentException( + "contentSizeThreshold: " + contentSizeThreshold + " (expected: non negative number)"); + } this.compressionLevel = compressionLevel; this.windowBits = windowBits; this.memLevel = memLevel; + this.contentSizeThreshold = contentSizeThreshold; } @Override @@ -100,6 +133,13 @@ public class HttpContentCompressor extends HttpContentEncoder { @Override protected Result beginEncode(HttpResponse headers, String acceptEncoding) throws Exception { + if (this.contentSizeThreshold > 0) { + if (headers instanceof HttpContent && + ((HttpContent) headers).content().readableBytes() < contentSizeThreshold) { + return null; + } + } + String contentEncoding = headers.headers().get(HttpHeaderNames.CONTENT_ENCODING); if (contentEncoding != null) { // Content-Encoding was set, either as something specific or as the IDENTITY encoding diff --git a/codec-http/src/test/java/io/netty/handler/codec/http/HttpContentCompressorTest.java b/codec-http/src/test/java/io/netty/handler/codec/http/HttpContentCompressorTest.java index c6ff3bd6bc..6ab2ab88c6 100644 --- a/codec-http/src/test/java/io/netty/handler/codec/http/HttpContentCompressorTest.java +++ b/codec-http/src/test/java/io/netty/handler/codec/http/HttpContentCompressorTest.java @@ -29,11 +29,7 @@ import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.CoreMatchers.nullValue; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.Assert.*; public class HttpContentCompressorTest { @@ -454,6 +450,52 @@ public class HttpContentCompressorTest { assertTrue(ch.finishAndReleaseAll()); } + @Test + public void testCompressThresholdAllCompress() throws Exception { + EmbeddedChannel ch = new EmbeddedChannel(new HttpContentCompressor()); + assertTrue(ch.writeInbound(newRequest())); + + FullHttpResponse res1023 = new DefaultFullHttpResponse( + HttpVersion.HTTP_1_1, HttpResponseStatus.OK, + Unpooled.wrappedBuffer(new byte[1023])); + assertTrue(ch.writeOutbound(res1023)); + DefaultHttpResponse response1023 = ch.readOutbound(); + assertThat(response1023.headers().get(HttpHeaderNames.CONTENT_ENCODING), is("gzip")); + ch.releaseOutbound(); + + assertTrue(ch.writeInbound(newRequest())); + FullHttpResponse res1024 = new DefaultFullHttpResponse( + HttpVersion.HTTP_1_1, HttpResponseStatus.OK, + Unpooled.wrappedBuffer(new byte[1024])); + assertTrue(ch.writeOutbound(res1024)); + DefaultHttpResponse response1024 = ch.readOutbound(); + assertThat(response1024.headers().get(HttpHeaderNames.CONTENT_ENCODING), is("gzip")); + assertTrue(ch.finishAndReleaseAll()); + } + + @Test + public void testCompressThresholdNotCompress() throws Exception { + EmbeddedChannel ch = new EmbeddedChannel(new HttpContentCompressor(6, 15, 8, 1024)); + assertTrue(ch.writeInbound(newRequest())); + + FullHttpResponse res1023 = new DefaultFullHttpResponse( + HttpVersion.HTTP_1_1, HttpResponseStatus.OK, + Unpooled.wrappedBuffer(new byte[1023])); + assertTrue(ch.writeOutbound(res1023)); + DefaultHttpResponse response1023 = ch.readOutbound(); + assertFalse(response1023.headers().contains(HttpHeaderNames.CONTENT_ENCODING)); + ch.releaseOutbound(); + + assertTrue(ch.writeInbound(newRequest())); + FullHttpResponse res1024 = new DefaultFullHttpResponse( + HttpVersion.HTTP_1_1, HttpResponseStatus.OK, + Unpooled.wrappedBuffer(new byte[1024])); + assertTrue(ch.writeOutbound(res1024)); + DefaultHttpResponse response1024 = ch.readOutbound(); + assertThat(response1024.headers().get(HttpHeaderNames.CONTENT_ENCODING), is("gzip")); + assertTrue(ch.finishAndReleaseAll()); + } + private static FullHttpRequest newRequest() { FullHttpRequest req = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/"); req.headers().set(HttpHeaderNames.ACCEPT_ENCODING, "gzip");