use of io.netty.handler.codec.http.HttpContent in project async-http-client by AsyncHttpClient.
the class AsyncHttpClientHandler method channelRead.
@Override
public void channelRead(final ChannelHandlerContext ctx, Object msg) throws Exception {
Channel channel = ctx.channel();
Object attribute = Channels.getAttribute(channel);
try {
if (attribute instanceof OnLastHttpContentCallback && msg instanceof LastHttpContent) {
((OnLastHttpContentCallback) attribute).call();
} else if (attribute instanceof NettyResponseFuture) {
NettyResponseFuture<?> future = (NettyResponseFuture<?>) attribute;
future.touch();
handleRead(channel, future, msg);
} else if (attribute instanceof StreamedResponsePublisher) {
StreamedResponsePublisher publisher = (StreamedResponsePublisher) attribute;
publisher.future().touch();
if (msg instanceof HttpContent) {
ByteBuf content = ((HttpContent) msg).content();
// Republish as a HttpResponseBodyPart
if (content.isReadable()) {
HttpResponseBodyPart part = config.getResponseBodyPartFactory().newResponseBodyPart(content, false);
ctx.fireChannelRead(part);
}
if (msg instanceof LastHttpContent) {
// Remove the handler from the pipeline, this will trigger
// it to finish
ctx.pipeline().remove(publisher);
// Trigger a read, just in case the last read complete
// triggered no new read
ctx.read();
// Send the last content on to the protocol, so that it can
// conclude the cleanup
handleRead(channel, publisher.future(), msg);
}
} else {
logger.info("Received unexpected message while expecting a chunk: " + msg);
ctx.pipeline().remove(publisher);
Channels.setDiscard(channel);
}
} else if (attribute != DiscardEvent.DISCARD) {
// unhandled message
logger.debug("Orphan channel {} with attribute {} received message {}, closing", channel, attribute, msg);
Channels.silentlyCloseChannel(channel);
}
} finally {
ReferenceCountUtil.release(msg);
}
}
use of io.netty.handler.codec.http.HttpContent in project riposte by Nike-Inc.
the class ProxyRouterEndpointExecutionHandler method doChannelRead.
@Override
public PipelineContinuationBehavior doChannelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
HttpProcessingState state = ChannelAttributes.getHttpProcessingStateForChannel(ctx).get();
Endpoint<?> endpoint = state.getEndpointForExecution();
if (shouldHandleDoChannelReadMessage(msg, endpoint)) {
ProxyRouterProcessingState proxyRouterState = getOrCreateProxyRouterProcessingState(ctx);
ProxyRouterEndpoint endpointProxyRouter = ((ProxyRouterEndpoint) endpoint);
RequestInfo<?> requestInfo = state.getRequestInfo();
if (msg instanceof HttpRequest) {
if (requestInfo instanceof RiposteInternalRequestInfo) {
// Tell this RequestInfo that we'll be managing the release of content chunks, so that when
// RequestInfo.releaseAllResources() is called we don't have extra reference count removals.
((RiposteInternalRequestInfo) requestInfo).contentChunksWillBeReleasedExternally();
}
// We're supposed to start streaming. There may be pre-endpoint-execution validation logic or other work
// that needs to happen before the endpoint is executed, so set up the CompletableFuture for the
// endpoint call to only execute if the pre-endpoint-execution validation/work chain is successful.
CompletableFuture<DownstreamRequestFirstChunkInfo> firstChunkFuture = state.getPreEndpointExecutionWorkChain().thenCompose(functionWithTracingAndMdc(aVoid -> endpointProxyRouter.getDownstreamRequestFirstChunkInfo(requestInfo, longRunningTaskExecutor, ctx), ctx));
Long endpointTimeoutOverride = endpointProxyRouter.completableFutureTimeoutOverrideMillis();
long callTimeoutValueToUse = (endpointTimeoutOverride == null) ? defaultCompletableFutureTimeoutMillis : endpointTimeoutOverride;
// When the first chunk is ready, stream it downstream and set up what happens afterward.
firstChunkFuture.whenComplete((downstreamRequestFirstChunkInfo, throwable) -> {
Optional<ManualModeTask<HttpResponse>> circuitBreakerManualTask = getCircuitBreaker(downstreamRequestFirstChunkInfo, ctx).map(CircuitBreaker::newManualModeTask);
StreamingCallback callback = new StreamingCallbackForCtx(ctx, circuitBreakerManualTask, endpointProxyRouter, requestInfo, proxyRouterState);
if (throwable != null) {
// Something blew up trying to determine the first chunk info.
callback.unrecoverableErrorOccurred(throwable, true);
} else if (!ctx.channel().isOpen()) {
// The channel was closed for some reason before we were able to start streaming.
String errorMsg = "The channel from the original caller was closed before we could begin the " + "downstream call.";
Exception channelClosedException = new RuntimeException(errorMsg);
runnableWithTracingAndMdc(() -> logger.warn(errorMsg), ctx).run();
callback.unrecoverableErrorOccurred(channelClosedException, true);
} else {
try {
// Ok we have the first chunk info. Start by setting the downstream call info in the request
// info (i.e. for access logs if desired)
requestInfo.addRequestAttribute(DOWNSTREAM_CALL_PATH_REQUEST_ATTR_KEY, HttpUtils.extractPath(downstreamRequestFirstChunkInfo.firstChunk.getUri()));
// Try our circuit breaker (if we have one).
Throwable circuitBreakerException = null;
try {
circuitBreakerManualTask.ifPresent(ManualModeTask::throwExceptionIfCircuitBreakerIsOpen);
} catch (Throwable t) {
circuitBreakerException = t;
}
if (circuitBreakerException == null) {
// No circuit breaker, or the breaker is closed. We can now stream the first chunk info.
String downstreamHost = downstreamRequestFirstChunkInfo.host;
int downstreamPort = downstreamRequestFirstChunkInfo.port;
HttpRequest downstreamRequestFirstChunk = downstreamRequestFirstChunkInfo.firstChunk;
boolean isSecureHttpsCall = downstreamRequestFirstChunkInfo.isHttps;
boolean relaxedHttpsValidation = downstreamRequestFirstChunkInfo.relaxedHttpsValidation;
boolean performSubSpanAroundDownstreamCall = downstreamRequestFirstChunkInfo.performSubSpanAroundDownstreamCall;
boolean addTracingHeadersToDownstreamCall = downstreamRequestFirstChunkInfo.addTracingHeadersToDownstreamCall;
// Tell the proxyRouterState about the streaming callback so that
// callback.unrecoverableErrorOccurred(...) can be called in the case of an error
// on subsequent chunks.
proxyRouterState.setStreamingCallback(callback);
// Setup the streaming channel future with everything it needs to kick off the
// downstream request.
proxyRouterState.setStreamingStartTimeNanos(System.nanoTime());
CompletableFuture<StreamingChannel> streamingChannel = streamingAsyncHttpClient.streamDownstreamCall(downstreamHost, downstreamPort, downstreamRequestFirstChunk, isSecureHttpsCall, relaxedHttpsValidation, callback, callTimeoutValueToUse, performSubSpanAroundDownstreamCall, addTracingHeadersToDownstreamCall, ctx);
// Tell the streaming channel future what to do when it completes.
streamingChannel = streamingChannel.whenComplete((sc, cause) -> {
if (cause == null) {
// Successfully connected and sent the first chunk. We can now safely let
// the remaining content chunks through for streaming.
proxyRouterState.triggerChunkProcessing(sc);
} else {
// Something blew up while connecting to the downstream server.
callback.unrecoverableErrorOccurred(cause, true);
}
});
// Set the streaming channel future on the state so it can be connected to.
proxyRouterState.setStreamingChannelCompletableFuture(streamingChannel);
} else {
// Circuit breaker is tripped (or otherwise threw an unexpected exception). Immediately
// short circuit the error back to the client.
callback.unrecoverableErrorOccurred(circuitBreakerException, true);
}
} catch (Throwable t) {
callback.unrecoverableErrorOccurred(t, true);
}
}
});
} else if (msg instanceof HttpContent) {
HttpContent msgContent = (HttpContent) msg;
// chunk-streaming behavior and subsequent cleanup for the given HttpContent.
if (!releaseContentChunkIfStreamAlreadyFailed(msgContent, proxyRouterState)) {
registerChunkStreamingAction(proxyRouterState, msgContent, ctx);
}
}
return PipelineContinuationBehavior.DO_NOT_FIRE_CONTINUE_EVENT;
}
return PipelineContinuationBehavior.CONTINUE;
}
use of io.netty.handler.codec.http.HttpContent in project riposte by Nike-Inc.
the class RequestContentValidationHandlerTest method doChannelRead_does_nothing_if_msg_is_not_LastHttpContent.
@Test
public void doChannelRead_does_nothing_if_msg_is_not_LastHttpContent() throws Exception {
// given
HttpContent notLastContentMsg = mock(HttpContent.class);
// when
PipelineContinuationBehavior result = handler.doChannelRead(ctxMock, notLastContentMsg);
// then
verifyZeroInteractions(requestInfoMock);
verifyZeroInteractions(endpointMock);
verifyZeroInteractions(stateMock);
verifyZeroInteractions(requestValidatorMock);
assertThat(result).isEqualTo(PipelineContinuationBehavior.CONTINUE);
}
use of io.netty.handler.codec.http.HttpContent in project riposte by Nike-Inc.
the class RequestFilterHandlerTest method doChannelRead_does_nothing_and_returns_CONTINUE_when_msg_is_not_first_or_last_chunk.
@Test
public void doChannelRead_does_nothing_and_returns_CONTINUE_when_msg_is_not_first_or_last_chunk() throws Exception {
// given
HttpContent contentChunkMsg = mock(HttpContent.class);
// when
PipelineContinuationBehavior result = handlerSpy.doChannelRead(ctxMock, contentChunkMsg);
// then
assertThat(result).isEqualTo(CONTINUE);
verify(handlerSpy, never()).handleFilterLogic(any(), any(), any(), any(), any());
}
use of io.netty.handler.codec.http.HttpContent in project openzaly by akaxincom.
the class HttpServerHandler method channelRead.
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
try {
/**
* http-request包含: <br>
* 1.请求行 ,Method Request-URI Http-Version CRLF<br>
* 2.消息头 <br>
* 3.请求正文 <br>
*/
if (msg instanceof HttpRequest) {
request = (HttpRequest) msg;
if (!checkLegalRequest()) {
logger.error("{} http request method error. please use post!", AkxProject.PLN);
ctx.close();
return;
}
String clientIp = request.headers().get(HttpConst.HTTP_H_FORWARDED);
if (clientIp == null) {
InetSocketAddress address = (InetSocketAddress) ctx.channel().remoteAddress();
clientIp = address.getAddress().getHostAddress();
}
if (!checkLegalClientIp(clientIp)) {
logger.error("{} http request illegal IP={}.", AkxProject.PLN, clientIp);
ctx.close();
return;
}
logger.debug("{} request uri:{} clientIp={}", AkxProject.PLN, request.uri(), clientIp);
}
/**
* HttpContent:表示HTTP实体正文和内容标头的基类 <br>
* method.name=POST 传输消息体存在内容
*/
if (msg instanceof LastHttpContent) {
HttpContent content = (HttpContent) msg;
ByteBuf httpByteBuf = content.content();
if (httpByteBuf == null) {
return;
}
if (!checkLegalRequest()) {
ctx.close();
return;
}
String clientIp = request.headers().get(HttpConst.HTTP_H_FORWARDED);
String sitePluginId = request.headers().get(PluginConst.SITE_PLUGIN_ID);
byte[] contentBytes = new byte[httpByteBuf.readableBytes()];
httpByteBuf.readBytes(contentBytes);
httpByteBuf.release();
// 查询扩展的auth——key
String authKey = PluginSession.getInstance().getPluginAuthKey(sitePluginId);
if (StringUtils.isNotEmpty(authKey)) {
// byte[] tsk = AESCrypto.generateTSKey(authKey);
byte[] tsk = authKey.getBytes(CharsetCoding.ISO_8859_1);
byte[] decContent = AESCrypto.decrypt(tsk, contentBytes);
contentBytes = decContent;
}
PluginProto.ProxyPluginPackage pluginPackage = PluginProto.ProxyPluginPackage.parseFrom(contentBytes);
Map<Integer, String> proxyHeader = pluginPackage.getPluginHeaderMap();
String requestTime = proxyHeader.get(PluginProto.PluginHeaderKey.PLUGIN_TIMESTAMP_VALUE);
long currentTime = System.currentTimeMillis();
boolean timeOut = true;
if (StringUtils.isNotEmpty(requestTime)) {
long timeMills = Long.valueOf(requestTime);
if (currentTime - timeMills < 10 * 1000l) {
timeOut = false;
}
}
logger.debug("{} client={} http request timeOut={} currTime={} reqTime={}", AkxProject.PLN, clientIp, timeOut, currentTime, requestTime);
if (!timeOut) {
Command command = new Command();
command.setField(PluginConst.PLUGIN_AUTH_KEY, authKey);
if (proxyHeader != null) {
command.setSiteUserId(proxyHeader.get(PluginProto.PluginHeaderKey.CLIENT_SITE_USER_ID_VALUE));
}
command.setChannelContext(ctx);
command.setUri(request.uri());
command.setParams(Base64.getDecoder().decode(pluginPackage.getData()));
command.setClientIp(clientIp);
command.setStartTime(System.currentTimeMillis());
logger.debug("{} client={} http server handler command={}", AkxProject.PLN, clientIp, command.toString());
CommandResponse response = this.executor.execute(HttpUriAction.HTTP_ACTION.getUri(), command);
LogUtils.requestResultLog(logger, command, response);
} else {
// 超时10s,认为此请求失效,直接断开连接
ctx.close();
logger.error("{} client={} http request error.timeOut={} currTime={} reqTime={}", AkxProject.PLN, clientIp, timeOut, currentTime, requestTime);
}
}
} catch (Exception e) {
ctx.close();
logger.error(StringHelper.format("{} http request error.", AkxProject.PLN), e);
}
}
Aggregations