in httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/ProxyClient.java [132:208]
public Socket tunnel(
final HttpHost proxy,
final HttpHost target,
final Credentials credentials) throws IOException, HttpException {
Args.notNull(proxy, "Proxy host");
Args.notNull(target, "Target host");
Args.notNull(credentials, "Credentials");
Args.check(target.getPort() > 0, "A valid port number must be provided for the tunnel CONNECT request.");
final HttpRoute route = new HttpRoute(
target,
null,
proxy, false, TunnelType.TUNNELLED, LayerType.PLAIN);
final ManagedHttpClientConnection conn = this.connFactory.createConnection(null);
final HttpClientContext context = HttpClientContext.create();
ClassicHttpResponse response;
final ClassicHttpRequest connect = new BasicClassicHttpRequest(Method.CONNECT, proxy, target.toHostString());
final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(new AuthScope(proxy), credentials);
// Populate the execution context
context.setRequest(connect);
context.setRoute(route);
context.setCredentialsProvider(credsProvider);
context.setAuthSchemeRegistry(this.authSchemeRegistry);
context.setRequestConfig(this.requestConfig);
this.requestExec.preProcess(connect, this.httpProcessor, context);
for (;;) {
if (!conn.isOpen()) {
final Socket socket = new Socket(proxy.getHostName(), proxy.getPort());
conn.bind(socket);
}
this.authenticator.addAuthResponse(proxy, ChallengeType.PROXY, connect, this.proxyAuthExchange, context);
response = this.requestExec.execute(connect, conn, context);
final int status = response.getCode();
if (status < 200) {
throw new HttpException("Unexpected response to CONNECT request: " + response);
}
if (this.authenticator.isChallenged(proxy, ChallengeType.PROXY, response, this.proxyAuthExchange, context)
|| authenticator.isChallengeExpected(proxyAuthExchange)) {
if (this.authenticator.handleResponse(proxy, ChallengeType.PROXY, response,
this.proxyAuthStrategy, this.proxyAuthExchange, context)) {
// Retry request
if (this.reuseStrategy.keepAlive(connect, response, context)) {
// Consume response content
final HttpEntity entity = response.getEntity();
EntityUtils.consume(entity);
} else {
conn.close();
}
// discard previous auth header
connect.removeHeaders(HttpHeaders.PROXY_AUTHORIZATION);
} else {
break;
}
} else {
break;
}
}
final int status = response.getCode();
if (status > 299) {
EntityUtils.consume(response.getEntity());
conn.close();
throw new HttpException("Tunnel refused: " + new StatusLine(response));
}
return conn.getSocket();
}