Search in sources :

Example 51 with LastHttpContent

use of io.netty.handler.codec.http.LastHttpContent in project riposte by Nike-Inc.

the class ProxyRouterEndpointExecutionHandler method registerChunkStreamingAction.

protected void registerChunkStreamingAction(ProxyRouterProcessingState proxyRouterState, HttpContent msgContent, ChannelHandlerContext ctx) {
    // We have a content chunk to stream downstream. Attach the chunk processing to the proxyRouterState and
    // tell it to stream itself when that future says everything is ready.
    proxyRouterState.registerStreamingChannelChunkProcessingAction((sc, cause) -> {
        if (releaseContentChunkIfStreamAlreadyFailed(msgContent, proxyRouterState)) {
            // content has been released. Nothing left for us to do.
            return;
        }
        if (cause == null) {
            // Nothing has blown up yet, so stream this next chunk downstream. Calling streamChunk() will decrement
            // the chunk's reference count (at some point in the future), allowing it to be destroyed since
            // this should be the last handle on the chunk's memory.
            ChannelFuture writeFuture = sc.streamChunk(msgContent);
            writeFuture.addListener(future -> {
                // a problem.
                if (!future.isSuccess()) {
                    try {
                        String errorMsg = "Chunk streaming ChannelFuture came back as being unsuccessful. " + "downstream_channel_id=" + sc.getChannel().toString();
                        Throwable errorToFire = new WrapperException(errorMsg, future.cause());
                        StreamingCallback callback = proxyRouterState.getStreamingCallback();
                        if (callback != null) {
                            // This doesn't necessarily guarantee a broken downstream response in the case where
                            // the downstream system returned a response before receiving all request chunks
                            // (e.g. short circuit error response), so we'll call unrecoverableErrorOccurred()
                            // with false for the guaranteesBrokenDownstreamResponse argument. This will give
                            // the downstream system a chance to fully send its response if it had started
                            // but not yet completed by the time we hit this code on the request chunk.
                            callback.unrecoverableErrorOccurred(errorToFire, false);
                        } else {
                            // We have to call proxyRouterState.cancelRequestStreaming() here since we couldn't
                            // call callback.unrecoverableErrorOccurred(...);
                            proxyRouterState.cancelRequestStreaming(errorToFire, ctx);
                            runnableWithTracingAndMdc(() -> logger.error("Unrecoverable error occurred and somehow the StreamingCallback was " + "not available. This should not be possible. Firing the following " + "error down the pipeline manually: " + errorMsg, errorToFire), ctx).run();
                            executeOnlyIfChannelIsActive(ctx, "ProxyRouterEndpointExecutionHandler-streamchunk-writefuture-unsuccessful", () -> ctx.fireExceptionCaught(errorToFire));
                        }
                    } finally {
                        // Close down the StreamingChannel so its Channel can be released back to the pool.
                        sc.closeChannelDueToUnrecoverableError(future.cause());
                    }
                } else if (msgContent instanceof LastHttpContent) {
                    // This msgContent was the last chunk and it was streamed successfully, so mark the proxy router
                    // state as having completed successfully.
                    proxyRouterState.setRequestStreamingCompletedSuccessfully();
                }
            });
        } else {
            StreamingChannel scToNotify = sc;
            try {
                // Something blew up while attempting to send a chunk to the downstream server.
                if (scToNotify == null) {
                    // No StreamingChannel from the registration future. Try to extract it from the
                    // proxyRouterState directly if possible.
                    CompletableFuture<StreamingChannel> scFuture = proxyRouterState.getStreamingChannelCompletableFuture();
                    if (scFuture.isDone() && !scFuture.isCompletedExceptionally()) {
                        try {
                            scToNotify = scFuture.join();
                        } catch (Throwable t) {
                            runnableWithTracingAndMdc(() -> logger.error("What? This should never happen. Swallowing.", t), ctx).run();
                        }
                    }
                }
                String downstreamChannelId = (scToNotify == null) ? "UNKNOWN" : scToNotify.getChannel().toString();
                String errorMsg = "Chunk streaming future came back as being unsuccessful. " + "downstream_channel_id=" + downstreamChannelId;
                Throwable errorToFire = new WrapperException(errorMsg, cause);
                StreamingCallback callback = proxyRouterState.getStreamingCallback();
                if (callback != null) {
                    // This doesn't necessarily guarantee a broken downstream response in the case where
                    // the downstream system returned a response before receiving all request chunks
                    // (e.g. short circuit error response), so we'll call unrecoverableErrorOccurred()
                    // with false for the guaranteesBrokenDownstreamResponse argument. This will give
                    // the downstream system a chance to fully send its response if it had started
                    // but not yet completed by the time we hit this code on the request chunk.
                    callback.unrecoverableErrorOccurred(errorToFire, false);
                } else {
                    runnableWithTracingAndMdc(() -> logger.error("Unrecoverable error occurred and somehow the StreamingCallback was not " + "available. This should not be possible. Firing the following error down the " + "pipeline manually: " + errorMsg, errorToFire), ctx).run();
                    executeOnlyIfChannelIsActive(ctx, "ProxyRouterEndpointExecutionHandler-streamchunk-unsuccessful", () -> ctx.fireExceptionCaught(errorToFire));
                }
            } finally {
                // We were never able to call StreamingChannel.streamChunk() on this chunk, so it still has a
                // dangling reference count handle that needs cleaning up. Since there's nothing left to
                // do with this chunk, we can release it now.
                msgContent.release();
                // Close down the StreamingChannel so its Channel can be released back to the pool.
                if (scToNotify != null) {
                    scToNotify.closeChannelDueToUnrecoverableError(cause);
                } else {
                    @SuppressWarnings("ThrowableResultOfMethodCallIgnored") Throwable actualCause = unwrapAsyncExceptions(cause);
                    if (!(actualCause instanceof WrapperException)) {
                        runnableWithTracingAndMdc(() -> logger.error("Unable to extract StreamingChannel during error handling and the error that " + "caused it was not a WrapperException, meaning " + "StreamingAsyncHttpClient.streamDownstreamCall(...) did not properly handle it. " + "This should likely never happen and might leave things in a bad state - it " + "should be investigated and fixed! The error that caused this is: ", cause), ctx).run();
                    }
                }
            }
        }
    });
}
Also used : ChannelFuture(io.netty.channel.ChannelFuture) WrapperException(com.nike.backstopper.exception.WrapperException) StreamingChannel(com.nike.riposte.client.asynchttp.netty.StreamingAsyncHttpClient.StreamingChannel) StreamingCallback(com.nike.riposte.client.asynchttp.netty.StreamingAsyncHttpClient.StreamingCallback) LastHttpContent(io.netty.handler.codec.http.LastHttpContent)

Example 52 with LastHttpContent

use of io.netty.handler.codec.http.LastHttpContent in project riposte by Nike-Inc.

the class RequestContentValidationHandler method doChannelRead.

@Override
public PipelineContinuationBehavior doChannelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    if (msg instanceof LastHttpContent) {
        HttpProcessingState state = ChannelAttributes.getHttpProcessingStateForChannel(ctx).get();
        Endpoint<?> endpoint = state.getEndpointForExecution();
        RequestInfo<?> requestInfo = state.getRequestInfo();
        if (endpoint != null && requestInfo.isCompleteRequestWithAllChunks()) {
            if (endpoint.isRequireRequestContent() && requestInfo.getRawContentLengthInBytes() == 0) {
                throw new MissingRequiredContentException(requestInfo, endpoint);
            }
            if (endpoint.isValidateRequestContent(requestInfo) && // TODO: Is this actually necessary? Does false indicate a misconfigured endpoint?
            requestInfo.isContentDeserializerSetup()) {
                if (endpoint.shouldValidateAsynchronously(requestInfo)) {
                    // The endpoint has requested asynchronous validation, so split it off into the
                    // pre-endpoint-execution-work-chain.
                    state.addPreEndpointExecutionWorkChainSegment(aVoid -> CompletableFuture.runAsync(() -> executeValidation(requestInfo, endpoint, ctx), ASYNC_VALIDATION_EXECUTOR));
                } else {
                    // This request can be validated synchronously, so do it now.
                    executeValidation(requestInfo, endpoint, ctx);
                }
            }
        }
    }
    return PipelineContinuationBehavior.CONTINUE;
}
Also used : MissingRequiredContentException(com.nike.riposte.server.error.exception.MissingRequiredContentException) HttpProcessingState(com.nike.riposte.server.http.HttpProcessingState) LastHttpContent(io.netty.handler.codec.http.LastHttpContent)

Example 53 with LastHttpContent

use of io.netty.handler.codec.http.LastHttpContent in project riposte by Nike-Inc.

the class RequestStateCleanerHandler method channelRead.

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    if (msg instanceof HttpRequest) {
        // New request incoming - setup/clear *all* state objects for new requests
        for (ProcessingStateClassAndKeyPair<? extends ProcessingState> stateClassAndKeyPair : PROCESSING_STATE_ATTRIBUTE_KEYS) {
            // See if we have an existing state object for this channel for the given state type.
            @SuppressWarnings("unchecked") AttributeKey<ProcessingState> attrKey = (AttributeKey<ProcessingState>) stateClassAndKeyPair.getRight();
            Attribute<ProcessingState> processingStateAttr = ctx.channel().attr(attrKey);
            ProcessingState processingState = processingStateAttr.get();
            if (processingState == null) {
                // We don't already have one for this channel, so create one and register it.
                processingState = stateClassAndKeyPair.getLeft().newInstance();
                processingStateAttr.set(processingState);
            }
            // Clean the state for the new request.
            processingState.cleanStateForNewRequest();
        }
        HttpProcessingState httpProcessingState = ChannelAttributes.getHttpProcessingStateForChannel(ctx).get();
        // Set the DistributedTracingConfig on the HttpProcessingState.
        // noinspection deprecation - This is the only place that should actually be calling this method.
        httpProcessingState.setDistributedTracingConfig(distributedTracingConfig);
        // Send a request received event to the metricsListener.
        if (metricsListener != null) {
            metricsListener.onEvent(ServerMetricsEvent.REQUEST_RECEIVED, httpProcessingState);
        }
        // Remove the idle channel timeout handler (if there is one) so that it doesn't kill this new request if the
        // endpoint takes longer to complete than the idle timeout value - the idle channel timeout is only for
        // timing out channels that are idle *in-between* requests.
        ChannelPipeline pipeline = ctx.pipeline();
        ChannelHandler idleChannelTimeoutHandler = pipeline.get(HttpChannelInitializer.IDLE_CHANNEL_TIMEOUT_HANDLER_NAME);
        if (idleChannelTimeoutHandler != null)
            pipeline.remove(idleChannelTimeoutHandler);
        // last chunk when the timeout hits.
        if (incompleteHttpCallTimeoutMillis > 0 && !(msg instanceof LastHttpContent)) {
            IncompleteHttpCallTimeoutHandler newHandler = new IncompleteHttpCallTimeoutHandler(incompleteHttpCallTimeoutMillis);
            ChannelHandler existingHandler = pipeline.get(INCOMPLETE_HTTP_CALL_TIMEOUT_HANDLER_NAME);
            if (existingHandler == null) {
                pipeline.addFirst(INCOMPLETE_HTTP_CALL_TIMEOUT_HANDLER_NAME, newHandler);
            } else {
                logger.error("Handling HttpRequest for new request and found an IncompleteHttpCallTimeoutHandler " + "already in the pipeline. This should not be possible. A new " + "IncompleteHttpCallTimeoutHandler will replace the old one. worker_channel_id={}", ctx.channel().toString());
                pipeline.replace(existingHandler, INCOMPLETE_HTTP_CALL_TIMEOUT_HANDLER_NAME, newHandler);
            }
        }
        ProxyRouterProcessingState proxyRouterProcessingState = ChannelAttributes.getProxyRouterProcessingStateForChannel(ctx).get();
        // Set the DistributedTracingConfig on the ProxyRouterProcessingState.
        // noinspection deprecation - This is the only place that should actually be calling this method.
        proxyRouterProcessingState.setDistributedTracingConfig(distributedTracingConfig);
    } else if (msg instanceof LastHttpContent) {
        // The HTTP call is complete, so we can remove the IncompleteHttpCallTimeoutHandler.
        ChannelPipeline pipeline = ctx.pipeline();
        ChannelHandler existingHandler = pipeline.get(INCOMPLETE_HTTP_CALL_TIMEOUT_HANDLER_NAME);
        if (existingHandler != null)
            pipeline.remove(INCOMPLETE_HTTP_CALL_TIMEOUT_HANDLER_NAME);
    }
    // Continue on the pipeline processing.
    super.channelRead(ctx, msg);
}
Also used : HttpRequest(io.netty.handler.codec.http.HttpRequest) HttpProcessingState(com.nike.riposte.server.http.HttpProcessingState) ProxyRouterProcessingState(com.nike.riposte.server.http.ProxyRouterProcessingState) ChannelHandler(io.netty.channel.ChannelHandler) LastHttpContent(io.netty.handler.codec.http.LastHttpContent) ChannelPipeline(io.netty.channel.ChannelPipeline) AttributeKey(io.netty.util.AttributeKey) HttpProcessingState(com.nike.riposte.server.http.HttpProcessingState) ProcessingState(com.nike.riposte.server.http.ProcessingState) ProxyRouterProcessingState(com.nike.riposte.server.http.ProxyRouterProcessingState)

Example 54 with LastHttpContent

use of io.netty.handler.codec.http.LastHttpContent in project riposte by Nike-Inc.

the class SmartHttpContentCompressor method write.

@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
    HttpProcessingState state = ChannelAttributes.getHttpProcessingStateForChannel(ctx).get();
    allowCompressionForThisRequest = false;
    if (state != null) {
        // We only want to allow compression if the endpoint being hit is *not* a ProxyRouterEndpoint, the response is full, and the response size
        // is greater than the threshold
        boolean isFull = msg instanceof HttpResponse && msg instanceof LastHttpContent;
        boolean endpointAllowed = endpointAllowsCompression(state.getEndpointForExecution());
        boolean responseInfoAllowed = state.getResponseInfo() == null || !state.getResponseInfo().isPreventCompressedOutput();
        if (isFull && endpointAllowed && responseInfoAllowed && ((LastHttpContent) msg).content().readableBytes() > responseSizeThresholdBytes) {
            allowCompressionForThisRequest = true;
        }
    }
    super.write(ctx, msg, promise);
}
Also used : HttpProcessingState(com.nike.riposte.server.http.HttpProcessingState) HttpResponse(io.netty.handler.codec.http.HttpResponse) LastHttpContent(io.netty.handler.codec.http.LastHttpContent)

Example 55 with LastHttpContent

use of io.netty.handler.codec.http.LastHttpContent in project cxf by apache.

the class NettyHttpClientHandler method channelRead.

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    if (msg instanceof HttpObject) {
        if (msg instanceof HttpResponse) {
            // just make sure we can combine the request and response together
            HttpResponse response = (HttpResponse) msg;
            NettyHttpClientRequest request = sendedQueue.poll();
            request.setResponse(response);
            // calling the callback here
            request.getCxfResponseCallback().responseReceived(response);
        }
        if (msg instanceof LastHttpContent) {
            ctx.close();
        }
    } else {
        super.channelRead(ctx, msg);
    }
}
Also used : HttpObject(io.netty.handler.codec.http.HttpObject) HttpResponse(io.netty.handler.codec.http.HttpResponse) LastHttpContent(io.netty.handler.codec.http.LastHttpContent)

Aggregations

LastHttpContent (io.netty.handler.codec.http.LastHttpContent)137 DefaultLastHttpContent (io.netty.handler.codec.http.DefaultLastHttpContent)63 HttpContent (io.netty.handler.codec.http.HttpContent)55 ByteBuf (io.netty.buffer.ByteBuf)49 EmbeddedChannel (io.netty.channel.embedded.EmbeddedChannel)43 HttpResponse (io.netty.handler.codec.http.HttpResponse)42 HttpRequest (io.netty.handler.codec.http.HttpRequest)34 Test (org.junit.Test)27 Test (org.junit.jupiter.api.Test)24 DefaultHttpContent (io.netty.handler.codec.http.DefaultHttpContent)23 HttpHeaders (io.netty.handler.codec.http.HttpHeaders)20 FullHttpResponse (io.netty.handler.codec.http.FullHttpResponse)18 DefaultFullHttpResponse (io.netty.handler.codec.http.DefaultFullHttpResponse)13 ChannelFuture (io.netty.channel.ChannelFuture)11 FullHttpRequest (io.netty.handler.codec.http.FullHttpRequest)10 HttpObject (io.netty.handler.codec.http.HttpObject)10 JsonObjectDecoder (io.netty.handler.codec.json.JsonObjectDecoder)10 IOException (java.io.IOException)10 HttpProcessingState (com.nike.riposte.server.http.HttpProcessingState)9 DefaultFullHttpRequest (io.netty.handler.codec.http.DefaultFullHttpRequest)9