diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/HttpClientCodec.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpClientCodec.java index 850faa26ad..8b868c4f49 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/HttpClientCodec.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpClientCodec.java @@ -86,7 +86,7 @@ public final class HttpClientCodec @Override protected void encode( - ChannelHandlerContext ctx, HttpObject msg, List out) throws Exception { + ChannelHandlerContext ctx, Object msg, List out) throws Exception { if (msg instanceof HttpRequest && !done) { queue.offer(((HttpRequest) msg).getMethod()); } diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/HttpObjectEncoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpObjectEncoder.java index 1d0898e2ae..6ce1013a44 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/HttpObjectEncoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpObjectEncoder.java @@ -18,8 +18,10 @@ package io.netty.handler.codec.http; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.FileRegion; import io.netty.handler.codec.MessageToMessageEncoder; import io.netty.util.CharsetUtil; +import io.netty.util.ReferenceCountUtil; import java.util.List; import java.util.Map; @@ -39,7 +41,7 @@ import static io.netty.handler.codec.http.HttpConstants.*; * To implement the encoder of such a derived protocol, extend this class and * implement all abstract methods properly. */ -public abstract class HttpObjectEncoder extends MessageToMessageEncoder { +public abstract class HttpObjectEncoder extends MessageToMessageEncoder { private static final byte[] CRLF = { CR, LF }; private static final byte[] ZERO_CRLF = { '0', CR, LF }; private static final byte[] ZERO_CRLF_CRLF = { '0', CR, LF, CR, LF }; @@ -53,7 +55,7 @@ public abstract class HttpObjectEncoder extends MessageTo private int state = ST_INIT; @Override - protected void encode(ChannelHandlerContext ctx, HttpObject msg, List out) throws Exception { + protected void encode(ChannelHandlerContext ctx, Object msg, List out) throws Exception { if (msg instanceof HttpMessage) { if (state != ST_INIT) { throw new IllegalStateException("unexpected message type: " + msg.getClass().getSimpleName()); @@ -70,25 +72,22 @@ public abstract class HttpObjectEncoder extends MessageTo out.add(buf); state = HttpHeaders.isTransferEncodingChunked(m) ? ST_CONTENT_CHUNK : ST_CONTENT_NON_CHUNK; } - if (msg instanceof HttpContent) { + if (msg instanceof HttpContent || msg instanceof ByteBuf || msg instanceof FileRegion) { if (state == ST_INIT) { throw new IllegalStateException("unexpected message type: " + msg.getClass().getSimpleName()); } - HttpContent chunk = (HttpContent) msg; - ByteBuf content = chunk.content(); - int contentLength = content.readableBytes(); - + int contentLength = contentLength(msg); if (state == ST_CONTENT_NON_CHUNK) { if (contentLength > 0) { - out.add(content.retain()); + out.add(encodeAndRetain(msg)); } else { // Need to produce some output otherwise an // IllegalstateException will be thrown out.add(Unpooled.EMPTY_BUFFER); } - if (chunk instanceof LastHttpContent) { + if (msg instanceof LastHttpContent) { state = ST_INIT; } } else if (state == ST_CONTENT_CHUNK) { @@ -98,12 +97,12 @@ public abstract class HttpObjectEncoder extends MessageTo buf.writeBytes(length); buf.writeBytes(CRLF); out.add(buf); - out.add(content.retain()); + out.add(encodeAndRetain(msg)); out.add(ctx.alloc().buffer(CRLF.length).writeBytes(CRLF)); } - if (chunk instanceof LastHttpContent) { - HttpHeaders headers = ((LastHttpContent) chunk).trailingHeaders(); + if (msg instanceof LastHttpContent) { + HttpHeaders headers = ((LastHttpContent) msg).trailingHeaders(); if (headers.isEmpty()) { out.add(ctx.alloc().buffer(ZERO_CRLF_CRLF.length).writeBytes(ZERO_CRLF_CRLF)); } else { @@ -128,6 +127,37 @@ public abstract class HttpObjectEncoder extends MessageTo } } + @Override + public boolean acceptOutboundMessage(Object msg) throws Exception { + return msg instanceof HttpObject || msg instanceof ByteBuf || msg instanceof FileRegion; + } + + private static Object encodeAndRetain(Object msg) { + if (msg instanceof ByteBuf) { + return ((ByteBuf) msg).retain(); + } + if (msg instanceof HttpContent) { + return ((HttpContent) msg).content().retain(); + } + if (msg instanceof FileRegion) { + return ((FileRegion) msg).retain(); + } + throw new IllegalStateException("unexpected message type: " + msg.getClass().getSimpleName()); + } + + private static int contentLength(Object msg) { + if (msg instanceof HttpContent) { + return ((HttpContent) msg).content().readableBytes(); + } + if (msg instanceof ByteBuf) { + return ((ByteBuf) msg).readableBytes(); + } + if (msg instanceof FileRegion) { + return (int) ((FileRegion) msg).count(); + } + throw new IllegalStateException("unexpected message type: " + msg.getClass().getSimpleName()); + } + private static void encodeHeaders(ByteBuf buf, HttpHeaders headers) { for (Map.Entry h: headers) { encodeHeader(buf, h.getKey(), h.getValue());