When the response exceeds the threshold, it will be compressed
Motivation: When the response is very small, compression will inflate the response. Modifications: Add filed io.netty.handler.codec.http.HttpContentCompressor#compressThreshold that control whether the HTTP response should be compressed. Result: Fixes #7660.
This commit is contained in:
parent
69582c0b6c
commit
06dcca1dbc
@ -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
|
||||
|
@ -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");
|
||||
|
Loading…
Reference in New Issue
Block a user