summaryrefslogtreecommitdiffstats
path: root/src/org/apache/http/impl/client/DefaultRequestDirector.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/org/apache/http/impl/client/DefaultRequestDirector.java')
-rw-r--r--src/org/apache/http/impl/client/DefaultRequestDirector.java1088
1 files changed, 0 insertions, 1088 deletions
diff --git a/src/org/apache/http/impl/client/DefaultRequestDirector.java b/src/org/apache/http/impl/client/DefaultRequestDirector.java
deleted file mode 100644
index 511f8a0..0000000
--- a/src/org/apache/http/impl/client/DefaultRequestDirector.java
+++ /dev/null
@@ -1,1088 +0,0 @@
-/*
- * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/DefaultRequestDirector.java $
- * $Revision: 676023 $
- * $Date: 2008-07-11 09:40:56 -0700 (Fri, 11 Jul 2008) $
- *
- * ====================================================================
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation. For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-
-package org.apache.http.impl.client;
-
-import java.io.IOException;
-import java.io.InterruptedIOException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.Locale;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.http.ConnectionReuseStrategy;
-import org.apache.http.Header;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpEntityEnclosingRequest;
-import org.apache.http.HttpException;
-import org.apache.http.HttpHost;
-import org.apache.http.HttpRequest;
-import org.apache.http.HttpResponse;
-import org.apache.http.ProtocolException;
-import org.apache.http.ProtocolVersion;
-import org.apache.http.auth.AuthScheme;
-import org.apache.http.auth.AuthScope;
-import org.apache.http.auth.AuthState;
-import org.apache.http.auth.AuthenticationException;
-import org.apache.http.auth.Credentials;
-import org.apache.http.auth.MalformedChallengeException;
-import org.apache.http.client.AuthenticationHandler;
-import org.apache.http.client.RequestDirector;
-import org.apache.http.client.CredentialsProvider;
-import org.apache.http.client.HttpRequestRetryHandler;
-import org.apache.http.client.NonRepeatableRequestException;
-import org.apache.http.client.RedirectException;
-import org.apache.http.client.RedirectHandler;
-import org.apache.http.client.UserTokenHandler;
-import org.apache.http.client.methods.AbortableHttpRequest;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.client.params.ClientPNames;
-import org.apache.http.client.params.HttpClientParams;
-import org.apache.http.client.protocol.ClientContext;
-import org.apache.http.client.utils.URIUtils;
-import org.apache.http.conn.BasicManagedEntity;
-import org.apache.http.conn.ClientConnectionManager;
-import org.apache.http.conn.ClientConnectionRequest;
-import org.apache.http.conn.ConnectionKeepAliveStrategy;
-import org.apache.http.conn.ManagedClientConnection;
-import org.apache.http.conn.params.ConnManagerParams;
-import org.apache.http.conn.routing.BasicRouteDirector;
-import org.apache.http.conn.routing.HttpRoute;
-import org.apache.http.conn.routing.HttpRouteDirector;
-import org.apache.http.conn.routing.HttpRoutePlanner;
-import org.apache.http.conn.scheme.Scheme;
-import org.apache.http.entity.BufferedHttpEntity;
-import org.apache.http.message.BasicHttpRequest;
-import org.apache.http.params.HttpConnectionParams;
-import org.apache.http.params.HttpParams;
-import org.apache.http.params.HttpProtocolParams;
-import org.apache.http.protocol.ExecutionContext;
-import org.apache.http.protocol.HTTP;
-import org.apache.http.protocol.HttpContext;
-import org.apache.http.protocol.HttpProcessor;
-import org.apache.http.protocol.HttpRequestExecutor;
-
-/**
- * Default implementation of {@link RequestDirector}.
- * <br/>
- * This class replaces the <code>HttpMethodDirector</code> in HttpClient 3.
- *
- * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
- * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
- *
- * <!-- empty lines to avoid svn diff problems -->
- * @version $Revision: 676023 $
- *
- * @since 4.0
- */
-public class DefaultRequestDirector implements RequestDirector {
-
- private final Log log = LogFactory.getLog(getClass());
-
- /** The connection manager. */
- protected final ClientConnectionManager connManager;
-
- /** The route planner. */
- protected final HttpRoutePlanner routePlanner;
-
- /** The connection re-use strategy. */
- protected final ConnectionReuseStrategy reuseStrategy;
-
- /** The keep-alive duration strategy. */
- protected final ConnectionKeepAliveStrategy keepAliveStrategy;
-
- /** The request executor. */
- protected final HttpRequestExecutor requestExec;
-
- /** The HTTP protocol processor. */
- protected final HttpProcessor httpProcessor;
-
- /** The request retry handler. */
- protected final HttpRequestRetryHandler retryHandler;
-
- /** The redirect handler. */
- protected final RedirectHandler redirectHandler;
-
- /** The target authentication handler. */
- private final AuthenticationHandler targetAuthHandler;
-
- /** The proxy authentication handler. */
- private final AuthenticationHandler proxyAuthHandler;
-
- /** The user token handler. */
- private final UserTokenHandler userTokenHandler;
-
- /** The HTTP parameters. */
- protected final HttpParams params;
-
- /** The currently allocated connection. */
- protected ManagedClientConnection managedConn;
-
- private int redirectCount;
-
- private int maxRedirects;
-
- private final AuthState targetAuthState;
-
- private final AuthState proxyAuthState;
-
- public DefaultRequestDirector(
- final HttpRequestExecutor requestExec,
- final ClientConnectionManager conman,
- final ConnectionReuseStrategy reustrat,
- final ConnectionKeepAliveStrategy kastrat,
- final HttpRoutePlanner rouplan,
- final HttpProcessor httpProcessor,
- final HttpRequestRetryHandler retryHandler,
- final RedirectHandler redirectHandler,
- final AuthenticationHandler targetAuthHandler,
- final AuthenticationHandler proxyAuthHandler,
- final UserTokenHandler userTokenHandler,
- final HttpParams params) {
-
- if (requestExec == null) {
- throw new IllegalArgumentException
- ("Request executor may not be null.");
- }
- if (conman == null) {
- throw new IllegalArgumentException
- ("Client connection manager may not be null.");
- }
- if (reustrat == null) {
- throw new IllegalArgumentException
- ("Connection reuse strategy may not be null.");
- }
- if (kastrat == null) {
- throw new IllegalArgumentException
- ("Connection keep alive strategy may not be null.");
- }
- if (rouplan == null) {
- throw new IllegalArgumentException
- ("Route planner may not be null.");
- }
- if (httpProcessor == null) {
- throw new IllegalArgumentException
- ("HTTP protocol processor may not be null.");
- }
- if (retryHandler == null) {
- throw new IllegalArgumentException
- ("HTTP request retry handler may not be null.");
- }
- if (redirectHandler == null) {
- throw new IllegalArgumentException
- ("Redirect handler may not be null.");
- }
- if (targetAuthHandler == null) {
- throw new IllegalArgumentException
- ("Target authentication handler may not be null.");
- }
- if (proxyAuthHandler == null) {
- throw new IllegalArgumentException
- ("Proxy authentication handler may not be null.");
- }
- if (userTokenHandler == null) {
- throw new IllegalArgumentException
- ("User token handler may not be null.");
- }
- if (params == null) {
- throw new IllegalArgumentException
- ("HTTP parameters may not be null");
- }
- this.requestExec = requestExec;
- this.connManager = conman;
- this.reuseStrategy = reustrat;
- this.keepAliveStrategy = kastrat;
- this.routePlanner = rouplan;
- this.httpProcessor = httpProcessor;
- this.retryHandler = retryHandler;
- this.redirectHandler = redirectHandler;
- this.targetAuthHandler = targetAuthHandler;
- this.proxyAuthHandler = proxyAuthHandler;
- this.userTokenHandler = userTokenHandler;
- this.params = params;
-
- this.managedConn = null;
-
- this.redirectCount = 0;
- this.maxRedirects = this.params.getIntParameter(ClientPNames.MAX_REDIRECTS, 100);
- this.targetAuthState = new AuthState();
- this.proxyAuthState = new AuthState();
- } // constructor
-
-
- private RequestWrapper wrapRequest(
- final HttpRequest request) throws ProtocolException {
- if (request instanceof HttpEntityEnclosingRequest) {
- return new EntityEnclosingRequestWrapper(
- (HttpEntityEnclosingRequest) request);
- } else {
- return new RequestWrapper(
- request);
- }
- }
-
-
- protected void rewriteRequestURI(
- final RequestWrapper request,
- final HttpRoute route) throws ProtocolException {
- try {
-
- URI uri = request.getURI();
- if (route.getProxyHost() != null && !route.isTunnelled()) {
- // Make sure the request URI is absolute
- if (!uri.isAbsolute()) {
- HttpHost target = route.getTargetHost();
- uri = URIUtils.rewriteURI(uri, target);
- request.setURI(uri);
- }
- } else {
- // Make sure the request URI is relative
- if (uri.isAbsolute()) {
- uri = URIUtils.rewriteURI(uri, null);
- request.setURI(uri);
- }
- }
-
- } catch (URISyntaxException ex) {
- throw new ProtocolException("Invalid URI: " +
- request.getRequestLine().getUri(), ex);
- }
- }
-
-
- // non-javadoc, see interface ClientRequestDirector
- public HttpResponse execute(HttpHost target, HttpRequest request,
- HttpContext context)
- throws HttpException, IOException {
-
- HttpRequest orig = request;
- RequestWrapper origWrapper = wrapRequest(orig);
- origWrapper.setParams(params);
- HttpRoute origRoute = determineRoute(target, origWrapper, context);
-
- RoutedRequest roureq = new RoutedRequest(origWrapper, origRoute);
-
- long timeout = ConnManagerParams.getTimeout(params);
-
- int execCount = 0;
-
- boolean reuse = false;
- HttpResponse response = null;
- boolean done = false;
- try {
- while (!done) {
- // In this loop, the RoutedRequest may be replaced by a
- // followup request and route. The request and route passed
- // in the method arguments will be replaced. The original
- // request is still available in 'orig'.
-
- RequestWrapper wrapper = roureq.getRequest();
- HttpRoute route = roureq.getRoute();
-
- // See if we have a user token bound to the execution context
- Object userToken = context.getAttribute(ClientContext.USER_TOKEN);
-
- // Allocate connection if needed
- if (managedConn == null) {
- ClientConnectionRequest connRequest = connManager.requestConnection(
- route, userToken);
- if (orig instanceof AbortableHttpRequest) {
- ((AbortableHttpRequest) orig).setConnectionRequest(connRequest);
- }
-
- try {
- managedConn = connRequest.getConnection(timeout, TimeUnit.MILLISECONDS);
- } catch(InterruptedException interrupted) {
- InterruptedIOException iox = new InterruptedIOException();
- iox.initCause(interrupted);
- throw iox;
- }
-
- if (HttpConnectionParams.isStaleCheckingEnabled(params)) {
- // validate connection
- this.log.debug("Stale connection check");
- if (managedConn.isStale()) {
- this.log.debug("Stale connection detected");
- managedConn.close();
- }
- }
- }
-
- if (orig instanceof AbortableHttpRequest) {
- ((AbortableHttpRequest) orig).setReleaseTrigger(managedConn);
- }
-
- // Reopen connection if needed
- if (!managedConn.isOpen()) {
- managedConn.open(route, context, params);
- }
-
- try {
- establishRoute(route, context);
- } catch (TunnelRefusedException ex) {
- if (this.log.isDebugEnabled()) {
- this.log.debug(ex.getMessage());
- }
- response = ex.getResponse();
- break;
- }
-
- // Reset headers on the request wrapper
- wrapper.resetHeaders();
-
- // Re-write request URI if needed
- rewriteRequestURI(wrapper, route);
-
- // Use virtual host if set
- target = (HttpHost) wrapper.getParams().getParameter(
- ClientPNames.VIRTUAL_HOST);
-
- if (target == null) {
- target = route.getTargetHost();
- }
-
- HttpHost proxy = route.getProxyHost();
-
- // Populate the execution context
- context.setAttribute(ExecutionContext.HTTP_TARGET_HOST,
- target);
- context.setAttribute(ExecutionContext.HTTP_PROXY_HOST,
- proxy);
- context.setAttribute(ExecutionContext.HTTP_CONNECTION,
- managedConn);
- context.setAttribute(ClientContext.TARGET_AUTH_STATE,
- targetAuthState);
- context.setAttribute(ClientContext.PROXY_AUTH_STATE,
- proxyAuthState);
-
- // Run request protocol interceptors
- requestExec.preProcess(wrapper, httpProcessor, context);
-
- context.setAttribute(ExecutionContext.HTTP_REQUEST,
- wrapper);
-
- boolean retrying = true;
- while (retrying) {
- // Increment total exec count (with redirects)
- execCount++;
- // Increment exec count for this particular request
- wrapper.incrementExecCount();
- if (wrapper.getExecCount() > 1 && !wrapper.isRepeatable()) {
- throw new NonRepeatableRequestException("Cannot retry request " +
- "with a non-repeatable request entity");
- }
-
- try {
- if (this.log.isDebugEnabled()) {
- this.log.debug("Attempt " + execCount + " to execute request");
- }
- response = requestExec.execute(wrapper, managedConn, context);
- retrying = false;
-
- } catch (IOException ex) {
- this.log.debug("Closing the connection.");
- managedConn.close();
- if (retryHandler.retryRequest(ex, execCount, context)) {
- if (this.log.isInfoEnabled()) {
- this.log.info("I/O exception ("+ ex.getClass().getName() +
- ") caught when processing request: "
- + ex.getMessage());
- }
- if (this.log.isDebugEnabled()) {
- this.log.debug(ex.getMessage(), ex);
- }
- this.log.info("Retrying request");
- } else {
- throw ex;
- }
-
- // If we have a direct route to the target host
- // just re-open connection and re-try the request
- if (route.getHopCount() == 1) {
- this.log.debug("Reopening the direct connection.");
- managedConn.open(route, context, params);
- } else {
- // otherwise give up
- retrying = false;
- }
-
- }
-
- }
-
- // Run response protocol interceptors
- response.setParams(params);
- requestExec.postProcess(response, httpProcessor, context);
-
-
- // The connection is in or can be brought to a re-usable state.
- reuse = reuseStrategy.keepAlive(response, context);
- if(reuse) {
- // Set the idle duration of this connection
- long duration = keepAliveStrategy.getKeepAliveDuration(response, context);
- managedConn.setIdleDuration(duration, TimeUnit.MILLISECONDS);
- }
-
- RoutedRequest followup = handleResponse(roureq, response, context);
- if (followup == null) {
- done = true;
- } else {
- if (reuse) {
- this.log.debug("Connection kept alive");
- // Make sure the response body is fully consumed, if present
- HttpEntity entity = response.getEntity();
- if (entity != null) {
- entity.consumeContent();
- }
- // entity consumed above is not an auto-release entity,
- // need to mark the connection re-usable explicitly
- managedConn.markReusable();
- } else {
- managedConn.close();
- }
- // check if we can use the same connection for the followup
- if (!followup.getRoute().equals(roureq.getRoute())) {
- releaseConnection();
- }
- roureq = followup;
- }
-
- userToken = this.userTokenHandler.getUserToken(context);
- context.setAttribute(ClientContext.USER_TOKEN, userToken);
- if (managedConn != null) {
- managedConn.setState(userToken);
- }
- } // while not done
-
-
- // check for entity, release connection if possible
- if ((response == null) || (response.getEntity() == null) ||
- !response.getEntity().isStreaming()) {
- // connection not needed and (assumed to be) in re-usable state
- if (reuse)
- managedConn.markReusable();
- releaseConnection();
- } else {
- // install an auto-release entity
- HttpEntity entity = response.getEntity();
- entity = new BasicManagedEntity(entity, managedConn, reuse);
- response.setEntity(entity);
- }
-
- return response;
-
- } catch (HttpException ex) {
- abortConnection();
- throw ex;
- } catch (IOException ex) {
- abortConnection();
- throw ex;
- } catch (RuntimeException ex) {
- abortConnection();
- throw ex;
- }
- } // execute
-
- /**
- * Returns the connection back to the connection manager
- * and prepares for retrieving a new connection during
- * the next request.
- */
- protected void releaseConnection() {
- // Release the connection through the ManagedConnection instead of the
- // ConnectionManager directly. This lets the connection control how
- // it is released.
- try {
- managedConn.releaseConnection();
- } catch(IOException ignored) {
- this.log.debug("IOException releasing connection", ignored);
- }
- managedConn = null;
- }
-
- /**
- * Determines the route for a request.
- * Called by {@link #execute}
- * to determine the route for either the original or a followup request.
- *
- * @param target the target host for the request.
- * Implementations may accept <code>null</code>
- * if they can still determine a route, for example
- * to a default target or by inspecting the request.
- * @param request the request to execute
- * @param context the context to use for the execution,
- * never <code>null</code>
- *
- * @return the route the request should take
- *
- * @throws HttpException in case of a problem
- */
- protected HttpRoute determineRoute(HttpHost target,
- HttpRequest request,
- HttpContext context)
- throws HttpException {
-
- if (target == null) {
- target = (HttpHost) request.getParams().getParameter(
- ClientPNames.DEFAULT_HOST);
- }
- if (target == null) {
- throw new IllegalStateException
- ("Target host must not be null, or set in parameters.");
- }
-
- return this.routePlanner.determineRoute(target, request, context);
- }
-
-
- /**
- * Establishes the target route.
- *
- * @param route the route to establish
- * @param context the context for the request execution
- *
- * @throws HttpException in case of a problem
- * @throws IOException in case of an IO problem
- */
- protected void establishRoute(HttpRoute route, HttpContext context)
- throws HttpException, IOException {
-
- //@@@ how to handle CONNECT requests for tunnelling?
- //@@@ refuse to send external CONNECT via director? special handling?
-
- //@@@ should the request parameters already be used below?
- //@@@ probably yes, but they're not linked yet
- //@@@ will linking above cause problems with linking in reqExec?
- //@@@ probably not, because the parent is replaced
- //@@@ just make sure we don't link parameters to themselves
-
- HttpRouteDirector rowdy = new BasicRouteDirector();
- int step;
- do {
- HttpRoute fact = managedConn.getRoute();
- step = rowdy.nextStep(route, fact);
-
- switch (step) {
-
- case HttpRouteDirector.CONNECT_TARGET:
- case HttpRouteDirector.CONNECT_PROXY:
- managedConn.open(route, context, this.params);
- break;
-
- case HttpRouteDirector.TUNNEL_TARGET: {
- boolean secure = createTunnelToTarget(route, context);
- this.log.debug("Tunnel to target created.");
- managedConn.tunnelTarget(secure, this.params);
- } break;
-
- case HttpRouteDirector.TUNNEL_PROXY: {
- // The most simple example for this case is a proxy chain
- // of two proxies, where P1 must be tunnelled to P2.
- // route: Source -> P1 -> P2 -> Target (3 hops)
- // fact: Source -> P1 -> Target (2 hops)
- final int hop = fact.getHopCount()-1; // the hop to establish
- boolean secure = createTunnelToProxy(route, hop, context);
- this.log.debug("Tunnel to proxy created.");
- managedConn.tunnelProxy(route.getHopTarget(hop),
- secure, this.params);
- } break;
-
-
- case HttpRouteDirector.LAYER_PROTOCOL:
- managedConn.layerProtocol(context, this.params);
- break;
-
- case HttpRouteDirector.UNREACHABLE:
- throw new IllegalStateException
- ("Unable to establish route." +
- "\nplanned = " + route +
- "\ncurrent = " + fact);
-
- case HttpRouteDirector.COMPLETE:
- // do nothing
- break;
-
- default:
- throw new IllegalStateException
- ("Unknown step indicator "+step+" from RouteDirector.");
- } // switch
-
- } while (step > HttpRouteDirector.COMPLETE);
-
- } // establishConnection
-
-
- /**
- * 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> update the connection with
- * information about the tunnel, that is left to the caller.
- *
- * @param route the route to establish
- * @param context the context for request execution
- *
- * @return <code>true</code> if the tunnelled route is secure,
- * <code>false</code> otherwise.
- * The implementation here always returns <code>false</code>,
- * but derived classes may override.
- *
- * @throws HttpException in case of a problem
- * @throws IOException in case of an IO problem
- */
- protected boolean createTunnelToTarget(HttpRoute route,
- HttpContext context)
- throws HttpException, IOException {
-
- HttpHost proxy = route.getProxyHost();
- HttpHost target = route.getTargetHost();
- HttpResponse response = null;
-
- boolean done = false;
- while (!done) {
-
- done = true;
-
- if (!this.managedConn.isOpen()) {
- this.managedConn.open(route, context, this.params);
- }
-
- HttpRequest connect = createConnectRequest(route, context);
-
- String agent = HttpProtocolParams.getUserAgent(params);
- if (agent != null) {
- connect.addHeader(HTTP.USER_AGENT, agent);
- }
- connect.addHeader(HTTP.TARGET_HOST, target.toHostString());
-
- AuthScheme authScheme = this.proxyAuthState.getAuthScheme();
- AuthScope authScope = this.proxyAuthState.getAuthScope();
- Credentials creds = this.proxyAuthState.getCredentials();
- if (creds != null) {
- if (authScope != null || !authScheme.isConnectionBased()) {
- try {
- connect.addHeader(authScheme.authenticate(creds, connect));
- } catch (AuthenticationException ex) {
- if (this.log.isErrorEnabled()) {
- this.log.error("Proxy authentication error: " + ex.getMessage());
- }
- }
- }
- }
-
- response = requestExec.execute(connect, this.managedConn, context);
-
- int status = response.getStatusLine().getStatusCode();
- if (status < 200) {
- throw new HttpException("Unexpected response to CONNECT request: " +
- response.getStatusLine());
- }
-
- CredentialsProvider credsProvider = (CredentialsProvider)
- context.getAttribute(ClientContext.CREDS_PROVIDER);
-
- if (credsProvider != null && HttpClientParams.isAuthenticating(params)) {
- if (this.proxyAuthHandler.isAuthenticationRequested(response, context)) {
-
- this.log.debug("Proxy requested authentication");
- Map<String, Header> challenges = this.proxyAuthHandler.getChallenges(
- response, context);
- try {
- processChallenges(
- challenges, this.proxyAuthState, this.proxyAuthHandler,
- response, context);
- } catch (AuthenticationException ex) {
- if (this.log.isWarnEnabled()) {
- this.log.warn("Authentication error: " + ex.getMessage());
- break;
- }
- }
- updateAuthState(this.proxyAuthState, proxy, credsProvider);
-
- if (this.proxyAuthState.getCredentials() != null) {
- done = false;
-
- // Retry request
- if (this.reuseStrategy.keepAlive(response, context)) {
- this.log.debug("Connection kept alive");
- // Consume response content
- HttpEntity entity = response.getEntity();
- if (entity != null) {
- entity.consumeContent();
- }
- } else {
- this.managedConn.close();
- }
-
- }
-
- } else {
- // Reset proxy auth scope
- this.proxyAuthState.setAuthScope(null);
- }
- }
- }
-
- int status = response.getStatusLine().getStatusCode();
-
- if (status > 299) {
-
- // Buffer response content
- HttpEntity entity = response.getEntity();
- if (entity != null) {
- response.setEntity(new BufferedHttpEntity(entity));
- }
-
- this.managedConn.close();
- throw new TunnelRefusedException("CONNECT refused by proxy: " +
- response.getStatusLine(), response);
- }
-
- this.managedConn.markReusable();
-
- // How to decide on security of the tunnelled connection?
- // The socket factory knows only about the segment to the proxy.
- // Even if that is secure, the hop to the target may be insecure.
- // Leave it to derived classes, consider insecure by default here.
- return false;
-
- } // createTunnelToTarget
-
-
-
- /**
- * Creates a tunnel to an intermediate proxy.
- * This method is <i>not</i> implemented in this class.
- * It just throws an exception here.
- *
- * @param route the route to establish
- * @param hop the hop in the route to establish now.
- * <code>route.getHopTarget(hop)</code>
- * will return the proxy to tunnel to.
- * @param context the context for request execution
- *
- * @return <code>true</code> if the partially tunnelled connection
- * is secure, <code>false</code> otherwise.
- *
- * @throws HttpException in case of a problem
- * @throws IOException in case of an IO problem
- */
- protected boolean createTunnelToProxy(HttpRoute route, int hop,
- HttpContext context)
- throws HttpException, IOException {
-
- // Have a look at createTunnelToTarget and replicate the parts
- // you need in a custom derived class. If your proxies don't require
- // authentication, it is not too hard. But for the stock version of
- // HttpClient, we cannot make such simplifying assumptions and would
- // have to include proxy authentication code. The HttpComponents team
- // is currently not in a position to support rarely used code of this
- // complexity. Feel free to submit patches that refactor the code in
- // createTunnelToTarget to facilitate re-use for proxy tunnelling.
-
- throw new UnsupportedOperationException
- ("Proxy chains are not supported.");
- }
-
-
-
- /**
- * Creates the CONNECT request for tunnelling.
- * Called by {@link #createTunnelToTarget createTunnelToTarget}.
- *
- * @param route the route to establish
- * @param context the context for request execution
- *
- * @return the CONNECT request for tunnelling
- */
- protected HttpRequest createConnectRequest(HttpRoute route,
- HttpContext context) {
- // see RFC 2817, section 5.2 and
- // INTERNET-DRAFT: Tunneling TCP based protocols through
- // Web proxy servers
-
- HttpHost target = route.getTargetHost();
-
- String host = target.getHostName();
- int port = target.getPort();
- if (port < 0) {
- Scheme scheme = connManager.getSchemeRegistry().
- getScheme(target.getSchemeName());
- port = scheme.getDefaultPort();
- }
-
- StringBuilder buffer = new StringBuilder(host.length() + 6);
- buffer.append(host);
- buffer.append(':');
- buffer.append(Integer.toString(port));
-
- String authority = buffer.toString();
- ProtocolVersion ver = HttpProtocolParams.getVersion(params);
- HttpRequest req = new BasicHttpRequest
- ("CONNECT", authority, ver);
-
- return req;
- }
-
-
- /**
- * Analyzes a response to check need for a followup.
- *
- * @param roureq the request and route.
- * @param response the response to analayze
- * @param context the context used for the current request execution
- *
- * @return the followup request and route if there is a followup, or
- * <code>null</code> if the response should be returned as is
- *
- * @throws HttpException in case of a problem
- * @throws IOException in case of an IO problem
- */
- protected RoutedRequest handleResponse(RoutedRequest roureq,
- HttpResponse response,
- HttpContext context)
- throws HttpException, IOException {
-
- HttpRoute route = roureq.getRoute();
- HttpHost proxy = route.getProxyHost();
- RequestWrapper request = roureq.getRequest();
-
- HttpParams params = request.getParams();
- if (HttpClientParams.isRedirecting(params) &&
- this.redirectHandler.isRedirectRequested(response, context)) {
-
- if (redirectCount >= maxRedirects) {
- throw new RedirectException("Maximum redirects ("
- + maxRedirects + ") exceeded");
- }
- redirectCount++;
-
- URI uri = this.redirectHandler.getLocationURI(response, context);
-
- HttpHost newTarget = new HttpHost(
- uri.getHost(),
- uri.getPort(),
- uri.getScheme());
-
- HttpGet redirect = new HttpGet(uri);
-
- HttpRequest orig = request.getOriginal();
- redirect.setHeaders(orig.getAllHeaders());
-
- RequestWrapper wrapper = new RequestWrapper(redirect);
- wrapper.setParams(params);
-
- HttpRoute newRoute = determineRoute(newTarget, wrapper, context);
- RoutedRequest newRequest = new RoutedRequest(wrapper, newRoute);
-
- if (this.log.isDebugEnabled()) {
- this.log.debug("Redirecting to '" + uri + "' via " + newRoute);
- }
-
- return newRequest;
- }
-
- CredentialsProvider credsProvider = (CredentialsProvider)
- context.getAttribute(ClientContext.CREDS_PROVIDER);
-
- if (credsProvider != null && HttpClientParams.isAuthenticating(params)) {
-
- if (this.targetAuthHandler.isAuthenticationRequested(response, context)) {
-
- HttpHost target = (HttpHost)
- context.getAttribute(ExecutionContext.HTTP_TARGET_HOST);
- if (target == null) {
- target = route.getTargetHost();
- }
-
- this.log.debug("Target requested authentication");
- Map<String, Header> challenges = this.targetAuthHandler.getChallenges(
- response, context);
- try {
- processChallenges(challenges,
- this.targetAuthState, this.targetAuthHandler,
- response, context);
- } catch (AuthenticationException ex) {
- if (this.log.isWarnEnabled()) {
- this.log.warn("Authentication error: " + ex.getMessage());
- return null;
- }
- }
- updateAuthState(this.targetAuthState, target, credsProvider);
-
- if (this.targetAuthState.getCredentials() != null) {
- // Re-try the same request via the same route
- return roureq;
- } else {
- return null;
- }
- } else {
- // Reset target auth scope
- this.targetAuthState.setAuthScope(null);
- }
-
- if (this.proxyAuthHandler.isAuthenticationRequested(response, context)) {
-
- this.log.debug("Proxy requested authentication");
- Map<String, Header> challenges = this.proxyAuthHandler.getChallenges(
- response, context);
- try {
- processChallenges(challenges,
- this.proxyAuthState, this.proxyAuthHandler,
- response, context);
- } catch (AuthenticationException ex) {
- if (this.log.isWarnEnabled()) {
- this.log.warn("Authentication error: " + ex.getMessage());
- return null;
- }
- }
- updateAuthState(this.proxyAuthState, proxy, credsProvider);
-
- if (this.proxyAuthState.getCredentials() != null) {
- // Re-try the same request via the same route
- return roureq;
- } else {
- return null;
- }
- } else {
- // Reset proxy auth scope
- this.proxyAuthState.setAuthScope(null);
- }
- }
- return null;
- } // handleResponse
-
-
- /**
- * Shuts down the connection.
- * This method is called from a <code>catch</code> block in
- * {@link #execute execute} during exception handling.
- */
- private void abortConnection() {
- ManagedClientConnection mcc = managedConn;
- if (mcc != null) {
- // we got here as the result of an exception
- // no response will be returned, release the connection
- managedConn = null;
- try {
- mcc.abortConnection();
- } catch (IOException ex) {
- if (this.log.isDebugEnabled()) {
- this.log.debug(ex.getMessage(), ex);
- }
- }
- // ensure the connection manager properly releases this connection
- try {
- mcc.releaseConnection();
- } catch(IOException ignored) {
- this.log.debug("Error releasing connection", ignored);
- }
- }
- } // abortConnection
-
-
- private void processChallenges(
- final Map<String, Header> challenges,
- final AuthState authState,
- final AuthenticationHandler authHandler,
- final HttpResponse response,
- final HttpContext context)
- throws MalformedChallengeException, AuthenticationException {
-
- AuthScheme authScheme = authState.getAuthScheme();
- if (authScheme == null) {
- // Authentication not attempted before
- authScheme = authHandler.selectScheme(challenges, response, context);
- authState.setAuthScheme(authScheme);
- }
- String id = authScheme.getSchemeName();
-
- Header challenge = challenges.get(id.toLowerCase(Locale.ENGLISH));
- if (challenge == null) {
- throw new AuthenticationException(id +
- " authorization challenge expected, but not found");
- }
- authScheme.processChallenge(challenge);
- this.log.debug("Authorization challenge processed");
- }
-
-
- private void updateAuthState(
- final AuthState authState,
- final HttpHost host,
- final CredentialsProvider credsProvider) {
-
- if (!authState.isValid()) {
- return;
- }
-
- String hostname = host.getHostName();
- int port = host.getPort();
- if (port < 0) {
- Scheme scheme = connManager.getSchemeRegistry().getScheme(host);
- port = scheme.getDefaultPort();
- }
-
- AuthScheme authScheme = authState.getAuthScheme();
- AuthScope authScope = new AuthScope(
- hostname,
- port,
- authScheme.getRealm(),
- authScheme.getSchemeName());
-
- if (this.log.isDebugEnabled()) {
- this.log.debug("Authentication scope: " + authScope);
- }
- Credentials creds = authState.getCredentials();
- if (creds == null) {
- creds = credsProvider.getCredentials(authScope);
- if (this.log.isDebugEnabled()) {
- if (creds != null) {
- this.log.debug("Found credentials");
- } else {
- this.log.debug("Credentials not found");
- }
- }
- } else {
- if (authScheme.isComplete()) {
- this.log.debug("Authentication failed");
- creds = null;
- }
- }
- authState.setAuthScope(authScope);
- authState.setCredentials(creds);
- }
-
-} // class DefaultClientRequestDirector