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();
}
}
}
}
});
}
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;
}
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);
}
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);
}
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);
}
}
Aggregations