private void internalExecute()

in httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncProtocolExec.java [178:301]


    private void internalExecute(
            final HttpHost target,
            final String pathPrefix,
            final AuthExchange targetAuthExchange,
            final AuthExchange proxyAuthExchange,
            final AtomicBoolean challenged,
            final HttpRequest request,
            final AsyncEntityProducer entityProducer,
            final AsyncExecChain.Scope scope,
            final AsyncExecChain chain,
            final AsyncExecCallback asyncExecCallback) throws HttpException, IOException {
        final String exchangeId = scope.exchangeId;
        final HttpRoute route = scope.route;
        final HttpClientContext clientContext = scope.clientContext;
        final AsyncExecRuntime execRuntime = scope.execRuntime;

        final HttpHost proxy = route.getProxyHost();

        if (!request.containsHeader(HttpHeaders.AUTHORIZATION)) {
            if (LOG.isDebugEnabled()) {
                LOG.debug("{} target auth state: {}", exchangeId, targetAuthExchange.getState());
            }
            authenticator.addAuthResponse(target, ChallengeType.TARGET, request, targetAuthExchange, clientContext);
        }
        if (!request.containsHeader(HttpHeaders.PROXY_AUTHORIZATION) && !route.isTunnelled()) {
            if (LOG.isDebugEnabled()) {
                LOG.debug("{} proxy auth state: {}", exchangeId, proxyAuthExchange.getState());
            }
            authenticator.addAuthResponse(proxy, ChallengeType.PROXY, request, proxyAuthExchange, clientContext);
        }

        chain.proceed(request, entityProducer, scope, new AsyncExecCallback() {

            @Override
            public AsyncDataConsumer handleResponse(
                    final HttpResponse response,
                    final EntityDetails entityDetails) throws HttpException, IOException {

                if (Method.TRACE.isSame(request.getMethod())) {
                    // Do not perform authentication for TRACE request
                    return asyncExecCallback.handleResponse(response, entityDetails);
                }
                if (needAuthentication(
                        targetAuthExchange,
                        proxyAuthExchange,
                        proxy != null ? proxy : target,
                        target,
                        pathPrefix,
                        response,
                        clientContext)) {
                    challenged.set(true);
                    return null;
                }
                challenged.set(false);
                return asyncExecCallback.handleResponse(response, entityDetails);
            }

            @Override
            public void handleInformationResponse(
                    final HttpResponse response) throws HttpException, IOException {
                asyncExecCallback.handleInformationResponse(response);
            }

            @Override
            public void completed() {
                if (!execRuntime.isEndpointConnected()) {
                    if (proxyAuthExchange.getState() == AuthExchange.State.SUCCESS
                            && proxyAuthExchange.isConnectionBased()) {
                        if (LOG.isDebugEnabled()) {
                            LOG.debug("{} resetting proxy auth state", exchangeId);
                        }
                        proxyAuthExchange.reset();
                    }
                    if (targetAuthExchange.getState() == AuthExchange.State.SUCCESS
                            && targetAuthExchange.isConnectionBased()) {
                        if (LOG.isDebugEnabled()) {
                            LOG.debug("{} resetting target auth state", exchangeId);
                        }
                        targetAuthExchange.reset();
                    }
                }

                if (challenged.get()) {
                    if (entityProducer != null && !entityProducer.isRepeatable()) {
                        if (LOG.isDebugEnabled()) {
                            LOG.debug("{} cannot retry non-repeatable request", exchangeId);
                        }
                        asyncExecCallback.completed();
                    } else {
                        // Reset request headers
                        final HttpRequest original = scope.originalRequest;
                        request.setHeaders();
                        for (final Iterator<Header> it = original.headerIterator(); it.hasNext(); ) {
                            request.addHeader(it.next());
                        }
                        try {
                            if (entityProducer != null) {
                                entityProducer.releaseResources();
                            }
                            internalExecute(target, pathPrefix, targetAuthExchange, proxyAuthExchange,
                                    challenged, request, entityProducer, scope, chain, asyncExecCallback);
                        } catch (final HttpException | IOException ex) {
                            asyncExecCallback.failed(ex);
                        }
                    }
                } else {
                    asyncExecCallback.completed();
                }
            }

            @Override
            public void failed(final Exception cause) {
                if (cause instanceof IOException || cause instanceof RuntimeException) {
                    for (final AuthExchange authExchange : clientContext.getAuthExchanges().values()) {
                        if (authExchange.isConnectionBased()) {
                            authExchange.reset();
                        }
                    }
                }
                asyncExecCallback.failed(cause);
            }

        });
    }