in httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/ConnectExec.java [110:206]
public ClassicHttpResponse execute(
final ClassicHttpRequest request,
final ExecChain.Scope scope,
final ExecChain chain) throws IOException, HttpException {
Args.notNull(request, "HTTP request");
Args.notNull(scope, "Scope");
final String exchangeId = scope.exchangeId;
final HttpRoute route = scope.route;
final HttpClientContext context = scope.clientContext;
final ExecRuntime execRuntime = scope.execRuntime;
if (!execRuntime.isEndpointAcquired()) {
final Object userToken = context.getUserToken();
if (LOG.isDebugEnabled()) {
LOG.debug("{} acquiring connection with route {}", exchangeId, route);
}
execRuntime.acquireEndpoint(exchangeId, route, userToken, context);
}
try {
if (!execRuntime.isEndpointConnected()) {
if (LOG.isDebugEnabled()) {
LOG.debug("{} opening connection {}", exchangeId, route);
}
final RouteTracker tracker = new RouteTracker(route);
int step;
do {
final HttpRoute fact = tracker.toRoute();
step = this.routeDirector.nextStep(route, fact);
switch (step) {
case HttpRouteDirector.CONNECT_TARGET:
execRuntime.connectEndpoint(context);
tracker.connectTarget(route.isSecure());
break;
case HttpRouteDirector.CONNECT_PROXY:
execRuntime.connectEndpoint(context);
final HttpHost proxy = route.getProxyHost();
tracker.connectProxy(proxy, route.isSecure() && !route.isTunnelled());
break;
case HttpRouteDirector.TUNNEL_TARGET: {
final ClassicHttpResponse finalResponse = createTunnelToTarget(
exchangeId, route, request, execRuntime, context);
if (finalResponse != null) {
return finalResponse;
}
if (LOG.isDebugEnabled()) {
LOG.debug("{} tunnel to target created.", exchangeId);
}
tracker.tunnelTarget(false);
}
break;
case HttpRouteDirector.TUNNEL_PROXY: {
// The most simple example for this case is a proxy chain
// of two proxies, where P1 must be tunnelled to P2.
// route: Source -> P1 -> P2 -> Target (3 hops)
// fact: Source -> P1 -> Target (2 hops)
final int hop = fact.getHopCount() - 1; // the hop to establish
final boolean secure = createTunnelToProxy(route, hop, context);
if (LOG.isDebugEnabled()) {
LOG.debug("{} tunnel to proxy created.", exchangeId);
}
tracker.tunnelProxy(route.getHopTarget(hop), secure);
}
break;
case HttpRouteDirector.LAYER_PROTOCOL:
execRuntime.upgradeTls(context);
tracker.layerProtocol(route.isSecure());
break;
case HttpRouteDirector.UNREACHABLE:
throw new HttpException("Unable to establish route: " +
"planned = " + route + "; current = " + fact);
case HttpRouteDirector.COMPLETE:
break;
default:
throw new IllegalStateException("Unknown step indicator "
+ step + " from RouteDirector.");
}
} while (step > HttpRouteDirector.COMPLETE);
}
final EndpointInfo endpointInfo = execRuntime.getEndpointInfo();
if (endpointInfo != null) {
context.setSSLSession(endpointInfo.getSslSession());
}
return chain.proceed(request, scope);
} catch (final IOException | HttpException | RuntimeException ex) {
execRuntime.discardEndpoint();
throw ex;
}
}