Ensure valid message sequence if channel is closed before receive headers.

Motivation:

When the channel is closed while we still decode the headers we currently not preserve correct message sequence. In this case we should generate an invalid message with a current cause.

Modifications:

Create an invalid message with a PrematureChannelClosureException as cause when the channel is closed while we decode the headers.

Result:

Correct message sequence preserved and correct DecoderResult if the channel is closed while decode headers.
This commit is contained in:
Norman Maurer 2016-06-07 10:27:53 +02:00
parent 88dbd96376
commit 398efb1f71
2 changed files with 27 additions and 2 deletions

View File

@ -21,6 +21,7 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.DecoderResult;
import io.netty.handler.codec.PrematureChannelClosureException;
import io.netty.handler.codec.TooLongFrameException;
import io.netty.util.ByteProcessor;
import io.netty.util.internal.AppendableCharSequence;
@ -411,9 +412,19 @@ public abstract class HttpObjectDecoder extends ByteToMessageDecoder {
if (currentState == State.READ_VARIABLE_LENGTH_CONTENT && !in.isReadable() && !chunked) {
// End of connection.
out.add(LastHttpContent.EMPTY_LAST_CONTENT);
reset();
resetNow();
return;
}
if (currentState == State.READ_HEADER) {
// If we are still in the state of reading headers we need to create a new invalid message that
// signals that the connection was closed before we received the headers.
out.add(invalidMessage(Unpooled.EMPTY_BUFFER,
new PrematureChannelClosureException("Connection closed before received headers")));
resetNow();
return;
}
// Check if the closure of the connection signifies the end of the content.
boolean prematureClosure;
if (isDecodingRequest() || chunked) {
@ -425,11 +436,11 @@ public abstract class HttpObjectDecoder extends ByteToMessageDecoder {
// connection, so it is perfectly fine.
prematureClosure = contentLength() > 0;
}
resetNow();
if (!prematureClosure) {
out.add(LastHttpContent.EMPTY_LAST_CONTENT);
}
resetNow();
}
}

View File

@ -18,6 +18,7 @@ package io.netty.handler.codec.http;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.PrematureChannelClosureException;
import io.netty.handler.codec.TooLongFrameException;
import io.netty.util.CharsetUtil;
import org.junit.Test;
@ -647,4 +648,17 @@ public class HttpResponseDecoderTest {
// .. even after the connection is closed.
assertThat(channel.finish(), is(false));
}
@Test
public void testConnectionClosedBeforeHeadersReceived() {
EmbeddedChannel channel = new EmbeddedChannel(new HttpResponseDecoder());
String responseInitialLine =
"HTTP/1.1 200 OK\r\n";
assertFalse(channel.writeInbound(Unpooled.copiedBuffer(responseInitialLine, CharsetUtil.US_ASCII)));
assertTrue(channel.finish());
HttpMessage message = channel.readInbound();
assertTrue(message.decoderResult().isFailure());
assertThat(message.decoderResult().cause(), instanceOf(PrematureChannelClosureException.class));
assertNull(channel.readInbound());
}
}