Search in sources :

Example 46 with HttpProcessingState

use of com.nike.riposte.server.http.HttpProcessingState in project riposte by Nike-Inc.

the class RequestContentDeserializerHandler 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 reqInfo = state.getRequestInfo();
        // Don't bother trying to deserialize until we have an endpoint and the request content has fully arrived
        if (endpoint != null && reqInfo.isCompleteRequestWithAllChunks()) {
            // Setup the content deserializer if desired
            TypeReference<?> contentTypeRef = endpoint.requestContentType();
            if (contentTypeRef != null) {
                // A non-null TypeReference is available, so deserialization is possible. Retrieve the appropriate
                //      deserializer and setup the RequestInfo so that it can lazily deserialize when requested.
                ObjectMapper deserializer = endpoint.customRequestContentDeserializer(reqInfo);
                if (deserializer == null)
                    deserializer = defaultRequestContentDeserializer;
                //noinspection unchecked
                reqInfo.setupContentDeserializer(deserializer, contentTypeRef);
            }
        }
    }
    return PipelineContinuationBehavior.CONTINUE;
}
Also used : HttpProcessingState(com.nike.riposte.server.http.HttpProcessingState) LastHttpContent(io.netty.handler.codec.http.LastHttpContent) RequestInfo(com.nike.riposte.server.http.RequestInfo) ObjectMapper(com.fasterxml.jackson.databind.ObjectMapper)

Example 47 with HttpProcessingState

use of com.nike.riposte.server.http.HttpProcessingState in project riposte by Nike-Inc.

the class RequestFilterHandler method handleFilterLogic.

protected PipelineContinuationBehavior handleFilterLogic(ChannelHandlerContext ctx, Object msg, BiFunction<RequestAndResponseFilter, RequestInfo, RequestInfo> normalFilterCall, BiFunction<RequestAndResponseFilter, RequestInfo, Pair<RequestInfo, Optional<ResponseInfo<?>>>> shortCircuitFilterCall) {
    HttpProcessingState state = ChannelAttributes.getHttpProcessingStateForChannel(ctx).get();
    RequestInfo<?> currentReqInfo = state.getRequestInfo();
    // Run through each filter.
    for (RequestAndResponseFilter filter : filters) {
        try {
            // See if we're supposed to do short circuit call or not
            if (filter.isShortCircuitRequestFilter()) {
                Pair<RequestInfo, Optional<ResponseInfo<?>>> result = shortCircuitFilterCall.apply(filter, currentReqInfo);
                if (result != null) {
                    currentReqInfo = requestInfoUpdateNoNulls(currentReqInfo, result.getLeft());
                    // See if we need to short circuit.
                    ResponseInfo<?> responseInfo = (result.getRight() == null) ? null : result.getRight().orElse(null);
                    if (responseInfo != null) {
                        //      full, not chunked.
                        if (responseInfo.isChunkedResponse()) {
                            throw new IllegalStateException("RequestAndResponseFilter should never return a " + "chunked ResponseInfo when short circuiting.");
                        }
                        state.setRequestInfo(currentReqInfo);
                        state.setResponseInfo(responseInfo);
                        // Fire the short-circuit event that will get the desired response info sent to the caller.
                        ctx.fireChannelRead(LastOutboundMessageSendFullResponseInfo.INSTANCE);
                        // Tell this event to stop where it is.
                        return PipelineContinuationBehavior.DO_NOT_FIRE_CONTINUE_EVENT;
                    }
                }
            } else {
                currentReqInfo = requestInfoUpdateNoNulls(currentReqInfo, normalFilterCall.apply(filter, currentReqInfo));
            }
        } catch (Throwable ex) {
            logger.error("An error occurred while processing a request filter. This error will be ignored and the " + "filtering/processing will continue normally, however this error should be fixed (filters should " + "never throw errors). filter_class={}", filter.getClass().getName(), ex);
        }
    }
    // All the filters have been processed, so set the state to whatever the current request info says.
    state.setRequestInfo(currentReqInfo);
    // No short circuit if we reach here, so continue normally.
    return PipelineContinuationBehavior.CONTINUE;
}
Also used : Optional(java.util.Optional) RequestAndResponseFilter(com.nike.riposte.server.http.filter.RequestAndResponseFilter) HttpProcessingState(com.nike.riposte.server.http.HttpProcessingState) RequestInfo(com.nike.riposte.server.http.RequestInfo)

Example 48 with HttpProcessingState

use of com.nike.riposte.server.http.HttpProcessingState in project riposte by Nike-Inc.

the class RequestInfoSetterHandler method doChannelRead.

@Override
public PipelineContinuationBehavior doChannelRead(ChannelHandlerContext ctx, Object msg) {
    try {
        HttpProcessingState state = ChannelAttributes.getHttpProcessingStateForChannel(ctx).get();
        if (state == null || state.isResponseSendingLastChunkSent()) {
            if (state == null)
                logger.error("HttpProcessingState is null for this request. This should not be possible.");
            //      anything further.
            return PipelineContinuationBehavior.DO_NOT_FIRE_CONTINUE_EVENT;
        }
        // We have a HttpProcessingState. Process the message and continue the pipeline processing.
        if (msg instanceof HttpRequest) {
            throwExceptionIfNotSuccessfullyDecoded((HttpRequest) msg);
            RequestInfo<?> requestInfo = new RequestInfoImpl<>((HttpRequest) msg);
            state.setRequestInfo(requestInfo);
        } else if (msg instanceof HttpContent) {
            HttpContent httpContentMsg = (HttpContent) msg;
            throwExceptionIfNotSuccessfullyDecoded(httpContentMsg);
            RequestInfo<?> requestInfo = state.getRequestInfo();
            if (requestInfo == null) {
                throw new IllegalStateException("Found a HttpContent msg without a RequestInfo stored in the HttpProcessingState. " + "This should be impossible");
            }
            int currentRequestLengthInBytes = requestInfo.addContentChunk(httpContentMsg);
            int configuredMaxRequestSize = getConfiguredMaxRequestSize(state.getEndpointForExecution(), globalConfiguredMaxRequestSizeInBytes);
            if (!isMaxRequestSizeValidationDisabled(configuredMaxRequestSize) && currentRequestLengthInBytes > configuredMaxRequestSize) {
                throw new TooLongFrameException("Request raw content length exceeded configured max request size of " + configuredMaxRequestSize);
            }
        }
        return PipelineContinuationBehavior.CONTINUE;
    } finally {
        // For HttpContent messages, either requestInfo.addContentChunk() has been called and the reference count
        //      increased (i.e. the RequestInfo is now responsible for releasing the content when
        //      requestInfo.releaseAllResources() is called), or an exception has been thrown. In any case, we
        //      are done with any message from a pipeline perspective and can reduce its reference count.
        ReferenceCountUtil.release(msg);
    }
}
Also used : HttpRequest(io.netty.handler.codec.http.HttpRequest) TooLongFrameException(io.netty.handler.codec.TooLongFrameException) HttpProcessingState(com.nike.riposte.server.http.HttpProcessingState) RequestInfoImpl(com.nike.riposte.server.http.impl.RequestInfoImpl) RequestInfo(com.nike.riposte.server.http.RequestInfo) HttpContent(io.netty.handler.codec.http.HttpContent)

Example 49 with HttpProcessingState

use of com.nike.riposte.server.http.HttpProcessingState in project riposte by Nike-Inc.

the class ExceptionHandlingHandler method doExceptionCaught.

@Override
public PipelineContinuationBehavior doExceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
    // We expect to end up here when handlers previously in the pipeline throw an error, so do the normal
    //      processError call.
    HttpProcessingState state = getStateAndCreateIfNeeded(ctx, cause);
    if (state.isResponseSendingStarted()) {
        logger.info("A response has already been started. Ignoring this exception since it's secondary. NOTE: This often " + "occurs when an error happens repeatedly on multiple chunks of a request or response - only the " + "first one is processed into the error sent to the user. The original error is probably higher up in " + "the logs. ignored_secondary_exception=\"{}\"", cause.toString());
        return PipelineContinuationBehavior.DO_NOT_FIRE_CONTINUE_EVENT;
    } else {
        ResponseInfo<ErrorResponseBody> responseInfo = processError(state, null, cause);
        if (shouldForceConnectionCloseAfterResponseSent(cause))
            responseInfo.setForceConnectionCloseAfterResponseSent(true);
        state.setResponseInfo(responseInfo);
    }
    return PipelineContinuationBehavior.CONTINUE;
}
Also used : HttpProcessingState(com.nike.riposte.server.http.HttpProcessingState) ErrorResponseBody(com.nike.riposte.server.error.handler.ErrorResponseBody)

Example 50 with HttpProcessingState

use of com.nike.riposte.server.http.HttpProcessingState in project riposte by Nike-Inc.

the class ResponseSenderHandler method sendResponse.

protected void sendResponse(ChannelHandlerContext ctx, Object msg) throws JsonProcessingException {
    try {
        HttpProcessingState state = ChannelAttributes.getHttpProcessingStateForChannel(ctx).get();
        if (state.isResponseSendingLastChunkSent()) {
            if (logger.isDebugEnabled()) {
                runnableWithTracingAndMdc(() -> logger.debug("A response has already been sent. " + "Ignoring this method call to send response."), ctx).run();
            }
            return;
        }
        RequestInfo<?> requestInfo = state.getRequestInfo();
        if (requestInfo == null)
            requestInfo = RequestInfoImpl.dummyInstanceForUnknownRequests();
        ResponseInfo<?> responseInfo = state.getResponseInfo();
        Endpoint<?> endpointExecuted = state.getEndpointForExecution();
        ObjectMapper customSerializer = (endpointExecuted == null) ? null : endpointExecuted.customResponseContentSerializer(requestInfo);
        if (msg != null && msg instanceof ChunkedOutboundMessage) {
            // Chunked message. Stream it out.
            responseSender.sendResponseChunk(ctx, requestInfo, responseInfo, (ChunkedOutboundMessage) msg);
        } else {
            // Full message. Send it.
            if (containsErrorResponseBody(responseInfo)) {
                //noinspection unchecked
                responseSender.sendErrorResponse(ctx, requestInfo, (ResponseInfo<ErrorResponseBody>) responseInfo);
            } else
                responseSender.sendFullResponse(ctx, requestInfo, responseInfo, customSerializer);
        }
    } catch (Throwable t) {
        runnableWithTracingAndMdc(() -> logger.error("An unexpected error occurred while attempting to send a response.", t), ctx).run();
        throw t;
    }
}
Also used : HttpProcessingState(com.nike.riposte.server.http.HttpProcessingState) ErrorResponseBody(com.nike.riposte.server.error.handler.ErrorResponseBody) ChunkedOutboundMessage(com.nike.riposte.server.channelpipeline.message.ChunkedOutboundMessage) ObjectMapper(com.fasterxml.jackson.databind.ObjectMapper)

Aggregations

HttpProcessingState (com.nike.riposte.server.http.HttpProcessingState)54 ChannelHandlerContext (io.netty.channel.ChannelHandlerContext)22 Before (org.junit.Before)20 Channel (io.netty.channel.Channel)19 Attribute (io.netty.util.Attribute)19 RequestInfo (com.nike.riposte.server.http.RequestInfo)14 ResponseInfo (com.nike.riposte.server.http.ResponseInfo)11 Test (org.junit.Test)9 JsonProcessingException (com.fasterxml.jackson.core.JsonProcessingException)8 ErrorResponseBody (com.nike.riposte.server.error.handler.ErrorResponseBody)8 Endpoint (com.nike.riposte.server.http.Endpoint)6 ProxyRouterProcessingState (com.nike.riposte.server.http.ProxyRouterProcessingState)6 Span (com.nike.wingtips.Span)5 ChannelFuture (io.netty.channel.ChannelFuture)5 LastHttpContent (io.netty.handler.codec.http.LastHttpContent)5 LastOutboundMessageSendFullResponseInfo (com.nike.riposte.server.channelpipeline.message.LastOutboundMessageSendFullResponseInfo)4 IncompleteHttpCallTimeoutException (com.nike.riposte.server.error.exception.IncompleteHttpCallTimeoutException)4 TooManyOpenChannelsException (com.nike.riposte.server.error.exception.TooManyOpenChannelsException)4 RequestAndResponseFilter (com.nike.riposte.server.http.filter.RequestAndResponseFilter)4 HttpRequest (io.netty.handler.codec.http.HttpRequest)4