Allow to also write FileRegion and ChunkInput when using HTTP chunked. Fixes [#1693]
This commit is contained in:
parent
ea1dca8105
commit
60b889375c
@ -86,7 +86,7 @@ public final class HttpClientCodec
|
||||
|
||||
@Override
|
||||
protected void encode(
|
||||
ChannelHandlerContext ctx, HttpObject msg, List<Object> out) throws Exception {
|
||||
ChannelHandlerContext ctx, Object msg, List<Object> out) throws Exception {
|
||||
if (msg instanceof HttpRequest && !done) {
|
||||
queue.offer(((HttpRequest) msg).getMethod());
|
||||
}
|
||||
|
@ -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<H extends HttpMessage> extends MessageToMessageEncoder<HttpObject> {
|
||||
public abstract class HttpObjectEncoder<H extends HttpMessage> extends MessageToMessageEncoder<Object> {
|
||||
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<H extends HttpMessage> extends MessageTo
|
||||
private int state = ST_INIT;
|
||||
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext ctx, HttpObject msg, List<Object> out) throws Exception {
|
||||
protected void encode(ChannelHandlerContext ctx, Object msg, List<Object> 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<H extends HttpMessage> 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<H extends HttpMessage> 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<H extends HttpMessage> 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<String, String> h: headers) {
|
||||
encodeHeader(buf, h.getKey(), h.getValue());
|
||||
|
Loading…
Reference in New Issue
Block a user