}
public HttpRequest generateRequest(
final InternalState state,
final InternalConnManager connManager) throws IOException, HttpException {
final HttpClientContext localContext = state.getLocalContext();
final HttpRoute route = state.getRoute();
final NHttpClientConnection managedConn = connManager.getConnection();
if (!state.isRouteEstablished() && state.getRouteTracker() == null) {
state.setRouteEstablished(this.connmgr.isRouteComplete(managedConn));
if (!state.isRouteEstablished()) {
this.log.debug("Start connection routing");
state.setRouteTracker(new RouteTracker(route));
} else {
this.log.debug("Connection route already established");
}
}
if (!state.isRouteEstablished()) {
final RouteTracker routeTracker = state.getRouteTracker();
int step;
loop:
do {
final HttpRoute fact = routeTracker.toRoute();
step = this.routeDirector.nextStep(route, fact);
switch (step) {
case HttpRouteDirector.CONNECT_TARGET:
this.connmgr.startRoute(managedConn, route, localContext);
routeTracker.connectTarget(route.isSecure());
break;
case HttpRouteDirector.CONNECT_PROXY:
this.connmgr.startRoute(managedConn, route, localContext);
final HttpHost proxy = route.getProxyHost();
routeTracker.connectProxy(proxy, false);
break;
case HttpRouteDirector.TUNNEL_TARGET:
if (this.log.isDebugEnabled()) {
this.log.debug("[exchange: " + state.getId() + "] Tunnel required");
}
final HttpRequest connect = createConnectRequest(route, state);
state.setCurrentRequest(HttpRequestWrapper.wrap(connect));
break loop;
case HttpRouteDirector.TUNNEL_PROXY:
throw new HttpException("Proxy chains are not supported");
case HttpRouteDirector.LAYER_PROTOCOL:
this.connmgr.upgrade(managedConn, route, localContext);
routeTracker.layerProtocol(route.isSecure());
break;
case HttpRouteDirector.UNREACHABLE:
throw new HttpException("Unable to establish route: " +
"planned = " + route + "; current = " + fact);
case HttpRouteDirector.COMPLETE:
this.connmgr.routeComplete(managedConn, route, localContext);
state.setRouteEstablished(true);
state.setRouteTracker(null);
this.log.debug("Connection route established");
break;
default:
throw new IllegalStateException("Unknown step indicator "
+ step + " from RouteDirector.");
}
} while (step > HttpRouteDirector.COMPLETE);
}
HttpRequestWrapper currentRequest = state.getCurrentRequest();
if (currentRequest == null) {
currentRequest = state.getMainRequest();
state.setCurrentRequest(currentRequest);
}
if (state.isRouteEstablished()) {
state.incrementExecCount();
if (state.getExecCount() > 1) {
final HttpAsyncRequestProducer requestProducer = state.getRequestProducer();
if (!requestProducer.isRepeatable() && state.isRequestContentProduced()) {
throw new NonRepeatableRequestException("Cannot retry request " +
"with a non-repeatable request entity.");
}
requestProducer.resetRequest();
}
if (this.log.isDebugEnabled()) {
this.log.debug("[exchange: " + state.getId() + "] Attempt " + state.getExecCount() +
" to execute request");
}
if (!currentRequest.containsHeader(AUTH.WWW_AUTH_RESP)) {
final AuthState targetAuthState = localContext.getTargetAuthState();
if (this.log.isDebugEnabled()) {
this.log.debug("Target auth state: " + targetAuthState.getState());
}
this.authenticator.generateAuthResponse(currentRequest, targetAuthState, localContext);
}
if (!currentRequest.containsHeader(AUTH.PROXY_AUTH_RESP) && !route.isTunnelled()) {
final AuthState proxyAuthState = localContext.getProxyAuthState();
if (this.log.isDebugEnabled()) {
this.log.debug("Proxy auth state: " + proxyAuthState.getState());
}
this.authenticator.generateAuthResponse(currentRequest, proxyAuthState, localContext);
}
} else {
if (!currentRequest.containsHeader(AUTH.PROXY_AUTH_RESP)) {
final AuthState proxyAuthState = localContext.getProxyAuthState();
if (this.log.isDebugEnabled()) {
this.log.debug("Proxy auth state: " + proxyAuthState.getState());
}
this.authenticator.generateAuthResponse(currentRequest, proxyAuthState, localContext);
}
}
localContext.setAttribute(HttpCoreContext.HTTP_CONNECTION, managedConn);
final RequestConfig config = localContext.getRequestConfig();
if (config.getSocketTimeout() > 0) {
managedConn.setSocketTimeout(config.getSocketTimeout());
}
return currentRequest;
}