in httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/ConnectExec.java [204:292]
private boolean createTunnelToTarget(
final String exchangeId,
final HttpRoute route,
final HttpRequest request,
final ExecRuntime execRuntime,
final HttpClientContext context) throws HttpException, IOException {
final RequestConfig config = context.getRequestConfig();
final HttpHost target = route.getTargetHost();
final HttpHost proxy = route.getProxyHost();
final AuthExchange proxyAuthExchange = context.getAuthExchange(proxy);
if (authCacheKeeper != null) {
authCacheKeeper.loadPreemptively(proxy, null, proxyAuthExchange, context);
}
ClassicHttpResponse response = null;
final String authority = target.toHostString();
final ClassicHttpRequest connect = new BasicClassicHttpRequest(Method.CONNECT, target, authority);
connect.setVersion(HttpVersion.HTTP_1_1);
this.proxyHttpProcessor.process(connect, null, context);
while (response == null) {
connect.removeHeaders(HttpHeaders.PROXY_AUTHORIZATION);
this.authenticator.addAuthResponse(proxy, ChallengeType.PROXY, connect, proxyAuthExchange, context);
response = execRuntime.execute(exchangeId, connect, context);
this.proxyHttpProcessor.process(response, response.getEntity(), context);
final int status = response.getCode();
if (status < HttpStatus.SC_SUCCESS) {
throw new HttpException("Unexpected response to CONNECT request: " + new StatusLine(response));
}
if (config.isAuthenticationEnabled()) {
final boolean proxyAuthRequested = authenticator.isChallenged(proxy, ChallengeType.PROXY, response, proxyAuthExchange, context);
if (authCacheKeeper != null) {
if (proxyAuthRequested) {
authCacheKeeper.updateOnChallenge(proxy, null, proxyAuthExchange, context);
} else {
authCacheKeeper.updateOnNoChallenge(proxy, null, proxyAuthExchange, context);
}
}
if (proxyAuthRequested) {
final boolean updated = authenticator.updateAuthState(proxy, ChallengeType.PROXY, response,
proxyAuthStrategy, proxyAuthExchange, context);
if (authCacheKeeper != null) {
authCacheKeeper.updateOnResponse(proxy, null, proxyAuthExchange, context);
}
if (updated) {
// Retry request
if (this.reuseStrategy.keepAlive(connect, response, context)) {
if (LOG.isDebugEnabled()) {
LOG.debug("{} connection kept alive", exchangeId);
}
// Consume response content
final HttpEntity entity = response.getEntity();
EntityUtils.consume(entity);
} else {
execRuntime.disconnectEndpoint();
}
response = null;
}
}
}
}
final int status = response.getCode();
if (status != HttpStatus.SC_OK) {
// Buffer response content
final HttpEntity entity = response.getEntity();
final String responseMessage = entity != null ? EntityUtils.toString(entity) : null;
execRuntime.disconnectEndpoint();
throw new TunnelRefusedException("CONNECT refused by proxy: " + new StatusLine(response), responseMessage);
}
// How to decide on security of the tunnelled connection?
// The socket factory knows only about the segment to the proxy.
// Even if that is secure, the hop to the target may be insecure.
// Leave it to derived classes, consider insecure by default here.
return false;
}