Fix writing of empty LastHttpContent with trailers

Motivation:

4732fabb16 introduced a regression in HttpObjectEncoder which will lead to buffer leak and IllegalStateException when a LastHttpContent with trailers is written.

Modifications:

- Correctly add the buffer to the encoded list.
- Add testcases

Result:

Fixes [#7418]
This commit is contained in:
Norman Maurer 2017-11-19 09:19:07 +01:00
parent 5ca273814f
commit 8009c4c8a0
3 changed files with 72 additions and 6 deletions

View File

@ -206,6 +206,7 @@ public abstract class HttpObjectEncoder<H extends HttpMessage> extends MessageTo
buf.writeBytes(CRLF);
trailersEncodedSizeAccumulator = TRAILERS_WEIGHT_NEW * padSizeForAccumulation(buf.readableBytes()) +
TRAILERS_WEIGHT_HISTORICAL * trailersEncodedSizeAccumulator;
out.add(buf);
}
} else if (contentLength == 0) {
// Need to produce some output otherwise an

View File

@ -135,16 +135,26 @@ public class HttpRequestEncoderTest {
}
@Test
public void testEmptyContentChunked() throws Exception {
testEmptyContent(true);
public void testEmptyContentsChunked() throws Exception {
testEmptyContents(true, false);
}
@Test
public void testEmptyContentNotChunked() throws Exception {
testEmptyContent(false);
public void testEmptyContentsChunkedWithTrailers() throws Exception {
testEmptyContents(true, true);
}
private void testEmptyContent(boolean chunked) throws Exception {
@Test
public void testEmptyContentsNotChunked() throws Exception {
testEmptyContents(false, false);
}
@Test
public void testEmptyContentNotsChunkedWithTrailers() throws Exception {
testEmptyContents(false, true);
}
private void testEmptyContents(boolean chunked, boolean trailers) throws Exception {
HttpRequestEncoder encoder = new HttpRequestEncoder();
EmbeddedChannel channel = new EmbeddedChannel(encoder);
HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, "/");
@ -157,7 +167,11 @@ public class HttpRequestEncoderTest {
assertTrue(channel.writeOutbound(new DefaultHttpContent(contentBuffer)));
ByteBuf lastContentBuffer = Unpooled.buffer();
assertTrue(channel.writeOutbound(new DefaultHttpContent(lastContentBuffer)));
LastHttpContent last = new DefaultLastHttpContent(lastContentBuffer);
if (trailers) {
last.trailingHeaders().set("X-Netty-Test", "true");
}
assertTrue(channel.writeOutbound(last));
// Ensure we only produce ByteBuf instances.
ByteBuf head = (ByteBuf) channel.readOutbound();

View File

@ -286,4 +286,55 @@ public class HttpResponseEncoderTest {
buffer = (ByteBuf) channel.readOutbound();
buffer.release();
}
@Test
public void testEmptyContentsChunked() throws Exception {
testEmptyContents(true, false);
}
@Test
public void testEmptyContentsChunkedWithTrailers() throws Exception {
testEmptyContents(true, true);
}
@Test
public void testEmptyContentsNotChunked() throws Exception {
testEmptyContents(false, false);
}
@Test
public void testEmptyContentNotsChunkedWithTrailers() throws Exception {
testEmptyContents(false, true);
}
private void testEmptyContents(boolean chunked, boolean trailers) throws Exception {
HttpResponseEncoder encoder = new HttpResponseEncoder();
EmbeddedChannel channel = new EmbeddedChannel(encoder);
HttpResponse request = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
if (chunked) {
HttpHeaders.setTransferEncodingChunked(request);
}
assertTrue(channel.writeOutbound(request));
ByteBuf contentBuffer = Unpooled.buffer();
assertTrue(channel.writeOutbound(new DefaultHttpContent(contentBuffer)));
ByteBuf lastContentBuffer = Unpooled.buffer();
LastHttpContent last = new DefaultLastHttpContent(lastContentBuffer);
if (trailers) {
last.trailingHeaders().set("X-Netty-Test", "true");
}
assertTrue(channel.writeOutbound(last));
// Ensure we only produce ByteBuf instances.
ByteBuf head = (ByteBuf) channel.readOutbound();
assertTrue(head.release());
ByteBuf content = (ByteBuf) channel.readOutbound();
content.release();
ByteBuf lastContent = (ByteBuf) channel.readOutbound();
lastContent.release();
assertFalse(channel.finish());
}
}