Fixed issue: NETTY-359 Missing support for HTTP 'Expect: 100-continue' header.

* Improved HttpHeaders.is100ContinueExpected() to conform to the RFC
* HttpChunkAggregator now sends "HTTP/1.1 100 Continue" response automatically.
* Added some TODO items which should be done in 4.0.
This commit is contained in:
Trustin Lee 2010-10-19 05:40:44 +00:00
parent d093ed4a54
commit 57dc0b3bc8
3 changed files with 39 additions and 0 deletions

View File

@ -15,6 +15,9 @@
*/ */
package org.jboss.netty.handler.codec.http; package org.jboss.netty.handler.codec.http;
import static org.jboss.netty.channel.Channels.*;
import static org.jboss.netty.handler.codec.http.HttpHeaders.*;
import java.util.List; import java.util.List;
import java.util.Map.Entry; import java.util.Map.Entry;
@ -27,6 +30,7 @@ import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
import org.jboss.netty.handler.codec.frame.TooLongFrameException; import org.jboss.netty.handler.codec.frame.TooLongFrameException;
import org.jboss.netty.util.CharsetUtil;
/** /**
* A {@link ChannelHandler} that aggregates an {@link HttpMessage} * A {@link ChannelHandler} that aggregates an {@link HttpMessage}
@ -53,6 +57,9 @@ import org.jboss.netty.handler.codec.frame.TooLongFrameException;
*/ */
public class HttpChunkAggregator extends SimpleChannelUpstreamHandler { public class HttpChunkAggregator extends SimpleChannelUpstreamHandler {
private static final ChannelBuffer CONTINUE = ChannelBuffers.copiedBuffer(
"HTTP/1.1 100 Continue\r\n\r\n", CharsetUtil.US_ASCII);
private final int maxContentLength; private final int maxContentLength;
private HttpMessage currentMessage; private HttpMessage currentMessage;
@ -82,6 +89,16 @@ public class HttpChunkAggregator extends SimpleChannelUpstreamHandler {
if (msg instanceof HttpMessage) { if (msg instanceof HttpMessage) {
HttpMessage m = (HttpMessage) msg; HttpMessage m = (HttpMessage) msg;
// Handle the 'Expect: 100-continue' header if necessary.
// TODO: Respond with 413 Request Entity Too Large
// and discard the traffic or close the connection.
// No need to notify the upstream handlers - just log.
// If decoding a response, just throw an exception.
if (is100ContinueExpected(m)) {
write(ctx, succeededFuture(ctx.getChannel()), CONTINUE.duplicate());
}
if (m.isChunked()) { if (m.isChunked()) {
// A chunked message - remove 'Transfer-Encoding' header, // A chunked message - remove 'Transfer-Encoding' header,
// initialize the cumulative buffer, and wait for incoming chunks. // initialize the cumulative buffer, and wait for incoming chunks.
@ -111,6 +128,10 @@ public class HttpChunkAggregator extends SimpleChannelUpstreamHandler {
ChannelBuffer content = currentMessage.getContent(); ChannelBuffer content = currentMessage.getContent();
if (content.readableBytes() > maxContentLength - chunk.getContent().readableBytes()) { if (content.readableBytes() > maxContentLength - chunk.getContent().readableBytes()) {
// TODO: Respond with 413 Request Entity Too Large
// and discard the traffic or close the connection.
// No need to notify the upstream handlers - just log.
// If decoding a response, just throw an exception.
throw new TooLongFrameException( throw new TooLongFrameException(
"HTTP content length exceeded " + maxContentLength + "HTTP content length exceeded " + maxContentLength +
" bytes."); " bytes.");

View File

@ -679,6 +679,16 @@ public class HttpHeaders {
* {@code "Expect: 100-continue"} header. * {@code "Expect: 100-continue"} header.
*/ */
public static boolean is100ContinueExpected(HttpMessage message) { public static boolean is100ContinueExpected(HttpMessage message) {
// Expect: 100-continue is for requests only.
if (!(message instanceof HttpRequest)) {
return false;
}
// It works only on HTTP/1.1 or later.
if (message.getProtocolVersion().compareTo(HttpVersion.HTTP_1_1) < 0) {
return false;
}
// In most cases, there will be one or zero 'Expect' header. // In most cases, there will be one or zero 'Expect' header.
String value = message.getHeader(Names.EXPECT); String value = message.getHeader(Names.EXPECT);
if (value == null) { if (value == null) {

View File

@ -536,6 +536,10 @@ public abstract class HttpMessageDecoder extends ReplayingDecoder<HttpMessageDec
// Abort decoding if the header part is too large. // Abort decoding if the header part is too large.
if (headerSize >= maxHeaderSize) { if (headerSize >= maxHeaderSize) {
// TODO: Respond with Bad Request and discard the traffic
// or close the connection.
// No need to notify the upstream handlers - just log.
// If decoding a response, just throw an exception.
throw new TooLongFrameException( throw new TooLongFrameException(
"HTTP header is larger than " + "HTTP header is larger than " +
maxHeaderSize + " bytes."); maxHeaderSize + " bytes.");
@ -581,6 +585,10 @@ public abstract class HttpMessageDecoder extends ReplayingDecoder<HttpMessageDec
} }
else { else {
if (lineLength >= maxLineLength) { if (lineLength >= maxLineLength) {
// TODO: Respond with Bad Request and discard the traffic
// or close the connection.
// No need to notify the upstream handlers - just log.
// If decoding a response, just throw an exception.
throw new TooLongFrameException( throw new TooLongFrameException(
"An HTTP line is larger than " + maxLineLength + "An HTTP line is larger than " + maxLineLength +
" bytes."); " bytes.");