private <T> NettyResponseFuture<T> newNettyResponseFuture(Request request, AsyncHandler<T> asyncHandler, NettyRequest nettyRequest, ProxyServer proxyServer) { NettyResponseFuture<T> future = new NettyResponseFuture<>( request, asyncHandler, nettyRequest, config.getMaxRequestRetry(), request.getChannelPoolPartitioning(), connectionSemaphore, proxyServer); String expectHeader = request.getHeaders().get(EXPECT); if (HttpHeaderValues.CONTINUE.contentEqualsIgnoreCase(expectHeader)) future.setDontWriteBodyBecauseExpectContinue(true); return future; }
public void abort(Channel channel, NettyResponseFuture<?> future, Throwable t) { if (channel != null && channel.isActive()) { channelManager.closeChannel(channel); } if (!future.isDone()) { future.setChannelState(ChannelState.CLOSED); LOGGER.debug("Aborting Future {}\n", future); LOGGER.debug(t.getMessage(), t); future.abort(t); } }
void finishUpdate(NettyResponseFuture<?> future, Channel channel, boolean close) { future.cancelTimeouts(); if (close) { channelManager.closeChannel(channel); } else { channelManager.tryToOfferChannelToPool(channel, future.getAsyncHandler(), true, future.getPartitionKey()); } try { future.done(); } catch (Exception t) { // Never propagate exception once we know we are done. logger.debug(t.getMessage(), t); } }
private boolean terminateAndExit() { releasePartitionKeyLock(); cancelTimeouts(); this.channel = null; this.reuseChannel = false; return IS_DONE_FIELD.getAndSet(this, 1) != 0 || isCancelled != 0; }
private Channel getOpenChannel(NettyResponseFuture<?> future, Request request, ProxyServer proxyServer, AsyncHandler<?> asyncHandler) { if (future != null && future.isReuseChannel() && Channels.isChannelActive(future.channel())) { return future.channel(); } else { return pollPooledChannel(request, proxyServer, asyncHandler); } }
@Override public void call() throws Exception { WebSocketUpgradeHandler handler = WebSocketUpgradeHandler.class.cast(future.getAsyncHandler()); Request request = future.getRequest(); HttpResponseStatus status = new NettyResponseStatus(future.getUri(), config, response, channel); HttpResponseHeaders responseHeaders = new NettyResponseHeaders(response.headers()); Realm realm = request.getRealm() != null ? request.getRealm() : config.getRealm(); future.setHttpHeaders(response.headers()); if (exitAfterHandlingRedirect(channel, future, response, request, response.getStatus().code(), realm)) return; handler.onCompleted(); } finally { future.done(); String key = getAcceptKey(future.getNettyRequest().getHttpRequest().headers().get(HttpHeaders.Names.SEC_WEBSOCKET_KEY)); if (accept == null || !accept.equals(key)) { requestSender.abort(channel, future, new IOException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept, key))); future.done();
public boolean retry(NettyResponseFuture<?> future) { if (isClosed()) return false; if (future.canBeReplayed()) { future.setState(NettyResponseFuture.STATE.RECONNECTED); future.getAndSetStatusReceived(false); LOGGER.debug("Trying to recover request {}\n", future.getNettyRequest().getHttpRequest()); if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) { AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onRetry(); } try { sendNextRequest(future.getRequest(), future); return true; } catch (Exception e) { abort(future.channel(), future, e); return false; } } else { LOGGER.debug("Unable to recover future {}\n", future); return false; } }
private boolean exitAfterHandlingConnect(// final Channel channel,// final NettyResponseFuture<?> future,// final Request request,// ProxyServer proxyServer,// int statusCode,// HttpRequest httpRequest) throws IOException { if (statusCode == OK.code() && httpRequest.getMethod() == HttpMethod.CONNECT) { if (future.isKeepAlive()) future.attachChannel(channel, true); Uri requestUri = request.getUri(); logger.debug("Connecting to proxy {} for scheme {}", proxyServer, requestUri.getScheme()); try { channelManager.upgradeProtocol(channel.pipeline(), requestUri); future.setReuseChannel(true); future.setConnectAllowed(false); requestSender.drainChannelAndExecuteNextRequest(channel, future, new RequestBuilder(future.getRequest()).build()); } catch (GeneralSecurityException ex) { requestSender.abort(channel, future, ex); } return true; } return false; }
private void writeRequest(Channel channel) { LOGGER.debug("Using non-cached Channel {} for {} '{}'", channel, future.getNettyRequest().getHttpRequest().getMethod(), future.getNettyRequest().getHttpRequest().getUri()); Channels.setAttribute(channel, future); if (future.isDone()) { abortChannelPreemption(); return; } if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onConnectionOpen(); channelManager.registerOpenChannel(channel, partitionKey); future.attachChannel(channel, false); requestSender.writeRequest(future, channel); }
public boolean exitAfterHandlingConnect(Channel channel, NettyResponseFuture<?> future, Request request, ProxyServer proxyServer) { if (future.isKeepAlive()) future.attachChannel(channel, true); Uri requestUri = request.getUri(); LOGGER.debug("Connecting to proxy {} for scheme {}", proxyServer, requestUri.getScheme()); Future<Channel> whenHandshaked = channelManager.updatePipelineForHttpTunneling(channel.pipeline(), requestUri); future.setReuseChannel(true); future.setConnectAllowed(false); Request targetRequest = new RequestBuilder(future.getTargetRequest()).build(); if (whenHandshaked == null) { requestSender.drainChannelAndExecuteNextRequest(channel, future, targetRequest); } else { requestSender.drainChannelAndExecuteNextRequest(channel, future, targetRequest, whenHandshaked); } return true; } }
public boolean retry(NettyResponseFuture<?> future) { if (isClosed()) { return false; } if (future.isReplayPossible()) { future.setChannelState(ChannelState.RECONNECTED); LOGGER.debug("Trying to recover request {}\n", future.getNettyRequest().getHttpRequest()); try { future.getAsyncHandler().onRetry(); } catch (Exception e) { LOGGER.error("onRetry crashed", e); abort(future.channel(), future, e); return false; } try { sendNextRequest(future.getCurrentRequest(), future); return true; } catch (Exception e) { abort(future.channel(), future, e); return false; } } else { LOGGER.debug("Unable to recover future {}\n", future); return false; } }
return; if (nettyResponseFuture.isDone()) { timeoutsHolder.cancel(); return; long currentReadTimeoutInstant = readTimeout + nettyResponseFuture.getLastTouch(); long durationBeforeCurrentReadTimeout = currentReadTimeoutInstant - now; appendRemoteAddress(sb); String message = sb.append(" after ").append(readTimeout).append(" ms").toString(); long durationSinceLastTouch = now - nettyResponseFuture.getLastTouch(); expire(message, durationSinceLastTouch);
public <T> void writeRequest(NettyResponseFuture<T> future, Channel channel) { NettyRequest nettyRequest = future.getNettyRequest(); HttpRequest httpRequest = nettyRequest.getHttpRequest(); AsyncHandler<T> asyncHandler = future.getAsyncHandler(); boolean writeBody = !future.isDontWriteBodyBecauseExpectContinue() && httpRequest.method() != HttpMethod.CONNECT && nettyRequest.getBody() != null; if (!future.isHeadersAlreadyWrittenOnContinue()) { try { asyncHandler.onRequestSend(nettyRequest);
private V getContent() throws ExecutionException { if (isCancelled()) throw new CancellationException(); ExecutionException e = exEx.get(); if (e != null) throw e; V update = content.get(); // No more retry currentRetry.set(maxRetry); if (!contentProcessed.getAndSet(true)) { try { update = asyncHandler.onCompleted(); } catch (Throwable ex) { if (!onThrowableCalled.getAndSet(true)) { try { try { asyncHandler.onThrowable(ex); } catch (Throwable t) { LOGGER.debug("asyncHandler.onThrowable", t); } throw new RuntimeException(ex); } finally { cancelTimeouts(); } } } content.compareAndSet(null, update); } return update; }
public void abort(Channel channel, NettyResponseFuture<?> future, Throwable t) { if (channel != null) channelManager.closeChannel(channel); if (!future.isDone()) { future.setState(NettyResponseFuture.STATE.CLOSED); LOGGER.debug("Aborting Future {}\n", future); LOGGER.debug(t.getMessage(), t); future.abort(t); } }
private void writeRequest(Channel channel) { LOGGER.debug("Using non-cached Channel {} for {} '{}'", channel, future.getNettyRequest().getHttpRequest().getMethod(), future.getNettyRequest().getHttpRequest().getUri()); Channels.setAttribute(channel, future); if (future.isDone()) { abortChannelPreemption(); return; } future.attachChannel(channel, false); channelManager.registerOpenChannel(channel, partitionKey); requestSender.writeRequest(future, channel); }
@SuppressWarnings({"rawtypes", "unchecked"}) public void replayRequest(final NettyResponseFuture<?> future, FilterContext fc, Channel channel) { Request newRequest = fc.getRequest(); future.setAsyncHandler(fc.getAsyncHandler()); future.setChannelState(ChannelState.NEW); future.touch(); LOGGER.debug("\n\nReplaying Request {}\n for Future {}\n", newRequest, future); try { future.getAsyncHandler().onRetry(); } catch (Exception e) { LOGGER.error("onRetry crashed", e); abort(channel, future, e); return; } channelManager.drainChannelAndOffer(channel, future); sendNextRequest(newRequest, future); }
private <T> ListenableFuture<T> sendRequestWithCachedChannel(Request request, ProxyServer proxy, NettyResponseFuture<T> future, AsyncHandler<T> asyncHandler, Channel channel) { if (asyncHandler instanceof AsyncHandlerExtensions) AsyncHandlerExtensions.class.cast(asyncHandler).onConnectionPooled(channel); future.setState(NettyResponseFuture.STATE.POOLED); future.attachChannel(channel, false); LOGGER.debug("Using cached Channel {} for {} '{}'", channel, future.getNettyRequest().getHttpRequest().getMethod(), future.getNettyRequest().getHttpRequest().getUri()); if (Channels.isChannelValid(channel)) { Channels.setAttribute(channel, future); writeRequest(future, channel); } else { // bad luck, the channel was closed in-between // there's a very good chance onClose was already notified but the // future wasn't already registered handleUnexpectedClosedChannel(channel, future); } return future; }
private void handleHttpResponse(final HttpResponse response, final Channel channel, final NettyResponseFuture<?> future, AsyncHandler<?> handler) throws Exception { HttpRequest httpRequest = future.getNettyRequest().getHttpRequest(); logger.debug("\n\nRequest {}\n\nResponse {}\n", httpRequest, response); future.setKeepAlive(config.getKeepAliveStrategy().keepAlive(future.getTargetRequest(), httpRequest, response)); NettyResponseStatus status = new NettyResponseStatus(future.getUri(), response, channel); HttpHeaders responseHeaders = response.headers(); if (!interceptors.exitAfterIntercept(channel, future, handler, response, status, responseHeaders)) { boolean abort = abortAfterHandlingStatus(handler, status) || // abortAfterHandlingHeaders(handler, responseHeaders) || // abortAfterHandlingReactiveStreams(channel, future, handler); if (abort) { finishUpdate(future, channel, true); } } }
@Test public void testCancelOnAlreadyCancelled() { AsyncHandler<?> asyncHandler = mock(AsyncHandler.class); NettyResponseFuture<?> nettyResponseFuture = new NettyResponseFuture<>(null, asyncHandler, null, 3, null, null, null); nettyResponseFuture.cancel(false); boolean result = nettyResponseFuture.cancel(false); assertFalse(result, "cancel should return false for an already cancelled Future"); assertTrue(nettyResponseFuture.isCancelled(), "isCancelled should return true for a cancelled Future"); }