From 4a72aafd567489304824b89d8ab3e0765b76a4d8 Mon Sep 17 00:00:00 2001 From: Trustin Lee Date: Tue, 10 Mar 2009 07:20:27 +0000 Subject: [PATCH] Resolved issue: NETTY-133 Limit the length of HTTP header lines. * Added maxHeaderSize option * Added maxInitialLineLength option * Overall HTTP code cleanup --- .../http/HttpServerPipelineFactory.java | 2 +- .../codec/http/HttpMessageDecoder.java | 130 +++++++++++++++--- .../codec/http/HttpRequestDecoder.java | 15 +- .../codec/http/HttpResponseDecoder.java | 13 +- 4 files changed, 121 insertions(+), 39 deletions(-) diff --git a/src/main/java/org/jboss/netty/example/http/HttpServerPipelineFactory.java b/src/main/java/org/jboss/netty/example/http/HttpServerPipelineFactory.java index e3d950a204..3bf4508387 100644 --- a/src/main/java/org/jboss/netty/example/http/HttpServerPipelineFactory.java +++ b/src/main/java/org/jboss/netty/example/http/HttpServerPipelineFactory.java @@ -44,7 +44,7 @@ public class HttpServerPipelineFactory implements ChannelPipelineFactory { // Create a default pipeline implementation. ChannelPipeline pipeline = pipeline(); - pipeline.addLast("decoder", new HttpRequestDecoder(8192)); + pipeline.addLast("decoder", new HttpRequestDecoder(8192, 8192, 8192)); pipeline.addLast("encoder", new HttpResponseEncoder()); pipeline.addLast("handler", handler); return pipeline; diff --git a/src/main/java/org/jboss/netty/handler/codec/http/HttpMessageDecoder.java b/src/main/java/org/jboss/netty/handler/codec/http/HttpMessageDecoder.java index 872c98aac9..dd29486024 100644 --- a/src/main/java/org/jboss/netty/handler/codec/http/HttpMessageDecoder.java +++ b/src/main/java/org/jboss/netty/handler/codec/http/HttpMessageDecoder.java @@ -29,6 +29,7 @@ import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; +import org.jboss.netty.handler.codec.frame.TooLongFrameException; import org.jboss.netty.handler.codec.replay.ReplayingDecoder; /** @@ -46,9 +47,12 @@ public abstract class HttpMessageDecoder extends ReplayingDecoder= maxHeaderSize) { + throw new TooLongFrameException( + "HTTP header is larger than " + + maxHeaderSize + " bytes."); + + } + headerSize ++; + sb.append((char) nextByte); + } + } + } + protected abstract boolean isDecodingRequest(); - protected abstract void readInitial(ChannelBuffer buffer) throws Exception; + protected abstract HttpMessage createMessage(String[] initialLine) throws Exception; private int getChunkSize(String hex) { hex = hex.trim(); @@ -371,8 +428,9 @@ public abstract class HttpMessageDecoder extends ReplayingDecoder= maxLineLength) { + throw new TooLongFrameException( + "An HTTP line is larger than " + maxLineLength + + " bytes."); + } + lineLength ++; sb.append((char) nextByte); } } } - protected String[] splitInitial(String sb) { + /** + * Returns {@code true} if only if the skipped line was not empty. + * Please note that an empty line is also skipped, while {@code} false is + * returned. + */ + private boolean skipLine(ChannelBuffer buffer) { + int lineLength = 0; + while (true) { + byte nextByte = buffer.readByte(); + if (nextByte == HttpCodecUtil.CR) { + nextByte = buffer.readByte(); + if (nextByte == HttpCodecUtil.LF) { + return lineLength != 0; + } + } + else if (nextByte == HttpCodecUtil.LF) { + return lineLength != 0; + } + else if (!Character.isWhitespace((char) nextByte)) { + lineLength ++; + } + } + } + + private String[] splitInitialLine(String sb) { Matcher m = INITIAL_PATTERN.matcher(sb); if (m.matches()) { return new String[] { m.group(1), m.group(2), m.group(3) }; diff --git a/src/main/java/org/jboss/netty/handler/codec/http/HttpRequestDecoder.java b/src/main/java/org/jboss/netty/handler/codec/http/HttpRequestDecoder.java index d96fed7fd0..6ca62d52d9 100644 --- a/src/main/java/org/jboss/netty/handler/codec/http/HttpRequestDecoder.java +++ b/src/main/java/org/jboss/netty/handler/codec/http/HttpRequestDecoder.java @@ -21,7 +21,6 @@ */ package org.jboss.netty.handler.codec.http; -import org.jboss.netty.buffer.ChannelBuffer; /** * decodes an http request. @@ -37,17 +36,15 @@ public class HttpRequestDecoder extends HttpMessageDecoder { super(); } - public HttpRequestDecoder(int maxChunkSize) { - super(maxChunkSize); + public HttpRequestDecoder( + int maxInitialLineLength, int maxHeaderSize, int maxChunkSize) { + super(maxInitialLineLength, maxHeaderSize, maxChunkSize); } @Override - protected void readInitial(ChannelBuffer buffer) throws Exception{ - String line = readIntoCurrentLine(buffer); - String[] split = splitInitial(line); - message = new DefaultHttpRequest( - HttpVersion.valueOf(split[2]), HttpMethod.valueOf(split[0]), split[1]); - checkpoint(State.READ_HEADER); + protected HttpMessage createMessage(String[] initialLine) throws Exception{ + return new DefaultHttpRequest( + HttpVersion.valueOf(initialLine[2]), HttpMethod.valueOf(initialLine[0]), initialLine[1]); } @Override diff --git a/src/main/java/org/jboss/netty/handler/codec/http/HttpResponseDecoder.java b/src/main/java/org/jboss/netty/handler/codec/http/HttpResponseDecoder.java index 52f432dd30..740042e3f2 100644 --- a/src/main/java/org/jboss/netty/handler/codec/http/HttpResponseDecoder.java +++ b/src/main/java/org/jboss/netty/handler/codec/http/HttpResponseDecoder.java @@ -21,7 +21,6 @@ */ package org.jboss.netty.handler.codec.http; -import org.jboss.netty.buffer.ChannelBuffer; /** * an http response decoder @@ -37,16 +36,14 @@ public class HttpResponseDecoder extends HttpMessageDecoder { super(); } - public HttpResponseDecoder(int maxChunkSize) { - super(maxChunkSize); + public HttpResponseDecoder( + int maxInitialLineLength, int maxHeaderSize, int maxChunkSize) { + super(maxInitialLineLength, maxHeaderSize, maxChunkSize); } @Override - protected void readInitial(ChannelBuffer buffer) { - String line = readIntoCurrentLine(buffer); - String[] split = splitInitial(line); - message = new DefaultHttpResponse(HttpVersion.valueOf(split[0]), new HttpResponseStatus(Integer.valueOf(split[1]), split[2])); - checkpoint(State.READ_HEADER); + protected HttpMessage createMessage(String[] initialLine) { + return new DefaultHttpResponse(HttpVersion.valueOf(initialLine[0]), new HttpResponseStatus(Integer.valueOf(initialLine[1]), initialLine[2])); } @Override