Search in sources :

Example 1 with RequestAndResponseFilter

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

the class RequestFilterHandler method doChannelRead.

@Override
public PipelineContinuationBehavior doChannelRead(ChannelHandlerContext ctx, Object msg) {
    if (msg instanceof HttpRequest) {
        HttpProcessingState state = ChannelAttributes.getHttpProcessingStateForChannel(ctx).get();
        handlerUtils.createRequestInfoFromNettyHttpRequestAndHandleStateSetupIfNecessary((HttpRequest) msg, state);
        // If the Netty HttpRequest is invalid, we shouldn't process any of the filters.
        handlerUtils.throwExceptionIfNotSuccessfullyDecoded((HttpRequest) msg);
        // The HttpRequest is valid, so process the filters.
        BiFunction<RequestAndResponseFilter, RequestInfo, RequestInfo> normalFilterCall = (filter, request) -> filter.filterRequestFirstChunkNoPayload(request, ctx);
        BiFunction<RequestAndResponseFilter, RequestInfo, Pair<RequestInfo, Optional<ResponseInfo<?>>>> shortCircuitFilterCall = (filter, request) -> filter.filterRequestFirstChunkWithOptionalShortCircuitResponse(request, ctx);
        return handleFilterLogic(ctx, msg, state, normalFilterCall, shortCircuitFilterCall);
    }
    if (msg instanceof LastHttpContent) {
        HttpProcessingState state = ChannelAttributes.getHttpProcessingStateForChannel(ctx).get();
        BiFunction<RequestAndResponseFilter, RequestInfo, RequestInfo> normalFilterCall = (filter, request) -> filter.filterRequestLastChunkWithFullPayload(request, ctx);
        BiFunction<RequestAndResponseFilter, RequestInfo, Pair<RequestInfo, Optional<ResponseInfo<?>>>> shortCircuitFilterCall = (filter, request) -> filter.filterRequestLastChunkWithOptionalShortCircuitResponse(request, ctx);
        return handleFilterLogic(ctx, msg, state, normalFilterCall, shortCircuitFilterCall);
    }
    // Not the first or last chunk. No filters were executed, so continue normally.
    return PipelineContinuationBehavior.CONTINUE;
}
Also used : HttpRequest(io.netty.handler.codec.http.HttpRequest) HttpProcessingState(com.nike.riposte.server.http.HttpProcessingState) RequestInfo(com.nike.riposte.server.http.RequestInfo) Logger(org.slf4j.Logger) HttpRequest(io.netty.handler.codec.http.HttpRequest) RequestAndResponseFilter(com.nike.riposte.server.http.filter.RequestAndResponseFilter) BiFunction(java.util.function.BiFunction) LoggerFactory(org.slf4j.LoggerFactory) ResponseInfo(com.nike.riposte.server.http.ResponseInfo) PipelineContinuationBehavior(com.nike.riposte.server.handler.base.PipelineContinuationBehavior) LastHttpContent(io.netty.handler.codec.http.LastHttpContent) BaseInboundHandlerWithTracingAndMdcSupport(com.nike.riposte.server.handler.base.BaseInboundHandlerWithTracingAndMdcSupport) ChannelHandlerContext(io.netty.channel.ChannelHandlerContext) List(java.util.List) ChannelAttributes(com.nike.riposte.server.channelpipeline.ChannelAttributes) LastOutboundMessageSendFullResponseInfo(com.nike.riposte.server.channelpipeline.message.LastOutboundMessageSendFullResponseInfo) Optional(java.util.Optional) ChannelHandler(io.netty.channel.ChannelHandler) Pair(com.nike.internal.util.Pair) Collections(java.util.Collections) ResponseInfo(com.nike.riposte.server.http.ResponseInfo) LastOutboundMessageSendFullResponseInfo(com.nike.riposte.server.channelpipeline.message.LastOutboundMessageSendFullResponseInfo) RequestAndResponseFilter(com.nike.riposte.server.http.filter.RequestAndResponseFilter) HttpProcessingState(com.nike.riposte.server.http.HttpProcessingState) RequestInfo(com.nike.riposte.server.http.RequestInfo) LastHttpContent(io.netty.handler.codec.http.LastHttpContent) Pair(com.nike.internal.util.Pair)

Example 2 with RequestAndResponseFilter

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

the class ResponseFilterHandler method executeResponseFilters.

protected void executeResponseFilters(ChannelHandlerContext ctx) {
    try {
        HttpProcessingState state = ChannelAttributes.getHttpProcessingStateForChannel(ctx).get();
        // (for example).
        if (state.isResponseSendingStarted())
            return;
        // RequestHasBeenHandledVerificationHandler should have made sure that state.getResponseInfo() is not null,
        // and ExceptionHandlingHandler should have made sure that state.getRequestInfo() is not null
        // (even if no exception has occurred).
        ResponseInfo<?> currentResponseInfo = state.getResponseInfo();
        for (RequestAndResponseFilter filter : filtersInResponseProcessingOrder) {
            try {
                currentResponseInfo = responseInfoUpdateNoNulls(filter, currentResponseInfo, filter.filterResponse(currentResponseInfo, state.getRequestInfo(), ctx));
            } 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);
            }
        }
        // Set the ResponseInfo on our HttpPrcessingState, but propagate any error already set on the state -
        // we don't want to override the originating error simply because the filter wants to adjust the
        // response.
        state.setResponseInfo(currentResponseInfo, state.getErrorThatTriggeredThisResponse());
    } catch (Throwable ex) {
        logger.error("An error occurred while setting up to process response filters. This error will be ignored and the " + "pipeline will continue normally without any filtering having occurred, however this error should be " + "fixed (it should be impossible to reach here).", ex);
    }
}
Also used : RequestAndResponseFilter(com.nike.riposte.server.http.filter.RequestAndResponseFilter) HttpProcessingState(com.nike.riposte.server.http.HttpProcessingState)

Example 3 with RequestAndResponseFilter

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

the class RequestFilterHandlerTest method doChannelRead_delegates_to_handleFilterLogic_with_first_chunk_method_references_when_msg_is_HttpRequest.

@DataProvider(value = { "CONTINUE", "DO_NOT_FIRE_CONTINUE_EVENT" }, splitBy = "\\|")
@Test
public void doChannelRead_delegates_to_handleFilterLogic_with_first_chunk_method_references_when_msg_is_HttpRequest(PipelineContinuationBehavior expectedPipelineContinuationBehavior) throws Exception {
    // given
    doReturn(expectedPipelineContinuationBehavior).when(handlerSpy).handleFilterLogic(any(), any(), any(), any(), any());
    // when
    PipelineContinuationBehavior result = handlerSpy.doChannelRead(ctxMock, firstChunkMsgMock);
    // then
    assertThat(result).isEqualTo(expectedPipelineContinuationBehavior);
    ArgumentCaptor<BiFunction> normalFilterCallCaptor = ArgumentCaptor.forClass(BiFunction.class);
    ArgumentCaptor<BiFunction> shortCircuitFilterCallCaptor = ArgumentCaptor.forClass(BiFunction.class);
    verify(handlerSpy).handleFilterLogic(eq(ctxMock), eq(firstChunkMsgMock), eq(state), normalFilterCallCaptor.capture(), shortCircuitFilterCallCaptor.capture());
    BiFunction<RequestAndResponseFilter, RequestInfo, RequestInfo> normalFilterCall = normalFilterCallCaptor.getValue();
    BiFunction<RequestAndResponseFilter, RequestInfo, Pair<RequestInfo, Optional<ResponseInfo<?>>>> shortCircuitFilterCall = shortCircuitFilterCallCaptor.getValue();
    RequestAndResponseFilter filterForNormalCallMock = mock(RequestAndResponseFilter.class);
    normalFilterCall.apply(filterForNormalCallMock, requestInfoMock);
    verify(filterForNormalCallMock).filterRequestFirstChunkNoPayload(requestInfoMock, ctxMock);
    RequestAndResponseFilter filterForShortCircuitCallMock = mock(RequestAndResponseFilter.class);
    shortCircuitFilterCall.apply(filterForShortCircuitCallMock, requestInfoMock);
    verify(filterForShortCircuitCallMock).filterRequestFirstChunkWithOptionalShortCircuitResponse(requestInfoMock, ctxMock);
}
Also used : ResponseInfo(com.nike.riposte.server.http.ResponseInfo) LastOutboundMessageSendFullResponseInfo(com.nike.riposte.server.channelpipeline.message.LastOutboundMessageSendFullResponseInfo) PipelineContinuationBehavior(com.nike.riposte.server.handler.base.PipelineContinuationBehavior) BiFunction(java.util.function.BiFunction) RequestAndResponseFilter(com.nike.riposte.server.http.filter.RequestAndResponseFilter) RequestInfo(com.nike.riposte.server.http.RequestInfo) Pair(com.nike.internal.util.Pair) DataProvider(com.tngtech.java.junit.dataprovider.DataProvider) Test(org.junit.Test)

Example 4 with RequestAndResponseFilter

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

the class RequestFilterHandlerTest method doChannelRead_delegates_to_handleFilterLogic_with_last_chunk_method_references_when_msg_is_LastHttpContent.

@DataProvider(value = { "CONTINUE", "DO_NOT_FIRE_CONTINUE_EVENT" }, splitBy = "\\|")
@Test
public void doChannelRead_delegates_to_handleFilterLogic_with_last_chunk_method_references_when_msg_is_LastHttpContent(PipelineContinuationBehavior expectedPipelineContinuationBehavior) throws Exception {
    // given
    doReturn(expectedPipelineContinuationBehavior).when(handlerSpy).handleFilterLogic(any(), any(), any(), any(), any());
    // when
    PipelineContinuationBehavior result = handlerSpy.doChannelRead(ctxMock, lastChunkMsgMock);
    // then
    assertThat(result).isEqualTo(expectedPipelineContinuationBehavior);
    ArgumentCaptor<BiFunction> normalFilterCallCaptor = ArgumentCaptor.forClass(BiFunction.class);
    ArgumentCaptor<BiFunction> shortCircuitFilterCallCaptor = ArgumentCaptor.forClass(BiFunction.class);
    verify(handlerSpy).handleFilterLogic(eq(ctxMock), eq(lastChunkMsgMock), eq(state), normalFilterCallCaptor.capture(), shortCircuitFilterCallCaptor.capture());
    BiFunction<RequestAndResponseFilter, RequestInfo, RequestInfo> normalFilterCall = normalFilterCallCaptor.getValue();
    BiFunction<RequestAndResponseFilter, RequestInfo, Pair<RequestInfo, Optional<ResponseInfo<?>>>> shortCircuitFilterCall = shortCircuitFilterCallCaptor.getValue();
    RequestAndResponseFilter filterForNormalCallMock = mock(RequestAndResponseFilter.class);
    normalFilterCall.apply(filterForNormalCallMock, requestInfoMock);
    verify(filterForNormalCallMock).filterRequestLastChunkWithFullPayload(requestInfoMock, ctxMock);
    RequestAndResponseFilter filterForShortCircuitCallMock = mock(RequestAndResponseFilter.class);
    shortCircuitFilterCall.apply(filterForShortCircuitCallMock, requestInfoMock);
    verify(filterForShortCircuitCallMock).filterRequestLastChunkWithOptionalShortCircuitResponse(requestInfoMock, ctxMock);
}
Also used : ResponseInfo(com.nike.riposte.server.http.ResponseInfo) LastOutboundMessageSendFullResponseInfo(com.nike.riposte.server.channelpipeline.message.LastOutboundMessageSendFullResponseInfo) PipelineContinuationBehavior(com.nike.riposte.server.handler.base.PipelineContinuationBehavior) BiFunction(java.util.function.BiFunction) RequestAndResponseFilter(com.nike.riposte.server.http.filter.RequestAndResponseFilter) RequestInfo(com.nike.riposte.server.http.RequestInfo) Pair(com.nike.internal.util.Pair) DataProvider(com.tngtech.java.junit.dataprovider.DataProvider) Test(org.junit.Test)

Example 5 with RequestAndResponseFilter

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

the class RequestFilterHandlerTest method handleFilterLogic_short_circuits_as_expected_if_filter_returns_valid_response.

@DataProvider(value = { "true   |   0   |   true", "true   |   0   |   false", "true   |   1   |   true", "true   |   1   |   false", "false  |   0   |   true", "false  |   0   |   false", "false  |   1   |   true", "false  |   1   |   false" }, splitBy = "\\|")
@Test
public void handleFilterLogic_short_circuits_as_expected_if_filter_returns_valid_response(boolean isFirstChunk, int shortCircuitingFilterIndex, boolean filterReturnsModifiedRequestInfo) {
    // given
    HandleFilterLogicMethodCallArgs args = new HandleFilterLogicMethodCallArgs(isFirstChunk);
    RequestAndResponseFilter shortCircuitingFilter = filtersList.get(shortCircuitingFilterIndex);
    doReturn(true).when(shortCircuitingFilter).isShortCircuitRequestFilter();
    RequestInfo<?> modifiedRequestInfoMock = mock(RequestInfo.class);
    RequestInfo<?> returnedRequestInfo = (filterReturnsModifiedRequestInfo) ? modifiedRequestInfoMock : null;
    ResponseInfo<?> returnedResponseInfoMock = mock(ResponseInfo.class);
    doReturn(Pair.of(returnedRequestInfo, Optional.of(returnedResponseInfoMock))).when(shortCircuitingFilter).filterRequestFirstChunkWithOptionalShortCircuitResponse(any(), any());
    doReturn(Pair.of(returnedRequestInfo, Optional.of(returnedResponseInfoMock))).when(shortCircuitingFilter).filterRequestLastChunkWithOptionalShortCircuitResponse(any(), any());
    // when
    PipelineContinuationBehavior result = handlerSpy.handleFilterLogic(ctxMock, args.msg, args.httpState, args.normalFilterCall, args.shortCircuitFilterCall);
    // then
    // Pipeline stops for the given msg event.
    assertThat(result).isEqualTo(DO_NOT_FIRE_CONTINUE_EVENT);
    // The filter's short-circuit-capable method was called.
    if (isFirstChunk)
        verify(shortCircuitingFilter).filterRequestFirstChunkWithOptionalShortCircuitResponse(requestInfoMock, ctxMock);
    else
        verify(shortCircuitingFilter).filterRequestLastChunkWithOptionalShortCircuitResponse(requestInfoMock, ctxMock);
    // The state is updated with the correct RequestInfo depending on what the filter returned.
    if (filterReturnsModifiedRequestInfo)
        assertThat(state.getRequestInfo()).isSameAs(modifiedRequestInfoMock);
    else
        assertThat(state.getRequestInfo()).isSameAs(requestInfoMock);
    // The state is updated with the ResponseInfo returned by the filter.
    assertThat(state.getResponseInfo()).isSameAs(returnedResponseInfoMock);
    // The short circuiting "we're all done, return the response to the caller" event is fired down the pipeline.
    verify(ctxMock).fireChannelRead(LastOutboundMessageSendFullResponseInfo.INSTANCE);
}
Also used : PipelineContinuationBehavior(com.nike.riposte.server.handler.base.PipelineContinuationBehavior) RequestAndResponseFilter(com.nike.riposte.server.http.filter.RequestAndResponseFilter) DataProvider(com.tngtech.java.junit.dataprovider.DataProvider) Test(org.junit.Test)

Aggregations

RequestAndResponseFilter (com.nike.riposte.server.http.filter.RequestAndResponseFilter)14 Test (org.junit.Test)9 RequestFilterHandler (com.nike.riposte.server.handler.RequestFilterHandler)5 PipelineContinuationBehavior (com.nike.riposte.server.handler.base.PipelineContinuationBehavior)5 RequestInfo (com.nike.riposte.server.http.RequestInfo)5 ResponseFilterHandler (com.nike.riposte.server.handler.ResponseFilterHandler)4 DataProvider (com.tngtech.java.junit.dataprovider.DataProvider)4 Pair (com.nike.internal.util.Pair)3 LastOutboundMessageSendFullResponseInfo (com.nike.riposte.server.channelpipeline.message.LastOutboundMessageSendFullResponseInfo)3 RiposteErrorHandler (com.nike.riposte.server.error.handler.RiposteErrorHandler)3 RiposteUnhandledErrorHandler (com.nike.riposte.server.error.handler.RiposteUnhandledErrorHandler)3 HttpProcessingState (com.nike.riposte.server.http.HttpProcessingState)3 ResponseInfo (com.nike.riposte.server.http.ResponseInfo)3 ResponseSender (com.nike.riposte.server.http.ResponseSender)3 BiFunction (java.util.function.BiFunction)3 DistributedTracingConfig (com.nike.riposte.server.config.distributedtracing.DistributedTracingConfig)2 RequestValidator (com.nike.riposte.server.error.validation.RequestValidator)2 AccessLogStartHandler (com.nike.riposte.server.handler.AccessLogStartHandler)2 RequestContentDeserializerHandler (com.nike.riposte.server.handler.RequestContentDeserializerHandler)2 RoutingHandler (com.nike.riposte.server.handler.RoutingHandler)2