diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/HttpContentEncoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpContentEncoder.java index 578deb2599..c04d538681 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/HttpContentEncoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpContentEncoder.java @@ -164,18 +164,21 @@ public abstract class HttpContentEncoder extends MessageToMessageCodec out) { + int existingMessages = out.size(); + encodeContent(content, out); + + if (HttpUtil.isContentLengthSet(newRes)) { + // adjust the content-length header + int messageSize = 0; + for (int i = existingMessages; i < out.size(); i++) { + Object item = out.get(i); + if (item instanceof HttpContent) { + messageSize += ((HttpContent) item).content().readableBytes(); + } + } + HttpUtil.setContentLength(newRes, messageSize); + } else { + newRes.headers().set(HttpHeaderNames.TRANSFER_ENCODING, HttpHeaderValues.CHUNKED); + } + } + private static boolean isPassthru(HttpVersion version, int code, CharSequence httpMethod) { return code < 200 || code == 204 || code == 304 || (httpMethod == ZERO_LENGTH_HEAD || (httpMethod == ZERO_LENGTH_CONNECT && code == 200)) || 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 94b1aa6cd6..c6ff3bd6bc 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 @@ -197,15 +197,52 @@ public class HttpContentCompressorTest { assertThat(ch.readOutbound(), is(nullValue())); } + @Test + public void testFullContentWithContentLength() throws Exception { + EmbeddedChannel ch = new EmbeddedChannel(new HttpContentCompressor()); + ch.writeInbound(newRequest()); + + FullHttpResponse fullRes = new DefaultFullHttpResponse( + HttpVersion.HTTP_1_1, HttpResponseStatus.OK, + Unpooled.copiedBuffer("Hello, World", CharsetUtil.US_ASCII)); + fullRes.headers().set(HttpHeaderNames.CONTENT_LENGTH, fullRes.content().readableBytes()); + ch.writeOutbound(fullRes); + + HttpResponse res = ch.readOutbound(); + assertThat(res, is(not(instanceOf(HttpContent.class)))); + + assertThat(res.headers().get(HttpHeaderNames.TRANSFER_ENCODING), is(nullValue())); + assertThat(res.headers().get(HttpHeaderNames.CONTENT_ENCODING), is("gzip")); + + long contentLengthHeaderValue = HttpUtil.getContentLength(res); + long observedLength = 0; + + HttpContent c = ch.readOutbound(); + observedLength += c.content().readableBytes(); + assertThat(ByteBufUtil.hexDump(c.content()), is("1f8b0800000000000000f248cdc9c9d75108cf2fca4901000000ffff")); + c.release(); + + c = ch.readOutbound(); + observedLength += c.content().readableBytes(); + assertThat(ByteBufUtil.hexDump(c.content()), is("0300c6865b260c000000")); + c.release(); + + LastHttpContent last = ch.readOutbound(); + assertThat(last.content().readableBytes(), is(0)); + last.release(); + + assertThat(ch.readOutbound(), is(nullValue())); + assertEquals(contentLengthHeaderValue, observedLength); + } + @Test public void testFullContent() throws Exception { EmbeddedChannel ch = new EmbeddedChannel(new HttpContentCompressor()); ch.writeInbound(newRequest()); FullHttpResponse res = new DefaultFullHttpResponse( - HttpVersion.HTTP_1_1, HttpResponseStatus.OK, - Unpooled.copiedBuffer("Hello, World", CharsetUtil.US_ASCII)); - res.headers().set(HttpHeaderNames.CONTENT_LENGTH, res.content().readableBytes()); + HttpVersion.HTTP_1_1, HttpResponseStatus.OK, + Unpooled.copiedBuffer("Hello, World", CharsetUtil.US_ASCII)); ch.writeOutbound(res); assertEncodedResponse(ch); diff --git a/codec-http/src/test/java/io/netty/handler/codec/http/HttpContentEncoderTest.java b/codec-http/src/test/java/io/netty/handler/codec/http/HttpContentEncoderTest.java index 660df3406e..d4bb1af78b 100644 --- a/codec-http/src/test/java/io/netty/handler/codec/http/HttpContentEncoderTest.java +++ b/codec-http/src/test/java/io/netty/handler/codec/http/HttpContentEncoderTest.java @@ -160,14 +160,41 @@ public class HttpContentEncoderTest { assertThat(ch.readOutbound(), is(nullValue())); } + @Test + public void testFullContentWithContentLength() throws Exception { + EmbeddedChannel ch = new EmbeddedChannel(new TestEncoder()); + ch.writeInbound(new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/")); + + FullHttpResponse fullRes = new DefaultFullHttpResponse( + HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.wrappedBuffer(new byte[42])); + fullRes.headers().set(HttpHeaderNames.CONTENT_LENGTH, 42); + ch.writeOutbound(fullRes); + + HttpResponse res = ch.readOutbound(); + assertThat(res, is(not(instanceOf(HttpContent.class)))); + assertThat(res.headers().get(HttpHeaderNames.TRANSFER_ENCODING), is(nullValue())); + assertThat(res.headers().get(HttpHeaderNames.CONTENT_LENGTH), is("2")); + assertThat(res.headers().get(HttpHeaderNames.CONTENT_ENCODING), is("test")); + + HttpContent c = ch.readOutbound(); + assertThat(c.content().readableBytes(), is(2)); + assertThat(c.content().toString(CharsetUtil.US_ASCII), is("42")); + c.release(); + + LastHttpContent last = ch.readOutbound(); + assertThat(last.content().readableBytes(), is(0)); + last.release(); + + assertThat(ch.readOutbound(), is(nullValue())); + } + @Test public void testFullContent() throws Exception { EmbeddedChannel ch = new EmbeddedChannel(new TestEncoder()); ch.writeInbound(new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/")); FullHttpResponse res = new DefaultFullHttpResponse( - HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.wrappedBuffer(new byte[42])); - res.headers().set(HttpHeaderNames.CONTENT_LENGTH, 42); + HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.wrappedBuffer(new byte[42])); ch.writeOutbound(res); assertEncodedResponse(ch);