in httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/ProtocolExec.java [103:259]
public ClassicHttpResponse execute(
final ClassicHttpRequest userRequest,
final ExecChain.Scope scope,
final ExecChain chain) throws IOException, HttpException {
Args.notNull(userRequest, "HTTP request");
Args.notNull(scope, "Scope");
if (Method.CONNECT.isSame(userRequest.getMethod())) {
throw new ProtocolException("Direct execution of CONNECT is not allowed");
}
final String exchangeId = scope.exchangeId;
final HttpRoute route = scope.route;
final HttpClientContext context = scope.clientContext;
final ExecRuntime execRuntime = scope.execRuntime;
final HttpHost routeTarget = route.getTargetHost();
final HttpHost proxy = route.getProxyHost();
try {
final ClassicHttpRequest request;
if (proxy != null && !route.isTunnelled()) {
final ClassicRequestBuilder requestBuilder = ClassicRequestBuilder.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 = context.getAuthExchange(target);
final AuthExchange proxyAuthExchange = proxy != null ? context.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, context);
if (proxy != null) {
authCacheKeeper.loadPreemptively(proxy, null, proxyAuthExchange, context);
}
}
RequestEntityProxy.enhance(request);
for (;;) {
if (!request.containsHeader(HttpHeaders.AUTHORIZATION)) {
if (LOG.isDebugEnabled()) {
LOG.debug("{} target auth state: {}", exchangeId, targetAuthExchange.getState());
}
authenticator.addAuthResponse(target, ChallengeType.TARGET, request, targetAuthExchange, context);
}
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, context);
}
final ClassicHttpResponse response = chain.proceed(request, scope);
if (Method.TRACE.isSame(request.getMethod())) {
// Do not perform authentication for TRACE request
ResponseEntityProxy.enhance(response, execRuntime);
return response;
}
final HttpEntity requestEntity = request.getEntity();
if (requestEntity != null && !requestEntity.isRepeatable()) {
if (LOG.isDebugEnabled()) {
LOG.debug("{} Cannot retry non-repeatable request", exchangeId);
}
ResponseEntityProxy.enhance(response, execRuntime);
return response;
}
if (needAuthentication(
targetAuthExchange,
proxyAuthExchange,
proxy != null ? proxy : target,
target,
pathPrefix,
response,
context)) {
// Make sure the response body is fully consumed, if present
final HttpEntity responseEntity = response.getEntity();
if (execRuntime.isConnectionReusable()) {
EntityUtils.consume(responseEntity);
} else {
execRuntime.disconnectEndpoint();
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();
}
}
// Reset request headers
final ClassicHttpRequest original = scope.originalRequest;
request.setHeaders();
for (final Iterator<Header> it = original.headerIterator(); it.hasNext(); ) {
request.addHeader(it.next());
}
} else {
ResponseEntityProxy.enhance(response, execRuntime);
return response;
}
}
} catch (final HttpException ex) {
execRuntime.discardEndpoint();
throw ex;
} catch (final RuntimeException | IOException ex) {
execRuntime.discardEndpoint();
for (final AuthExchange authExchange : context.getAuthExchanges().values()) {
if (authExchange.isConnectionBased()) {
authExchange.reset();
}
}
throw ex;
}
}