private ClassicHttpResponse createTunnelToTarget(
            final String exchangeId,
            final HttpRoute route,
            final HttpRequest request,
            final ExecRuntime execRuntime,
            final HttpClientContext context) throws HttpException, IOException {

        final RequestConfig config = context.getRequestConfigOrDefault();

        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);
                final boolean proxyMutualAuthRequired = authenticator.isChallengeExpected(proxyAuthExchange);

                if (authCacheKeeper != null) {
                    if (proxyAuthRequested) {
                        authCacheKeeper.updateOnChallenge(proxy, null, proxyAuthExchange, context);
                    } else {
                        authCacheKeeper.updateOnNoChallenge(proxy, null, proxyAuthExchange, context);
                    }
                }

                if (proxyAuthRequested || proxyMutualAuthRequired) {
                    final boolean updated = authenticator.handleResponse(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) {
            context.setProtocolVersion(null);
        } else {
            final HttpEntity entity = response.getEntity();
            if (entity != null) {
                response.setEntity(new ByteArrayEntity(
                        EntityUtils.toByteArray(entity, 4096),
                        ContentType.parseLenient(entity.getContentType())));
                execRuntime.discardEndpoint();
            }
            return response;
        }
        return null;
    }
Creates a tunnel to the target server.
The connection must be established to the (last) proxy.
A CONNECT request for tunnelling through the proxy will
be created and sent, the response received and checked.
This method does <i>not</i> processChallenge the connection with
information about the tunnel, that is left to the caller.
httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/ConnectExec.java