Fixed issue: NETTY-272 HttpMessageEncoder should not prepend/append extra data around HttpChunk content if Transfer-Encoding is not chunked.

* HttpMessageEncoder now does not add any extra data around HttpChunk content if Transfer-Encoding is not 'chunked'
* Moved the utility code that checks the existance of 'Transfer-Encoding: chunked' to HttpCodecUtil so that both HttpMessageEncoder and DefaultHttpMessage can use it
This commit is contained in:
Trustin Lee 2010-01-07 09:05:38 +00:00
parent 491baa0c7b
commit 661acd24c8
3 changed files with 59 additions and 37 deletions

View File

@ -112,19 +112,9 @@ public class DefaultHttpMessage implements HttpMessage {
public boolean isChunked() { public boolean isChunked() {
if (chunked) { if (chunked) {
return true; return true;
} else {
return HttpCodecUtil.isTransferEncodingChunked(this);
} }
List<String> chunked = getHeaders(HttpHeaders.Names.TRANSFER_ENCODING);
if (chunked.isEmpty()) {
return false;
}
for (String v: chunked) {
if (v.equalsIgnoreCase(HttpHeaders.Values.CHUNKED)) {
return true;
}
}
return false;
} }
public void setChunked(boolean chunked) { public void setChunked(boolean chunked) {

View File

@ -16,6 +16,7 @@
package org.jboss.netty.handler.codec.http; package org.jboss.netty.handler.codec.http;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.List;
import org.jboss.netty.util.CharsetUtil; import org.jboss.netty.util.CharsetUtil;
@ -159,4 +160,18 @@ class HttpCodecUtil {
"value must not end with '\\r' or '\\n':" + value); "value must not end with '\\r' or '\\n':" + value);
} }
} }
static boolean isTransferEncodingChunked(HttpMessage m) {
List<String> chunked = m.getHeaders(HttpHeaders.Names.TRANSFER_ENCODING);
if (chunked.isEmpty()) {
return false;
}
for (String v: chunked) {
if (v.equalsIgnoreCase(HttpHeaders.Values.CHUNKED)) {
return true;
}
}
return false;
}
} }

View File

@ -50,12 +50,14 @@ import org.jboss.netty.util.CharsetUtil;
* *
* @apiviz.landmark * @apiviz.landmark
*/ */
@ChannelPipelineCoverage("all") @ChannelPipelineCoverage("one")
public abstract class HttpMessageEncoder extends OneToOneEncoder { public abstract class HttpMessageEncoder extends OneToOneEncoder {
private static final ChannelBuffer LAST_CHUNK = private static final ChannelBuffer LAST_CHUNK =
copiedBuffer("0\r\n\r\n", CharsetUtil.US_ASCII); copiedBuffer("0\r\n\r\n", CharsetUtil.US_ASCII);
private volatile boolean chunked;
/** /**
* Creates a new instance. * Creates a new instance.
*/ */
@ -66,16 +68,21 @@ public abstract class HttpMessageEncoder extends OneToOneEncoder {
@Override @Override
protected Object encode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception { protected Object encode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception {
if (msg instanceof HttpMessage) { if (msg instanceof HttpMessage) {
HttpMessage request = (HttpMessage) msg; HttpMessage m = (HttpMessage) msg;
boolean chunked = this.chunked = HttpCodecUtil.isTransferEncodingChunked(m);
ChannelBuffer header = ChannelBuffers.dynamicBuffer( ChannelBuffer header = ChannelBuffers.dynamicBuffer(
channel.getConfig().getBufferFactory()); channel.getConfig().getBufferFactory());
encodeInitialLine(header, request); encodeInitialLine(header, m);
encodeHeaders(header, request); encodeHeaders(header, m);
header.writeBytes(CRLF); header.writeBytes(CRLF);
ChannelBuffer content = request.getContent(); ChannelBuffer content = m.getContent();
if (!content.readable()) { if (!content.readable()) {
return header; // no content return header; // no content
} else if (chunked) {
throw new IllegalArgumentException(
"HttpMessage.content must be empty " +
"if Transfer-Encoding is chunked.");
} else { } else {
return wrappedBuffer(header, content); return wrappedBuffer(header, content);
} }
@ -83,7 +90,9 @@ public abstract class HttpMessageEncoder extends OneToOneEncoder {
if (msg instanceof HttpChunk) { if (msg instanceof HttpChunk) {
HttpChunk chunk = (HttpChunk) msg; HttpChunk chunk = (HttpChunk) msg;
if (chunked) {
if (chunk == HttpChunk.LAST_CHUNK) { if (chunk == HttpChunk.LAST_CHUNK) {
chunked = false;
return LAST_CHUNK.duplicate(); return LAST_CHUNK.duplicate();
} else if (chunk instanceof HttpChunkTrailer) { } else if (chunk instanceof HttpChunkTrailer) {
ChannelBuffer trailer = ChannelBuffers.dynamicBuffer( ChannelBuffer trailer = ChannelBuffers.dynamicBuffer(
@ -105,6 +114,14 @@ public abstract class HttpMessageEncoder extends OneToOneEncoder {
content.slice(content.readerIndex(), contentLength), content.slice(content.readerIndex(), contentLength),
wrappedBuffer(CRLF)); wrappedBuffer(CRLF));
} }
} else {
if (chunk == HttpChunk.LAST_CHUNK) {
return null;
} else {
return chunk.getContent();
}
}
} }
// Unknown message type. // Unknown message type.