use of io.netty.handler.codec.http.LastHttpContent in project reactor-netty by reactor.
the class HttpTrafficHandler method write.
@Override
@SuppressWarnings("FutureReturnValueIgnored")
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
// modify message on way out to add headers if needed
if (msg instanceof HttpResponse) {
final HttpResponse response = (HttpResponse) msg;
nonInformationalResponse = !isInformational(response);
// Assume the response writer knows if they can persist or not and sets isKeepAlive on the response
boolean maxKeepAliveRequestsReached = maxKeepAliveRequests != -1 && HttpServerOperations.requestsCounter(ctx.channel()) == maxKeepAliveRequests;
if (maxKeepAliveRequestsReached || !isKeepAlive(response) || !isSelfDefinedMessageLength(response)) {
// No longer keep alive as the client can't tell when the message is done unless we close connection
pendingResponses = 0;
persistentConnection = false;
}
// Server might think it can keep connection alive, but we should fix response header if we know better
if (!shouldKeepAlive()) {
setKeepAlive(response, false);
}
if (response.status().equals(HttpResponseStatus.CONTINUE)) {
// "FutureReturnValueIgnored" this is deliberate
ctx.write(msg, promise);
return;
}
}
if (msg instanceof LastHttpContent) {
if (!shouldKeepAlive()) {
if (HttpServerOperations.log.isDebugEnabled()) {
HttpServerOperations.log.debug(format(ctx.channel(), "Detected non persistent http " + "connection, preparing to close"), pendingResponses);
}
ctx.write(msg, promise.unvoid()).addListener(this).addListener(ChannelFutureListener.CLOSE);
return;
}
ctx.write(msg, promise.unvoid()).addListener(this);
if (!persistentConnection) {
return;
}
if (nonInformationalResponse) {
nonInformationalResponse = false;
pendingResponses -= 1;
if (HttpServerOperations.log.isDebugEnabled()) {
HttpServerOperations.log.debug(format(ctx.channel(), "Decreasing pending responses, now {}"), pendingResponses);
}
}
if (pipelined != null && !pipelined.isEmpty()) {
if (HttpServerOperations.log.isDebugEnabled()) {
HttpServerOperations.log.debug(format(ctx.channel(), "Draining next pipelined " + "request, pending response count: {}, queued: {}"), pendingResponses, pipelined.size());
}
ctx.executor().execute(this);
} else {
ctx.read();
}
return;
}
if (persistentConnection && pendingResponses == 0) {
if (HttpServerOperations.log.isDebugEnabled()) {
HttpServerOperations.log.debug(format(ctx.channel(), "Dropped HTTP content, " + "since response has been sent already: {}"), toPrettyHexDump(msg));
}
ReferenceCountUtil.release(msg);
promise.setSuccess();
return;
}
// "FutureReturnValueIgnored" this is deliberate
ctx.write(msg, promise);
}
use of io.netty.handler.codec.http.LastHttpContent in project reactor-netty by reactor.
the class HttpTrafficHandler method channelRead.
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
if (secure == null) {
secure = ctx.channel().pipeline().get(SslHandler.class) != null;
}
if (remoteAddress == null) {
remoteAddress = Optional.ofNullable(HAProxyMessageReader.resolveRemoteAddressFromProxyProtocol(ctx.channel())).orElse(ctx.channel().remoteAddress());
}
// read message and track if it was keepAlive
if (msg instanceof HttpRequest) {
IdleTimeoutHandler.removeIdleTimeoutHandler(ctx.pipeline());
final HttpRequest request = (HttpRequest) msg;
if (H2.equals(request.protocolVersion())) {
sendDecodingFailures(new IllegalStateException("Unexpected request [" + request.method() + " " + request.uri() + " HTTP/2.0]"), msg);
return;
}
if (persistentConnection) {
pendingResponses += 1;
if (HttpServerOperations.log.isDebugEnabled()) {
HttpServerOperations.log.debug(format(ctx.channel(), "Increasing pending responses, now {}"), pendingResponses);
}
persistentConnection = isKeepAlive(request);
} else {
if (HttpServerOperations.log.isDebugEnabled()) {
HttpServerOperations.log.debug(format(ctx.channel(), "Dropping pipelined HTTP request, " + "previous response requested connection close"));
}
ReferenceCountUtil.release(msg);
return;
}
if (pendingResponses > 1) {
if (HttpServerOperations.log.isDebugEnabled()) {
HttpServerOperations.log.debug(format(ctx.channel(), "Buffering pipelined HTTP request, " + "pending response count: {}, queue: {}"), pendingResponses, pipelined != null ? pipelined.size() : 0);
}
overflow = true;
doPipeline(ctx, msg);
return;
} else {
overflow = false;
DecoderResult decoderResult = request.decoderResult();
if (decoderResult.isFailure()) {
sendDecodingFailures(decoderResult.cause(), msg);
return;
}
HttpServerOperations ops;
try {
ops = new HttpServerOperations(Connection.from(ctx.channel()), listener, request, compress, ConnectionInfo.from(ctx.channel(), request, secure, remoteAddress, forwardedHeaderHandler), cookieDecoder, cookieEncoder, formDecoderProvider, mapHandle, secure);
} catch (RuntimeException e) {
sendDecodingFailures(e, msg);
return;
}
ops.bind();
listener.onStateChange(ops, ConnectionObserver.State.CONFIGURED);
ctx.fireChannelRead(msg);
return;
}
} else if (persistentConnection && pendingResponses == 0) {
if (msg instanceof LastHttpContent) {
DecoderResult decoderResult = ((LastHttpContent) msg).decoderResult();
if (decoderResult.isFailure()) {
sendDecodingFailures(decoderResult.cause(), msg);
return;
}
ctx.fireChannelRead(msg);
} else {
if (HttpServerOperations.log.isDebugEnabled()) {
HttpServerOperations.log.debug(format(ctx.channel(), "Dropped HTTP content, " + "since response has been sent already: {}"), msg);
}
ReferenceCountUtil.release(msg);
}
ctx.read();
return;
} else if (overflow) {
if (HttpServerOperations.log.isDebugEnabled()) {
HttpServerOperations.log.debug(format(ctx.channel(), "Buffering pipelined HTTP content, " + "pending response count: {}, pending pipeline:{}"), pendingResponses, pipelined != null ? pipelined.size() : 0);
}
doPipeline(ctx, msg);
return;
}
if (msg instanceof DecoderResultProvider) {
DecoderResult decoderResult = ((DecoderResultProvider) msg).decoderResult();
if (decoderResult.isFailure()) {
sendDecodingFailures(decoderResult.cause(), msg);
return;
}
}
ctx.fireChannelRead(msg);
}
use of io.netty.handler.codec.http.LastHttpContent in project apn-proxy by apn-proxy.
the class TestHttpClientHandler method channelRead0.
@Override
public void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
// }
if (msg instanceof HttpResponse) {
HttpResponse response = (HttpResponse) msg;
TestResultHolder.httpStatusCode(response.getStatus().code());
}
if (msg instanceof LastHttpContent) {
ctx.close();
}
}
use of io.netty.handler.codec.http.LastHttpContent in project vert.x by eclipse.
the class VertxHttpHandler method safeObject.
@Override
protected Object safeObject(Object msg, ByteBufAllocator allocator) throws Exception {
if (msg instanceof HttpContent) {
HttpContent content = (HttpContent) msg;
ByteBuf buf = content.content();
if (buf != Unpooled.EMPTY_BUFFER && buf.isDirect()) {
ByteBuf newBuf = safeBuffer(content, allocator);
if (msg instanceof LastHttpContent) {
LastHttpContent last = (LastHttpContent) msg;
return new AssembledLastHttpContent(newBuf, last.trailingHeaders(), last.getDecoderResult());
} else {
return new DefaultHttpContent(newBuf);
}
}
} else if (msg instanceof WebSocketFrame) {
ByteBuf payload = safeBuffer((WebSocketFrame) msg, allocator);
boolean isFinal = ((WebSocketFrame) msg).isFinalFragment();
FrameType frameType;
if (msg instanceof BinaryWebSocketFrame) {
frameType = FrameType.BINARY;
} else if (msg instanceof CloseWebSocketFrame) {
frameType = FrameType.CLOSE;
} else if (msg instanceof PingWebSocketFrame) {
frameType = FrameType.PING;
} else if (msg instanceof PongWebSocketFrame) {
frameType = FrameType.PONG;
} else if (msg instanceof TextWebSocketFrame) {
frameType = FrameType.TEXT;
} else if (msg instanceof ContinuationWebSocketFrame) {
frameType = FrameType.CONTINUATION;
} else {
throw new IllegalStateException("Unsupported websocket msg " + msg);
}
return new WebSocketFrameImpl(frameType, payload, isFinal);
}
return msg;
}
use of io.netty.handler.codec.http.LastHttpContent in project vert.x by eclipse.
the class ClientHandler method doMessageReceived.
@Override
protected void doMessageReceived(ClientConnection conn, ChannelHandlerContext ctx, Object msg) {
if (conn == null) {
return;
}
if (msg instanceof HttpObject) {
HttpObject obj = (HttpObject) msg;
DecoderResult result = obj.decoderResult();
if (result.isFailure()) {
// Close the connection as Netty's HttpResponseDecoder will not try further processing
// see https://github.com/netty/netty/issues/3362
conn.handleException(result.cause());
conn.close();
return;
}
if (msg instanceof HttpResponse) {
HttpResponse response = (HttpResponse) obj;
conn.handleResponse(response);
return;
}
if (msg instanceof HttpContent) {
HttpContent chunk = (HttpContent) obj;
if (chunk.content().isReadable()) {
Buffer buff = Buffer.buffer(chunk.content().slice());
conn.handleResponseChunk(buff);
}
if (chunk instanceof LastHttpContent) {
conn.handleResponseEnd((LastHttpContent) chunk);
}
return;
}
} else if (msg instanceof WebSocketFrameInternal) {
WebSocketFrameInternal frame = (WebSocketFrameInternal) msg;
switch(frame.type()) {
case BINARY:
case CONTINUATION:
case TEXT:
conn.handleWsFrame(frame);
break;
case PING:
// Echo back the content of the PING frame as PONG frame as specified in RFC 6455 Section 5.5.2
ctx.writeAndFlush(new WebSocketFrameImpl(FrameType.PONG, frame.getBinaryData()));
break;
case PONG:
// Just ignore it
break;
case CLOSE:
if (!closeFrameSent) {
// Echo back close frame and close the connection once it was written.
// This is specified in the WebSockets RFC 6455 Section 5.4.1
ctx.writeAndFlush(frame).addListener(ChannelFutureListener.CLOSE);
closeFrameSent = true;
}
break;
default:
throw new IllegalStateException("Invalid type: " + frame.type());
}
return;
}
throw new IllegalStateException("Invalid object " + msg);
}
Aggregations