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:
parent
491baa0c7b
commit
661acd24c8
@ -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) {
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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,28 +90,38 @@ public abstract class HttpMessageEncoder extends OneToOneEncoder {
|
|||||||
|
|
||||||
if (msg instanceof HttpChunk) {
|
if (msg instanceof HttpChunk) {
|
||||||
HttpChunk chunk = (HttpChunk) msg;
|
HttpChunk chunk = (HttpChunk) msg;
|
||||||
if (chunk == HttpChunk.LAST_CHUNK) {
|
if (chunked) {
|
||||||
return LAST_CHUNK.duplicate();
|
if (chunk == HttpChunk.LAST_CHUNK) {
|
||||||
} else if (chunk instanceof HttpChunkTrailer) {
|
chunked = false;
|
||||||
ChannelBuffer trailer = ChannelBuffers.dynamicBuffer(
|
return LAST_CHUNK.duplicate();
|
||||||
channel.getConfig().getBufferFactory());
|
} else if (chunk instanceof HttpChunkTrailer) {
|
||||||
trailer.writeByte((byte) '0');
|
ChannelBuffer trailer = ChannelBuffers.dynamicBuffer(
|
||||||
trailer.writeBytes(CRLF);
|
channel.getConfig().getBufferFactory());
|
||||||
encodeTrailingHeaders(trailer, (HttpChunkTrailer) chunk);
|
trailer.writeByte((byte) '0');
|
||||||
trailer.writeBytes(CRLF);
|
trailer.writeBytes(CRLF);
|
||||||
return trailer;
|
encodeTrailingHeaders(trailer, (HttpChunkTrailer) chunk);
|
||||||
} else {
|
trailer.writeBytes(CRLF);
|
||||||
ChannelBuffer content = chunk.getContent();
|
return trailer;
|
||||||
int contentLength = content.readableBytes();
|
} else {
|
||||||
|
ChannelBuffer content = chunk.getContent();
|
||||||
|
int contentLength = content.readableBytes();
|
||||||
|
|
||||||
return wrappedBuffer(
|
return wrappedBuffer(
|
||||||
copiedBuffer(
|
copiedBuffer(
|
||||||
Integer.toHexString(contentLength),
|
Integer.toHexString(contentLength),
|
||||||
CharsetUtil.US_ASCII),
|
CharsetUtil.US_ASCII),
|
||||||
wrappedBuffer(CRLF),
|
wrappedBuffer(CRLF),
|
||||||
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.
|
||||||
|
Loading…
Reference in New Issue
Block a user