From 41e0ef2e9ac5b19744e75392543632b21da498c6 Mon Sep 17 00:00:00 2001 From: Trustin Lee Date: Fri, 28 Sep 2012 15:16:29 +0900 Subject: [PATCH] [#441] Provide a better way to handle decoder failures * Update toString() of all HttpObject implementations * HttpMessageDecoder does not raise an exception but sets decoderResult property of the decoded message. * HttpMessageDecoder discards inbound traffic once decoding fails, by adding a new state called BAD_MESSAGE. * Add a test case that tests this behavior. --- .../handler/codec/http/DefaultHttpChunk.java | 20 +++ .../codec/http/DefaultHttpChunkTrailer.java | 34 +++++ .../codec/http/DefaultHttpRequest.java | 2 + .../codec/http/DefaultHttpResponse.java | 2 + .../codec/http/HttpMessageDecoder.java | 51 ++++++-- .../codec/http/HttpRequestDecoder.java | 5 + .../codec/http/HttpResponseDecoder.java | 7 ++ .../codec/rtsp/RtspRequestDecoder.java | 5 + .../codec/rtsp/RtspResponseDecoder.java | 7 ++ .../codec/http/HttpInvalidMessageTest.java | 117 ++++++++++++++++++ 10 files changed, 243 insertions(+), 7 deletions(-) create mode 100644 codec-http/src/test/java/io/netty/handler/codec/http/HttpInvalidMessageTest.java diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpChunk.java b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpChunk.java index f78c018d4d..9cf64e8711 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpChunk.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpChunk.java @@ -51,4 +51,24 @@ public class DefaultHttpChunk extends DefaultHttpObject implements HttpChunk { public boolean isLast() { return last; } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(); + buf.append(getClass().getSimpleName()); + + final boolean last = isLast(); + buf.append("(last: "); + buf.append(last); + if (!last) { + buf.append(", size: "); + buf.append(getContent().readableBytes()); + } + + buf.append(", decodeResult: "); + buf.append(getDecodeResult()); + buf.append(')'); + + return buf.toString(); + } } diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpChunkTrailer.java b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpChunkTrailer.java index 65235d4b86..2f3c6bc591 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpChunkTrailer.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpChunkTrailer.java @@ -17,6 +17,7 @@ package io.netty.handler.codec.http; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; +import io.netty.util.internal.StringUtil; import java.util.List; import java.util.Map; @@ -104,4 +105,37 @@ public class DefaultHttpChunkTrailer extends DefaultHttpObject implements HttpCh public void setContent(ByteBuf content) { throw new IllegalStateException("read-only"); } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(); + buf.append(getClass().getSimpleName()); + + final boolean last = isLast(); + buf.append("(last: "); + buf.append(last); + if (!last) { + buf.append(", size: "); + buf.append(getContent().readableBytes()); + } + + buf.append(", decodeResult: "); + buf.append(getDecodeResult()); + buf.append(')'); + buf.append(StringUtil.NEWLINE); + appendHeaders(buf); + + // Remove the last newline. + buf.setLength(buf.length() - StringUtil.NEWLINE.length()); + return buf.toString(); + } + + private void appendHeaders(StringBuilder buf) { + for (Map.Entry e: getHeaders()) { + buf.append(e.getKey()); + buf.append(": "); + buf.append(e.getValue()); + buf.append(StringUtil.NEWLINE); + } + } } diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpRequest.java b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpRequest.java index afadec21bd..2729b9e9d4 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpRequest.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpRequest.java @@ -70,6 +70,8 @@ public class DefaultHttpRequest extends DefaultHttpMessage implements HttpReques buf.append(getClass().getSimpleName()); buf.append("(transferEncoding: "); buf.append(getTransferEncoding()); + buf.append(", decodeResult: "); + buf.append(getDecodeResult()); buf.append(')'); buf.append(StringUtil.NEWLINE); buf.append(getMethod().toString()); diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpResponse.java b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpResponse.java index 440b34fed0..c872e940e4 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpResponse.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpResponse.java @@ -54,6 +54,8 @@ public class DefaultHttpResponse extends DefaultHttpMessage implements HttpRespo buf.append(getClass().getSimpleName()); buf.append("(transferEncoding: "); buf.append(getTransferEncoding()); + buf.append(", decodeResult: "); + buf.append(getDecodeResult()); buf.append(')'); buf.append(StringUtil.NEWLINE); buf.append(getProtocolVersion().getText()); diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/HttpMessageDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpMessageDecoder.java index 13ff6ad8f8..82a49f6ea0 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/HttpMessageDecoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpMessageDecoder.java @@ -19,6 +19,7 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPipeline; +import io.netty.handler.codec.DecodeResult; import io.netty.handler.codec.ReplayingDecoder; import io.netty.handler.codec.TooLongFrameException; @@ -125,7 +126,8 @@ public abstract class HttpMessageDecoder extends ReplayingDecoder