@Override
    public void execute(
            final HttpRequest userRequest,
            final AsyncEntityProducer entityProducer,
            final AsyncExecChain.Scope scope,
            final AsyncExecChain chain,
            final AsyncExecCallback asyncExecCallback) throws HttpException, IOException {

        if (Method.CONNECT.isSame(userRequest.getMethod())) {
            throw new ProtocolException("Direct execution of CONNECT is not allowed");
        }

        final HttpRoute route = scope.route;
        final HttpHost routeTarget = route.getTargetHost();
        final HttpHost proxy = route.getProxyHost();
        final HttpClientContext clientContext = scope.clientContext;

        final HttpRequest request;
        if (proxy != null && !route.isTunnelled()) {
            final BasicRequestBuilder requestBuilder = BasicRequestBuilder.copy(userRequest);
            if (requestBuilder.getAuthority() == null) {
                requestBuilder.setAuthority(new URIAuthority(routeTarget));
            }
            requestBuilder.setAbsoluteRequestUri(true);
            request = requestBuilder.build();
        } else {
            request = userRequest;
        }

        // Ensure the request has a scheme and an authority
        if (request.getScheme() == null) {
            request.setScheme(routeTarget.getSchemeName());
        }
        if (request.getAuthority() == null) {
            request.setAuthority(new URIAuthority(routeTarget));
        }

        final URIAuthority authority = request.getAuthority();
        if (authority.getUserInfo() != null) {
            throw new ProtocolException("Request URI authority contains deprecated userinfo component");
        }

        final HttpHost target = new HttpHost(
                request.getScheme(),
                authority.getHostName(),
                schemePortResolver.resolve(request.getScheme(), authority));
        final String pathPrefix = RequestSupport.extractPathPrefix(request);
        final AuthExchange targetAuthExchange = clientContext.getAuthExchange(target);
        final AuthExchange proxyAuthExchange = proxy != null ? clientContext.getAuthExchange(proxy) : new AuthExchange();

        if (!targetAuthExchange.isConnectionBased() &&
                targetAuthExchange.getPathPrefix() != null &&
                !pathPrefix.startsWith(targetAuthExchange.getPathPrefix())) {
            // force re-authentication if the current path prefix does not match
            // that of the previous authentication exchange.
            targetAuthExchange.reset();
        }
        if (targetAuthExchange.getPathPrefix() == null) {
            targetAuthExchange.setPathPrefix(pathPrefix);
        }

        if (authCacheKeeper != null) {
            authCacheKeeper.loadPreemptively(target, pathPrefix, targetAuthExchange, clientContext);
            if (proxy != null) {
                authCacheKeeper.loadPreemptively(proxy, null, proxyAuthExchange, clientContext);
            }
        }

        final AtomicBoolean challenged = new AtomicBoolean(false);
        internalExecute(target, pathPrefix, targetAuthExchange, proxyAuthExchange,
                challenged, request, entityProducer, scope, chain, asyncExecCallback);
    }
Request execution handler in the asynchronous request execution chain
that is responsible for implementation of HTTP specification requirements.
<p>
Further responsibilities such as communication with the opposite
endpoint is delegated to the next executor in the request execution
chain.
</p>

@since 5.0
httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncProtocolExec.java