diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/HttpCodecUtil.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpCodecUtil.java index ac40046505..d2a7b1dc00 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/HttpCodecUtil.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpCodecUtil.java @@ -151,6 +151,17 @@ final class HttpCodecUtil { return false; } + static void removeTransferEncodingChunked(HttpMessage m) { + List values = m.getHeaders(HttpHeaders.Names.TRANSFER_ENCODING); + values.remove(HttpHeaders.Values.CHUNKED); + m.setHeader(HttpHeaders.Names.TRANSFER_ENCODING, values); + } + + static boolean isContentLengthSet(HttpMessage m) { + List contentLength = m.getHeaders(HttpHeaders.Names.CONTENT_LENGTH); + return !contentLength.isEmpty(); + } + /** * A constructor to ensure that instances of this class are never made */ diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/HttpMessageEncoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpMessageEncoder.java index c83c192190..ca84a0ee16 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/HttpMessageEncoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpMessageEncoder.java @@ -47,7 +47,7 @@ public abstract class HttpMessageEncoder extends MessageToByteEncoder { private static final ByteBuf LAST_CHUNK = copiedBuffer("0\r\n\r\n", CharsetUtil.US_ASCII); - private volatile boolean chunked; + private boolean transferEncodingChunked; /** * Creates a new instance. @@ -64,17 +64,25 @@ public abstract class HttpMessageEncoder extends MessageToByteEncoder { public void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out) throws Exception { if (msg instanceof HttpMessage) { HttpMessage m = (HttpMessage) msg; - boolean chunked; + boolean contentMustBeEmmpty; if (m.isChunked()) { - // check if the Transfer-Encoding is set to chunked already. - // if not add the header to the message - if (!HttpCodecUtil.isTransferEncodingChunked(m)) { - m.addHeader(Names.TRANSFER_ENCODING, Values.CHUNKED); + // if Content-Length is set then the message can't be HTTP chunked + if (HttpCodecUtil.isContentLengthSet(m)) { + contentMustBeEmmpty = false; + transferEncodingChunked = false; + } else { + // check if the Transfer-Encoding is set to chunked already. + // if not add the header to the message + if (!HttpCodecUtil.isTransferEncodingChunked(m)) { + m.addHeader(Names.TRANSFER_ENCODING, Values.CHUNKED); + } + contentMustBeEmmpty = true; + transferEncodingChunked = true; } - chunked = this.chunked = true; } else { - chunked = this.chunked = HttpCodecUtil.isTransferEncodingChunked(m); + transferEncodingChunked = contentMustBeEmmpty = HttpCodecUtil.isTransferEncodingChunked(m); } + out.markWriterIndex(); encodeInitialLine(out, m); encodeHeaders(out, m); @@ -83,20 +91,19 @@ public abstract class HttpMessageEncoder extends MessageToByteEncoder { ByteBuf content = m.getContent(); if (content.readable()) { - if (chunked) { + if (contentMustBeEmmpty) { out.resetWriterIndex(); throw new IllegalArgumentException( - "HttpMessage.content must be empty " + - "if Transfer-Encoding is chunked."); + "HttpMessage.content must be empty if Transfer-Encoding is chunked."); } else { out.writeBytes(content, content.readerIndex(), content.readableBytes()); } } } else if (msg instanceof HttpChunk) { HttpChunk chunk = (HttpChunk) msg; - if (chunked) { + if (transferEncodingChunked) { if (chunk.isLast()) { - chunked = false; + transferEncodingChunked = false; if (chunk instanceof HttpChunkTrailer) { out.writeByte((byte) '0'); out.writeByte(CR);