Fix a bug where HttpObjectDecoder generates two LastHttpContent consecutively

Motivation:
When an HttpResponseDecoder decodes an invalid chunk, a LastHttpContent instance is produced and the decoder enters the 'BAD_MESSAGE' state, which is not supposed to produce a message any further.  However, because HttpObjectDecoder.invalidChunk() did not clear this.message out to null, decodeLast() will produce another LastHttpContent message on a certain situation.

Modification:
Do not forget to null out HttpObjectDecoder.message in invalidChunk(), and add a test case for it.

Result:
No more consecutive LastHttpContent messages produced by HttpObjectDecoder.
This commit is contained in:
Trustin Lee 2014-02-26 15:53:53 -08:00
parent ccd135df01
commit 0d210f45f2
2 changed files with 29 additions and 0 deletions

View File

@ -457,6 +457,7 @@ public abstract class HttpObjectDecoder extends ReplayingDecoder<HttpObjectDecod
checkpoint(State.BAD_MESSAGE);
HttpContent chunk = new DefaultLastHttpContent(Unpooled.EMPTY_BUFFER);
chunk.setDecoderResult(DecoderResult.failure(cause));
message = null;
return chunk;
}

View File

@ -509,4 +509,32 @@ public class HttpResponseDecoderTest {
ch.finish();
assertThat(ch.readInbound(), is(nullValue()));
}
/**
* Tests if the decoder produces one and only {@link LastHttpContent} when an invalid chunk is received and
* the connection is closed.
*/
@Test
public void testGarbageChunk() {
EmbeddedChannel channel = new EmbeddedChannel(new HttpResponseDecoder());
String responseWithIllegalChunk =
"HTTP/1.1 200 OK\r\n" +
"Transfer-Encoding: chunked\r\n\r\n" +
"NOT_A_CHUNK_LENGTH\r\n";
channel.writeInbound(Unpooled.copiedBuffer(responseWithIllegalChunk, CharsetUtil.US_ASCII));
assertThat(channel.readInbound(), is(instanceOf(HttpResponse.class)));
// Ensure that the decoder generates the last chunk with correct decoder result.
LastHttpContent invalidChunk = channel.readInbound();
assertThat(invalidChunk.getDecoderResult().isFailure(), is(true));
invalidChunk.release();
// And no more messages should be produced by the decoder.
assertThat(channel.readInbound(), is(nullValue()));
// .. even after the connection is closed.
assertThat(channel.finish(), is(false));
}
}