handlerUtils.createRequestInfoFromNettyHttpRequestAndHandleStateSetupIfNecessary( (HttpRequest) msg, state ); handlerUtils.throwExceptionIfNotSuccessfullyDecoded((HttpRequest) msg); handlerUtils.throwExceptionIfNotSuccessfullyDecoded(httpContentMsg); RequestInfo<?> requestInfo = state.getRequestInfo(); if (requestInfo == null) {
void throwExceptionIfNotSuccessfullyDecoded(HttpObject httpObject) { Throwable decoderFailure = getDecoderFailure(httpObject); if (decoderFailure == null) { return; } throw new InvalidHttpRequestException( "Detected HttpObject that was not successfully decoded.", decoderFailure ); }
/** * Tries to extract the {@link RequestInfo} associated with the current request using the given arguments. First it * will try to get it from the given state. If that fails, it will try to create a new one based on the given msg * (which only works if the msg is a {@link HttpRequest}). If that also fails then a new dummy instance for an * unknown request will be created via {@link RequestInfoImpl#dummyInstanceForUnknownRequests()} and returned. */ RequestInfo<?> getRequestInfo(HttpProcessingState state, Object msg) { // Try to get the RequestInfo from the state variable first. RequestInfo requestInfo = state.getRequestInfo(); if (requestInfo != null) { return requestInfo; } // The state did not have a request info. See if we can build one from the msg. if (msg instanceof HttpRequest) { try { return handlerUtils.createRequestInfoFromNettyHttpRequestAndHandleStateSetupIfNecessary( (HttpRequest) msg, state ); } catch (Throwable t) { logger.error( "Unable to generate RequestInfo from HttpRequest. Defaulting to a synthetic RequestInfo.", t ); } } // Something major blew up if we reach here, so we just need to create a dummy RequestInfo for an unknown // request. requestInfo = RequestInfoImpl.dummyInstanceForUnknownRequests(); state.setRequestInfo(requestInfo); return requestInfo; }
@Override public PipelineContinuationBehavior doChannelRead(ChannelHandlerContext ctx, Object msg) { // We may get multiple messages for a single HTTP request since riposte handles each individual HTTP message // object (including individual payload content messages). // We only do the processing for HttpRequest which is the first message in a request chain. if (shouldHandleDoChannelReadMessage(msg)) { try { startTrace((HttpRequest) msg, ctx); } catch (Throwable t) { logger.error( "An unexpected error occurred while starting the distributed tracing overall request span. This " + "exception will be swallowed to avoid breaking the Netty pipeline, but it should be " + "investigated as it shouldn't ever happen.", t ); } } if (msg instanceof LastHttpContent) { HttpProcessingState httpProcessingState = ChannelAttributes.getHttpProcessingStateForChannel(ctx).get(); // Add the "we received the last bytes of the request on the wire" annotation to the span if possible // and desired. Span requestSpan = handlerUtils.getOverallRequestSpan(httpProcessingState); if (requestSpan != null && spanNamingAndTaggingStrategy.shouldAddWireReceiveFinishAnnotation()) { requestSpan.addTimestampedAnnotationForCurrentTime( spanNamingAndTaggingStrategy.wireReceiveFinishAnnotationName() ); } } return PipelineContinuationBehavior.CONTINUE; }
@DataProvider(value = { "true", "false" }) @Test public void throwExceptionIfNotSuccessfullyDecoded_works_as_expected( boolean decoderFailureExists ) { // given Throwable decoderFailureEx = new RuntimeException("intentional exception"); if (decoderFailureExists) { nettyRequest.setDecoderResult(DecoderResult.failure(decoderFailureEx)); } // when Throwable resultEx = catchThrowable(() -> implSpy.throwExceptionIfNotSuccessfullyDecoded(nettyRequest)); // then if (decoderFailureExists) { assertThat(resultEx) .isInstanceOf(InvalidHttpRequestException.class) .hasCause(decoderFailureEx); } else { assertThat(resultEx).isNull(); } }
@Before public void beforeMethod() { implSpy = spy(new RiposteHandlerInternalUtil()); stateSpy = spy(new HttpProcessingState()); nettyRequest = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.PATCH, "/some/uri"); resetTracingAndMdc(); }
/** * Tries to extract the {@link RequestInfo} associated with the current request using the given arguments. First it * will try to get it from the given state. If that fails, it will try to create a new one based on the given msg * (which only works if the msg is a {@link HttpRequest}). If that also fails then a new dummy instance for an * unknown request will be created via {@link RequestInfoImpl#dummyInstanceForUnknownRequests()} and returned. */ RequestInfo<?> getRequestInfo(HttpProcessingState state, Object msg) { // Try to get the RequestInfo from the state variable first. RequestInfo requestInfo = state.getRequestInfo(); if (requestInfo != null) { return requestInfo; } // The state did not have a request info. See if we can build one from the msg. if (msg instanceof HttpRequest) { try { return handlerUtils.createRequestInfoFromNettyHttpRequestAndHandleStateSetupIfNecessary( (HttpRequest) msg, state ); } catch (Throwable t) { logger.error( "Unable to generate RequestInfo from HttpRequest. Defaulting to a synthetic RequestInfo.", t ); } } // Something major blew up if we reach here, so we just need to create a dummy RequestInfo for an unknown // request. requestInfo = RequestInfoImpl.dummyInstanceForUnknownRequests(); state.setRequestInfo(requestInfo); return requestInfo; }
@Override public PipelineContinuationBehavior doChannelRead(ChannelHandlerContext ctx, Object msg) { // We may get multiple messages for a single HTTP request since riposte handles each individual HTTP message // object (including individual payload content messages). // We only do the processing for HttpRequest which is the first message in a request chain. if (shouldHandleDoChannelReadMessage(msg)) { try { startTrace((HttpRequest) msg, ctx); } catch (Throwable t) { logger.error( "An unexpected error occurred while starting the distributed tracing overall request span. This " + "exception will be swallowed to avoid breaking the Netty pipeline, but it should be " + "investigated as it shouldn't ever happen.", t ); } } if (msg instanceof LastHttpContent) { HttpProcessingState httpProcessingState = ChannelAttributes.getHttpProcessingStateForChannel(ctx).get(); // Add the "we received the last bytes of the request on the wire" annotation to the span if possible // and desired. Span requestSpan = handlerUtils.getOverallRequestSpan(httpProcessingState); if (requestSpan != null && spanNamingAndTaggingStrategy.shouldAddWireReceiveFinishAnnotation()) { requestSpan.addTimestampedAnnotationForCurrentTime( spanNamingAndTaggingStrategy.wireReceiveFinishAnnotationName() ); } } return PipelineContinuationBehavior.CONTINUE; }
handlerUtils.createRequestInfoFromNettyHttpRequestAndHandleStateSetupIfNecessary( (HttpRequest) msg, state ); handlerUtils.throwExceptionIfNotSuccessfullyDecoded((HttpRequest) msg); handlerUtils.throwExceptionIfNotSuccessfullyDecoded(httpContentMsg); RequestInfo<?> requestInfo = state.getRequestInfo(); if (requestInfo == null) {
? handlerUtils.createRequestInfoFromNettyHttpRequestAndHandleStateSetupIfNecessary( (HttpRequest) msg, httpProcessingState
void throwExceptionIfNotSuccessfullyDecoded(HttpObject httpObject) { Throwable decoderFailure = getDecoderFailure(httpObject); if (decoderFailure == null) { return; } throw new InvalidHttpRequestException( "Detected HttpObject that was not successfully decoded.", decoderFailure ); }
@DataProvider(value = { "true", "false" }) @Test public void getOverallRequestSpan_works_as_expected(boolean stateIsNull) { // given Span stateOverallRequestSpanMock = mock(Span.class); HttpProcessingState stateMock = (stateIsNull) ? null : mock(HttpProcessingState.class); if (!stateIsNull) { doReturn(stateOverallRequestSpanMock).when(stateMock).getOverallRequestSpan(); } // when Span result = implSpy.getOverallRequestSpan(stateMock); // then if (stateIsNull) { assertThat(result).isNull(); } else { assertThat(result).isSameAs(stateOverallRequestSpanMock); verify(stateMock).getOverallRequestSpan(); } } }
if (msg instanceof HttpRequest) { HttpProcessingState state = ChannelAttributes.getHttpProcessingStateForChannel(ctx).get(); handlerUtils.createRequestInfoFromNettyHttpRequestAndHandleStateSetupIfNecessary( (HttpRequest)msg, state handlerUtils.throwExceptionIfNotSuccessfullyDecoded((HttpRequest) msg);
? handlerUtils.createRequestInfoFromNettyHttpRequestAndHandleStateSetupIfNecessary( (HttpRequest) msg, httpProcessingState
@Test public void getDecoderFailure_returns_null_when_DecoderResult_is_null() { // given HttpObject httpObjectMock = mock(HttpObject.class); doReturn(null).when(httpObjectMock).decoderResult(); // when Throwable result = implSpy.getDecoderFailure(httpObjectMock); // then assertThat(result).isNull(); }
@Override public PipelineContinuationBehavior doChannelRead(ChannelHandlerContext ctx, Object msg) { if (msg instanceof HttpRequest) { HttpProcessingState state = ChannelAttributes.getHttpProcessingStateForChannel(ctx).get(); RequestInfo request = handlerUtils.createRequestInfoFromNettyHttpRequestAndHandleStateSetupIfNecessary( (HttpRequest)msg, state ); // If the Netty HttpRequest is invalid, we shouldn't do any endpoint routing. handlerUtils.throwExceptionIfNotSuccessfullyDecoded((HttpRequest) msg); // The HttpRequest is valid, so continue with the endpoint routing. Pair<Endpoint<?>, String> endpointForExecution = findSingleEndpointForExecution(request); request.setPathParamsBasedOnPathTemplate(endpointForExecution.getRight()); state.setEndpointForExecution(endpointForExecution.getLeft(), endpointForExecution.getRight()); throwExceptionIfContentLengthHeaderIsLargerThanConfiguredMaxRequestSize( (HttpRequest) msg, endpointForExecution.getLeft() ); } return PipelineContinuationBehavior.CONTINUE; }
@Test public void getRequestInfo_uses_dummy_instance_if_an_exception_occurs_while_creating_RequestInfo_from_HttpRequest_msg() { // given assertThat(state.getRequestInfo(), nullValue()); RiposteHandlerInternalUtil explodingHandlerUtilMock = mock(RiposteHandlerInternalUtil.class); doThrow(new RuntimeException("intentional exception")) .when(explodingHandlerUtilMock) .createRequestInfoFromNettyHttpRequestAndHandleStateSetupIfNecessary(any(), any()); Whitebox.setInternalState(handler, "handlerUtils", explodingHandlerUtilMock); HttpRequest httpRequest = new DefaultHttpRequest( HttpVersion.HTTP_1_1, HttpMethod.GET, "/some/uri" ); // when RequestInfo<?> result = handler.getRequestInfo(state, httpRequest); // then assertThat(result.getUri(), is(RequestInfo.NONE_OR_UNKNOWN_TAG)); verify(explodingHandlerUtilMock) .createRequestInfoFromNettyHttpRequestAndHandleStateSetupIfNecessary(httpRequest, state); }
@Test public void getDecoderFailure_returns_null_when_passed_null() { // expect assertThat(implSpy.getDecoderFailure(null)).isNull(); }
if (msg instanceof HttpRequest) { HttpProcessingState state = ChannelAttributes.getHttpProcessingStateForChannel(ctx).get(); handlerUtils.createRequestInfoFromNettyHttpRequestAndHandleStateSetupIfNecessary( (HttpRequest)msg, state handlerUtils.throwExceptionIfNotSuccessfullyDecoded((HttpRequest) msg);
@Test public void createRequestInfoFromNettyHttpRequestAndHandleStateSetupIfNecessary_uses_RequestInfo_from_state_if_it_already_exists() { // given RequestInfo<?> alreadyExistingRequestInfoMock = mock(RequestInfo.class); doReturn(alreadyExistingRequestInfoMock).when(stateSpy).getRequestInfo(); assertThat(stateSpy.getRequestInfo()).isSameAs(alreadyExistingRequestInfoMock); // when RequestInfo<?> result = implSpy.createRequestInfoFromNettyHttpRequestAndHandleStateSetupIfNecessary(nettyRequest, stateSpy); // then assertThat(result).isSameAs(alreadyExistingRequestInfoMock); assertThat(stateSpy.getRequestInfo()).isSameAs(alreadyExistingRequestInfoMock); verify(stateSpy, never()).setRequestInfo(any(RequestInfo.class)); }