1ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel// copied verbatim (except for constructor access) from httpclient-4.0.3 sources
2ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
3ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel/*
4ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel * ====================================================================
5ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel * Licensed to the Apache Software Foundation (ASF) under one
6ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel * or more contributor license agreements.  See the NOTICE file
7ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel * distributed with this work for additional information
8ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel * regarding copyright ownership.  The ASF licenses this file
9ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel * to you under the Apache License, Version 2.0 (the
10ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel * "License"); you may not use this file except in compliance
11ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel * with the License.  You may obtain a copy of the License at
12ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel *
13ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel *   http://www.apache.org/licenses/LICENSE-2.0
14ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel *
15ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel * Unless required by applicable law or agreed to in writing,
16ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel * software distributed under the License is distributed on an
17ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel * KIND, either express or implied.  See the License for the
19ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel * specific language governing permissions and limitations
20ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel * under the License.
21ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel * ====================================================================
22ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel *
23ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel * This software consists of voluntary contributions made by many
24ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel * individuals on behalf of the Apache Software Foundation.  For more
25ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel * information on the Apache Software Foundation, please see
26ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel * <http://www.apache.org/>.
27ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel *
28ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel */
29ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkelpackage com.xtremelabs.robolectric.tester.org.apache.http.impl.client;
30ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
31ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkelimport org.apache.commons.logging.Log;
32ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkelimport org.apache.commons.logging.LogFactory;
334c5da7f8a2e3567f6b8cb2f26a5fc87907dbf208Amrit Thakur & Ryan Richardimport org.apache.http.*;
344c5da7f8a2e3567f6b8cb2f26a5fc87907dbf208Amrit Thakur & Ryan Richardimport org.apache.http.annotation.NotThreadSafe;
354c5da7f8a2e3567f6b8cb2f26a5fc87907dbf208Amrit Thakur & Ryan Richardimport org.apache.http.auth.*;
364c5da7f8a2e3567f6b8cb2f26a5fc87907dbf208Amrit Thakur & Ryan Richardimport org.apache.http.client.*;
37ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkelimport org.apache.http.client.methods.AbortableHttpRequest;
38ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkelimport org.apache.http.client.params.ClientPNames;
39ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkelimport org.apache.http.client.params.HttpClientParams;
40ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkelimport org.apache.http.client.protocol.ClientContext;
41ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkelimport org.apache.http.client.utils.URIUtils;
424c5da7f8a2e3567f6b8cb2f26a5fc87907dbf208Amrit Thakur & Ryan Richardimport org.apache.http.conn.*;
43ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkelimport org.apache.http.conn.params.ConnManagerParams;
44ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkelimport org.apache.http.conn.routing.BasicRouteDirector;
45ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkelimport org.apache.http.conn.routing.HttpRoute;
46ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkelimport org.apache.http.conn.routing.HttpRouteDirector;
47ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkelimport org.apache.http.conn.routing.HttpRoutePlanner;
48ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkelimport org.apache.http.conn.scheme.Scheme;
49ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkelimport org.apache.http.entity.BufferedHttpEntity;
50ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkelimport org.apache.http.impl.client.EntityEnclosingRequestWrapper;
51ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkelimport org.apache.http.impl.client.RequestWrapper;
52ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkelimport org.apache.http.impl.client.RoutedRequest;
53ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkelimport org.apache.http.impl.client.TunnelRefusedException;
54ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkelimport org.apache.http.message.BasicHttpRequest;
55ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkelimport org.apache.http.params.HttpConnectionParams;
56ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkelimport org.apache.http.params.HttpParams;
57ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkelimport org.apache.http.params.HttpProtocolParams;
58ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkelimport org.apache.http.protocol.ExecutionContext;
59ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkelimport org.apache.http.protocol.HttpContext;
60ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkelimport org.apache.http.protocol.HttpProcessor;
61ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkelimport org.apache.http.protocol.HttpRequestExecutor;
62ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
634c5da7f8a2e3567f6b8cb2f26a5fc87907dbf208Amrit Thakur & Ryan Richardimport java.io.IOException;
644c5da7f8a2e3567f6b8cb2f26a5fc87907dbf208Amrit Thakur & Ryan Richardimport java.io.InterruptedIOException;
654c5da7f8a2e3567f6b8cb2f26a5fc87907dbf208Amrit Thakur & Ryan Richardimport java.net.URI;
664c5da7f8a2e3567f6b8cb2f26a5fc87907dbf208Amrit Thakur & Ryan Richardimport java.net.URISyntaxException;
674c5da7f8a2e3567f6b8cb2f26a5fc87907dbf208Amrit Thakur & Ryan Richardimport java.util.Locale;
684c5da7f8a2e3567f6b8cb2f26a5fc87907dbf208Amrit Thakur & Ryan Richardimport java.util.Map;
694c5da7f8a2e3567f6b8cb2f26a5fc87907dbf208Amrit Thakur & Ryan Richardimport java.util.concurrent.TimeUnit;
704c5da7f8a2e3567f6b8cb2f26a5fc87907dbf208Amrit Thakur & Ryan Richard
71ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel/**
72ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel * Default implementation of {@link RequestDirector}.
73ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel * <p>
74ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel * The following parameters can be used to customize the behavior of this
75ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel * class:
76ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel * <ul>
77ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel *  <li>{@link org.apache.http.params.CoreProtocolPNames#PROTOCOL_VERSION}</li>
78ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel *  <li>{@link org.apache.http.params.CoreProtocolPNames#STRICT_TRANSFER_ENCODING}</li>
79ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel *  <li>{@link org.apache.http.params.CoreProtocolPNames#HTTP_ELEMENT_CHARSET}</li>
80ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel *  <li>{@link org.apache.http.params.CoreProtocolPNames#USE_EXPECT_CONTINUE}</li>
81ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel *  <li>{@link org.apache.http.params.CoreProtocolPNames#WAIT_FOR_CONTINUE}</li>
82ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel *  <li>{@link org.apache.http.params.CoreProtocolPNames#USER_AGENT}</li>
83ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel *  <li>{@link org.apache.http.params.CoreConnectionPNames#SOCKET_BUFFER_SIZE}</li>
84ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel *  <li>{@link org.apache.http.params.CoreConnectionPNames#MAX_LINE_LENGTH}</li>
85ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel *  <li>{@link org.apache.http.params.CoreConnectionPNames#MAX_HEADER_COUNT}</li>
86ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel *  <li>{@link org.apache.http.params.CoreConnectionPNames#SO_TIMEOUT}</li>
87ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel *  <li>{@link org.apache.http.params.CoreConnectionPNames#SO_LINGER}</li>
88ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel *  <li>{@link org.apache.http.params.CoreConnectionPNames#TCP_NODELAY}</li>
89ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel *  <li>{@link org.apache.http.params.CoreConnectionPNames#CONNECTION_TIMEOUT}</li>
90ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel *  <li>{@link org.apache.http.params.CoreConnectionPNames#STALE_CONNECTION_CHECK}</li>
91ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel *  <li>{@link org.apache.http.conn.params.ConnRoutePNames#FORCED_ROUTE}</li>
92ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel *  <li>{@link org.apache.http.conn.params.ConnRoutePNames#LOCAL_ADDRESS}</li>
93ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel *  <li>{@link org.apache.http.conn.params.ConnRoutePNames#DEFAULT_PROXY}</li>
94ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel *  <li>{@link org.apache.http.conn.params.ConnManagerPNames#TIMEOUT}</li>
95ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel *  <li>{@link org.apache.http.conn.params.ConnManagerPNames#MAX_CONNECTIONS_PER_ROUTE}</li>
96ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel *  <li>{@link org.apache.http.conn.params.ConnManagerPNames#MAX_TOTAL_CONNECTIONS}</li>
97ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel *  <li>{@link org.apache.http.cookie.params.CookieSpecPNames#DATE_PATTERNS}</li>
98ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel *  <li>{@link org.apache.http.cookie.params.CookieSpecPNames#SINGLE_COOKIE_HEADER}</li>
99ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel *  <li>{@link org.apache.http.auth.params.AuthPNames#CREDENTIAL_CHARSET}</li>
100ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel *  <li>{@link org.apache.http.client.params.ClientPNames#COOKIE_POLICY}</li>
101ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel *  <li>{@link org.apache.http.client.params.ClientPNames#HANDLE_AUTHENTICATION}</li>
102ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel *  <li>{@link org.apache.http.client.params.ClientPNames#HANDLE_REDIRECTS}</li>
103ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel *  <li>{@link org.apache.http.client.params.ClientPNames#MAX_REDIRECTS}</li>
104ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel *  <li>{@link org.apache.http.client.params.ClientPNames#ALLOW_CIRCULAR_REDIRECTS}</li>
105ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel *  <li>{@link org.apache.http.client.params.ClientPNames#VIRTUAL_HOST}</li>
106ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel *  <li>{@link org.apache.http.client.params.ClientPNames#DEFAULT_HOST}</li>
107ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel *  <li>{@link org.apache.http.client.params.ClientPNames#DEFAULT_HEADERS}</li>
108ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel * </ul>
109ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel *
110ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel * @since 4.0
111ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel */
112ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel@NotThreadSafe // e.g. managedConn
113ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkelpublic class DefaultRequestDirector implements RequestDirector {
114ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
115ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    private final Log log;
116ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
117ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    /** The connection manager. */
118ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    protected final ClientConnectionManager connManager;
119ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
120ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    /** The route planner. */
121ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    protected final HttpRoutePlanner routePlanner;
122ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
123ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    /** The connection re-use strategy. */
124ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    protected final ConnectionReuseStrategy reuseStrategy;
125ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
126ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    /** The keep-alive duration strategy. */
127ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    protected final ConnectionKeepAliveStrategy keepAliveStrategy;
128ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
129ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    /** The request executor. */
130ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    protected final HttpRequestExecutor requestExec;
131ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
132ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    /** The HTTP protocol processor. */
133ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    protected final HttpProcessor httpProcessor;
134ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
135ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    /** The request retry handler. */
136ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    protected final HttpRequestRetryHandler retryHandler;
137ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
138ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    /** The redirect handler. */
139ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    protected final RedirectHandler redirectHandler;
140ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
141ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    /** The target authentication handler. */
142ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    protected final AuthenticationHandler targetAuthHandler;
143ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
144ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    /** The proxy authentication handler. */
145ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    protected final AuthenticationHandler proxyAuthHandler;
146ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
147ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    /** The user token handler. */
148ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    protected final UserTokenHandler userTokenHandler;
149ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
150ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    /** The HTTP parameters. */
151ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    protected final HttpParams params;
152ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
153ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    /** The currently allocated connection. */
154ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    protected ManagedClientConnection managedConn;
155ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
156ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    protected final AuthState targetAuthState;
157ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
158ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    protected final AuthState proxyAuthState;
159ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
160ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    private int redirectCount;
161ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
162ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    private int maxRedirects;
163ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
164ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    private HttpHost virtualHost;
165ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
166ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    public DefaultRequestDirector(
167ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            final Log log,
168ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            final HttpRequestExecutor requestExec,
169ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            final ClientConnectionManager conman,
170ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            final ConnectionReuseStrategy reustrat,
171ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            final ConnectionKeepAliveStrategy kastrat,
172ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            final HttpRoutePlanner rouplan,
173ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            final HttpProcessor httpProcessor,
174ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            final HttpRequestRetryHandler retryHandler,
175ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            final RedirectHandler redirectHandler,
176ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            final AuthenticationHandler targetAuthHandler,
177ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            final AuthenticationHandler proxyAuthHandler,
178ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            final UserTokenHandler userTokenHandler,
179ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            final HttpParams params) {
180ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
181ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        if (log == null) {
182ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            throw new IllegalArgumentException
183ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                ("Log may not be null.");
184ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        }
185ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        if (requestExec == null) {
186ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            throw new IllegalArgumentException
187ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                ("Request executor may not be null.");
188ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        }
189ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        if (conman == null) {
190ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            throw new IllegalArgumentException
191ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                ("Client connection manager may not be null.");
192ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        }
193ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        if (reustrat == null) {
194ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            throw new IllegalArgumentException
195ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                ("Connection reuse strategy may not be null.");
196ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        }
197ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        if (kastrat == null) {
198ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            throw new IllegalArgumentException
199ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                ("Connection keep alive strategy may not be null.");
200ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        }
201ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        if (rouplan == null) {
202ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            throw new IllegalArgumentException
203ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                ("Route planner may not be null.");
204ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        }
205ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        if (httpProcessor == null) {
206ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            throw new IllegalArgumentException
207ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                ("HTTP protocol processor may not be null.");
208ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        }
209ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        if (retryHandler == null) {
210ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            throw new IllegalArgumentException
211ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                ("HTTP request retry handler may not be null.");
212ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        }
213ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        if (redirectHandler == null) {
214ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            throw new IllegalArgumentException
215ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                ("Redirect handler may not be null.");
216ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        }
217ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        if (targetAuthHandler == null) {
218ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            throw new IllegalArgumentException
219ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                ("Target authentication handler may not be null.");
220ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        }
221ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        if (proxyAuthHandler == null) {
222ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            throw new IllegalArgumentException
223ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                ("Proxy authentication handler may not be null.");
224ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        }
225ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        if (userTokenHandler == null) {
226ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            throw new IllegalArgumentException
227ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                ("User token handler may not be null.");
228ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        }
229ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        if (params == null) {
230ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            throw new IllegalArgumentException
231ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                ("HTTP parameters may not be null");
232ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        }
233ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        this.log               = log;
234ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        this.requestExec       = requestExec;
235ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        this.connManager       = conman;
236ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        this.reuseStrategy     = reustrat;
237ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        this.keepAliveStrategy = kastrat;
238ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        this.routePlanner      = rouplan;
239ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        this.httpProcessor     = httpProcessor;
240ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        this.retryHandler      = retryHandler;
241ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        this.redirectHandler   = redirectHandler;
242ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        this.targetAuthHandler = targetAuthHandler;
243ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        this.proxyAuthHandler  = proxyAuthHandler;
244ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        this.userTokenHandler  = userTokenHandler;
245ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        this.params            = params;
246ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
247ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        this.managedConn       = null;
248ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
249ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        this.redirectCount = 0;
250ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        this.maxRedirects = this.params.getIntParameter(ClientPNames.MAX_REDIRECTS, 100);
251ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        this.targetAuthState = new AuthState();
252ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        this.proxyAuthState = new AuthState();
253ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    } // constructor
254ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
255ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    public DefaultRequestDirector(
256ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            final HttpRequestExecutor requestExec,
257ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            final ClientConnectionManager conman,
258ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            final ConnectionReuseStrategy reustrat,
259ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            final ConnectionKeepAliveStrategy kastrat,
260ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            final HttpRoutePlanner rouplan,
261ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            final HttpProcessor httpProcessor,
262ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            final HttpRequestRetryHandler retryHandler,
263ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            final RedirectHandler redirectHandler,
264ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            final AuthenticationHandler targetAuthHandler,
265ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            final AuthenticationHandler proxyAuthHandler,
266ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            final UserTokenHandler userTokenHandler,
267ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            final HttpParams params) {
268ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        this(LogFactory.getLog(DefaultRequestDirector.class),
269ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                requestExec,
270ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                conman,
271ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                reustrat,
272ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                kastrat,
273ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                rouplan,
274ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                httpProcessor,
275ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                retryHandler,
276ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                redirectHandler,
277ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                targetAuthHandler,
278ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                proxyAuthHandler,
279ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                userTokenHandler,
280ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                params);
281ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
282ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    }
283ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
284ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    private RequestWrapper wrapRequest(
285ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            final HttpRequest request) throws ProtocolException {
286ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        if (request instanceof HttpEntityEnclosingRequest) {
287ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            return new EntityEnclosingRequestWrapper(
288ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    (HttpEntityEnclosingRequest) request);
289ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        } else {
290ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            return new RequestWrapper(
291ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    request);
292ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        }
293ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    }
294ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
295ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
296ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    protected void rewriteRequestURI(
297ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            final RequestWrapper request,
298ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            final HttpRoute route) throws ProtocolException {
299ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        try {
300ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
301ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            URI uri = request.getURI();
302ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            if (route.getProxyHost() != null && !route.isTunnelled()) {
303ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                // Make sure the request URI is absolute
304ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                if (!uri.isAbsolute()) {
305ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    HttpHost target = route.getTargetHost();
306ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    uri = URIUtils.rewriteURI(uri, target);
307ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    request.setURI(uri);
308ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                }
309ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            } else {
310ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                // Make sure the request URI is relative
311ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                if (uri.isAbsolute()) {
312ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    uri = URIUtils.rewriteURI(uri, null);
313ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    request.setURI(uri);
314ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                }
315ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            }
316ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
317ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        } catch (URISyntaxException ex) {
318ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            throw new ProtocolException("Invalid URI: " +
319ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    request.getRequestLine().getUri(), ex);
320ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        }
321ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    }
322ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
323ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
324ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    // non-javadoc, see interface ClientRequestDirector
325ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    public HttpResponse execute(HttpHost target, HttpRequest request,
326ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                                HttpContext context)
327ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        throws HttpException, IOException {
328ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
329ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        HttpRequest orig = request;
330ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        RequestWrapper origWrapper = wrapRequest(orig);
331ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        origWrapper.setParams(params);
332ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        HttpRoute origRoute = determineRoute(target, origWrapper, context);
333ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
334ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        virtualHost = (HttpHost) orig.getParams().getParameter(
335ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                ClientPNames.VIRTUAL_HOST);
336ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
337ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        RoutedRequest roureq = new RoutedRequest(origWrapper, origRoute);
338ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
339ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        long timeout = ConnManagerParams.getTimeout(params);
340ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
341ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        int execCount = 0;
342ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
343ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        boolean reuse = false;
344ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        boolean done = false;
345ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        try {
346ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            HttpResponse response = null;
347ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            while (!done) {
348ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                // In this loop, the RoutedRequest may be replaced by a
349ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                // followup request and route. The request and route passed
350ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                // in the method arguments will be replaced. The original
351ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                // request is still available in 'orig'.
352ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
353ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                RequestWrapper wrapper = roureq.getRequest();
354ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                HttpRoute route = roureq.getRoute();
355ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                response = null;
356ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
357ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                // See if we have a user token bound to the execution context
358ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                Object userToken = context.getAttribute(ClientContext.USER_TOKEN);
359ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
360ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                // Allocate connection if needed
361ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                if (managedConn == null) {
362ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    ClientConnectionRequest connRequest = connManager.requestConnection(
363ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                            route, userToken);
364ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    if (orig instanceof AbortableHttpRequest) {
365ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        ((AbortableHttpRequest) orig).setConnectionRequest(connRequest);
366ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    }
367ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
368ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    try {
369ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        managedConn = connRequest.getConnection(timeout, TimeUnit.MILLISECONDS);
370ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    } catch(InterruptedException interrupted) {
371ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        InterruptedIOException iox = new InterruptedIOException();
372ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        iox.initCause(interrupted);
373ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        throw iox;
374ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    }
375ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
376ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    if (HttpConnectionParams.isStaleCheckingEnabled(params)) {
377ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        // validate connection
378ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        if (managedConn.isOpen()) {
379ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                            this.log.debug("Stale connection check");
380ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                            if (managedConn.isStale()) {
381ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                                this.log.debug("Stale connection detected");
382ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                                managedConn.close();
383ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                            }
384ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        }
385ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    }
386ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                }
387ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
388ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                if (orig instanceof AbortableHttpRequest) {
389ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    ((AbortableHttpRequest) orig).setReleaseTrigger(managedConn);
390ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                }
391ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
392ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                // Reopen connection if needed
393ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                if (!managedConn.isOpen()) {
394ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    managedConn.open(route, context, params);
395ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                } else {
396ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    managedConn.setSocketTimeout(HttpConnectionParams.getSoTimeout(params));
397ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                }
398ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
399ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                try {
400ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    establishRoute(route, context);
401ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                } catch (TunnelRefusedException ex) {
402ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    if (this.log.isDebugEnabled()) {
403ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        this.log.debug(ex.getMessage());
404ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    }
405ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    response = ex.getResponse();
406ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    break;
407ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                }
408ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
409ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                // Reset headers on the request wrapper
410ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                wrapper.resetHeaders();
411ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
412ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                // Re-write request URI if needed
413ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                rewriteRequestURI(wrapper, route);
414ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
415ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                // Use virtual host if set
416ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                target = virtualHost;
417ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
418ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                if (target == null) {
419ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    target = route.getTargetHost();
420ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                }
421ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
422ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                HttpHost proxy = route.getProxyHost();
423ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
424ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                // Populate the execution context
425ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                context.setAttribute(ExecutionContext.HTTP_TARGET_HOST,
426ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        target);
427ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                context.setAttribute(ExecutionContext.HTTP_PROXY_HOST,
428ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        proxy);
429ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                context.setAttribute(ExecutionContext.HTTP_CONNECTION,
430ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        managedConn);
431ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                context.setAttribute(ClientContext.TARGET_AUTH_STATE,
432ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        targetAuthState);
433ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                context.setAttribute(ClientContext.PROXY_AUTH_STATE,
434ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        proxyAuthState);
435ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
436ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                // Run request protocol interceptors
437ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                requestExec.preProcess(wrapper, httpProcessor, context);
438ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
439ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                boolean retrying = true;
440ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                Exception retryReason = null;
441ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                while (retrying) {
442ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    // Increment total exec count (with redirects)
443ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    execCount++;
444ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    // Increment exec count for this particular request
445ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    wrapper.incrementExecCount();
446ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    if (!wrapper.isRepeatable()) {
447ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        this.log.debug("Cannot retry non-repeatable request");
448ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        if (retryReason != null) {
449ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                            throw new NonRepeatableRequestException("Cannot retry request " +
450ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                                "with a non-repeatable request entity.  The cause lists the " +
4514c5da7f8a2e3567f6b8cb2f26a5fc87907dbf208Amrit Thakur & Ryan Richard                                "reason the original request failed: " + retryReason);
452ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        } else {
453ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                            throw new NonRepeatableRequestException("Cannot retry request " +
454ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                                    "with a non-repeatable request entity.");
455ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        }
456ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    }
457ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
458ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    try {
459ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        if (this.log.isDebugEnabled()) {
460ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                            this.log.debug("Attempt " + execCount + " to execute request");
461ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        }
462ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        response = requestExec.execute(wrapper, managedConn, context);
463ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        retrying = false;
464ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
465ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    } catch (IOException ex) {
466ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        this.log.debug("Closing the connection.");
467ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        managedConn.close();
468ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        if (retryHandler.retryRequest(ex, wrapper.getExecCount(), context)) {
469ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                            if (this.log.isInfoEnabled()) {
470ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                                this.log.info("I/O exception ("+ ex.getClass().getName() +
471ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                                        ") caught when processing request: "
472ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                                        + ex.getMessage());
473ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                            }
474ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                            if (this.log.isDebugEnabled()) {
475ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                                this.log.debug(ex.getMessage(), ex);
476ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                            }
477ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                            this.log.info("Retrying request");
478ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                            retryReason = ex;
479ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        } else {
480ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                            throw ex;
481ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        }
482ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
483ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        // If we have a direct route to the target host
484ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        // just re-open connection and re-try the request
485ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        if (!route.isTunnelled()) {
486ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                            this.log.debug("Reopening the direct connection.");
487ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                            managedConn.open(route, context, params);
488ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        } else {
489ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                            // otherwise give up
490ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                            this.log.debug("Proxied connection. Need to start over.");
491ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                            retrying = false;
492ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        }
493ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
494ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    }
495ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
496ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                }
497ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
498ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                if (response == null) {
499ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    // Need to start over
500ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    continue;
501ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                }
502ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
503ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                // Run response protocol interceptors
504ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                response.setParams(params);
505ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                requestExec.postProcess(response, httpProcessor, context);
506ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
507ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
508ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                // The connection is in or can be brought to a re-usable state.
509ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                reuse = reuseStrategy.keepAlive(response, context);
510ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                if (reuse) {
511ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    // Set the idle duration of this connection
512ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    long duration = keepAliveStrategy.getKeepAliveDuration(response, context);
513ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    managedConn.setIdleDuration(duration, TimeUnit.MILLISECONDS);
514ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
515ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    if (this.log.isDebugEnabled()) {
516ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        if (duration >= 0) {
517ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                            this.log.debug("Connection can be kept alive for " + duration + " ms");
518ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        } else {
519ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                            this.log.debug("Connection can be kept alive indefinitely");
520ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        }
521ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    }
522ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                }
523ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
524ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                RoutedRequest followup = handleResponse(roureq, response, context);
525ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                if (followup == null) {
526ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    done = true;
527ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                } else {
528ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    if (reuse) {
529ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        // Make sure the response body is fully consumed, if present
530ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        HttpEntity entity = response.getEntity();
531ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        if (entity != null) {
532ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                            entity.consumeContent();
533ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        }
534ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        // entity consumed above is not an auto-release entity,
535ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        // need to mark the connection re-usable explicitly
536ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        managedConn.markReusable();
537ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    } else {
538ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        managedConn.close();
539ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    }
540ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    // check if we can use the same connection for the followup
541ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    if (!followup.getRoute().equals(roureq.getRoute())) {
542ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        releaseConnection();
543ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    }
544ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    roureq = followup;
545ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                }
546ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
547ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                if (managedConn != null && userToken == null) {
548ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    userToken = userTokenHandler.getUserToken(context);
549ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    context.setAttribute(ClientContext.USER_TOKEN, userToken);
550ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    if (userToken != null) {
551ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        managedConn.setState(userToken);
552ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    }
553ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                }
554ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
555ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            } // while not done
556ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
557ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
558ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            // check for entity, release connection if possible
559ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            if ((response == null) || (response.getEntity() == null) ||
560ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                !response.getEntity().isStreaming()) {
561ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                // connection not needed and (assumed to be) in re-usable state
562ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                if (reuse)
563ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    managedConn.markReusable();
564ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                releaseConnection();
565ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            } else {
566ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                // install an auto-release entity
567ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                HttpEntity entity = response.getEntity();
568ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                entity = new BasicManagedEntity(entity, managedConn, reuse);
569ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                response.setEntity(entity);
570ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            }
571ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
572ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            return response;
573ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
574ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        } catch (HttpException ex) {
575ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            abortConnection();
576ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            throw ex;
577ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        } catch (IOException ex) {
578ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            abortConnection();
579ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            throw ex;
580ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        } catch (RuntimeException ex) {
581ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            abortConnection();
582ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            throw ex;
583ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        }
584ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    } // execute
585ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
586ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    /**
587ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * Returns the connection back to the connection manager
588ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * and prepares for retrieving a new connection during
589ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * the next request.
590ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     */
591ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    protected void releaseConnection() {
592ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        // Release the connection through the ManagedConnection instead of the
593ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        // ConnectionManager directly.  This lets the connection control how
594ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        // it is released.
595ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        try {
596ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            managedConn.releaseConnection();
597ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        } catch(IOException ignored) {
598ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            this.log.debug("IOException releasing connection", ignored);
599ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        }
600ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        managedConn = null;
601ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    }
602ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
603ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    /**
604ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * Determines the route for a request.
605ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * Called by {@link #execute}
606ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * to determine the route for either the original or a followup request.
607ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     *
608ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * @param target    the target host for the request.
609ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     *                  Implementations may accept <code>null</code>
610ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     *                  if they can still determine a route, for example
611ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     *                  to a default target or by inspecting the request.
612ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * @param request   the request to execute
613ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * @param context   the context to use for the execution,
614ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     *                  never <code>null</code>
615ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     *
616ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * @return  the route the request should take
617ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     *
618ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * @throws HttpException    in case of a problem
619ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     */
620ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    protected HttpRoute determineRoute(HttpHost    target,
621ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                                           HttpRequest request,
622ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                                           HttpContext context)
623ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        throws HttpException {
624ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
625ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        if (target == null) {
626ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            target = (HttpHost) request.getParams().getParameter(
627ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                ClientPNames.DEFAULT_HOST);
628ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        }
629ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        if (target == null) {
630ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            throw new IllegalStateException
631ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                ("Target host must not be null, or set in parameters.");
632ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        }
633ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
634ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        return this.routePlanner.determineRoute(target, request, context);
635ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    }
636ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
637ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
638ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    /**
639ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * Establishes the target route.
640ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     *
641ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * @param route     the route to establish
642ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * @param context   the context for the request execution
643ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     *
644ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * @throws HttpException    in case of a problem
645ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * @throws IOException      in case of an IO problem
646ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     */
647ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    protected void establishRoute(HttpRoute route, HttpContext context)
648ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        throws HttpException, IOException {
649ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
650ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        HttpRouteDirector rowdy = new BasicRouteDirector();
651ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        int step;
652ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        do {
653ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            HttpRoute fact = managedConn.getRoute();
654ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            step = rowdy.nextStep(route, fact);
655ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
656ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            switch (step) {
657ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
658ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            case HttpRouteDirector.CONNECT_TARGET:
659ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            case HttpRouteDirector.CONNECT_PROXY:
660ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                managedConn.open(route, context, this.params);
661ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                break;
662ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
663ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            case HttpRouteDirector.TUNNEL_TARGET: {
664ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                boolean secure = createTunnelToTarget(route, context);
665ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                this.log.debug("Tunnel to target created.");
666ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                managedConn.tunnelTarget(secure, this.params);
667ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            }   break;
668ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
669ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            case HttpRouteDirector.TUNNEL_PROXY: {
670ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                // The most simple example for this case is a proxy chain
671ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                // of two proxies, where P1 must be tunnelled to P2.
672ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                // route: Source -> P1 -> P2 -> Target (3 hops)
673ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                // fact:  Source -> P1 -> Target       (2 hops)
674ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                final int hop = fact.getHopCount()-1; // the hop to establish
675ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                boolean secure = createTunnelToProxy(route, hop, context);
676ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                this.log.debug("Tunnel to proxy created.");
677ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                managedConn.tunnelProxy(route.getHopTarget(hop),
678ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                                        secure, this.params);
679ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            }   break;
680ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
681ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
682ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            case HttpRouteDirector.LAYER_PROTOCOL:
683ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                managedConn.layerProtocol(context, this.params);
684ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                break;
685ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
686ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            case HttpRouteDirector.UNREACHABLE:
687ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                throw new IllegalStateException
688ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    ("Unable to establish route." +
689ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                     "\nplanned = " + route +
690ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                     "\ncurrent = " + fact);
691ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
692ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            case HttpRouteDirector.COMPLETE:
693ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                // do nothing
694ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                break;
695ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
696ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            default:
697ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                throw new IllegalStateException
698ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    ("Unknown step indicator "+step+" from RouteDirector.");
699ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            } // switch
700ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
701ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        } while (step > HttpRouteDirector.COMPLETE);
702ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
703ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    } // establishConnection
704ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
705ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
706ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    /**
707ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * Creates a tunnel to the target server.
708ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * The connection must be established to the (last) proxy.
709ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * A CONNECT request for tunnelling through the proxy will
710ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * be created and sent, the response received and checked.
711ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * This method does <i>not</i> update the connection with
712ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * information about the tunnel, that is left to the caller.
713ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     *
714ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * @param route     the route to establish
715ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * @param context   the context for request execution
716ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     *
717ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * @return  <code>true</code> if the tunnelled route is secure,
718ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     *          <code>false</code> otherwise.
719ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     *          The implementation here always returns <code>false</code>,
720ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     *          but derived classes may override.
721ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     *
722ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * @throws HttpException    in case of a problem
723ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * @throws IOException      in case of an IO problem
724ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     */
725ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    protected boolean createTunnelToTarget(HttpRoute route,
726ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                                           HttpContext context)
727ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        throws HttpException, IOException {
728ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
729ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        HttpHost proxy = route.getProxyHost();
730ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        HttpHost target = route.getTargetHost();
731ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        HttpResponse response = null;
732ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
733ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        boolean done = false;
734ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        while (!done) {
735ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
736ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            done = true;
737ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
738ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            if (!this.managedConn.isOpen()) {
739ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                this.managedConn.open(route, context, this.params);
740ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            }
741ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
742ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            HttpRequest connect = createConnectRequest(route, context);
743ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            connect.setParams(this.params);
744ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
745ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            // Populate the execution context
746ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            context.setAttribute(ExecutionContext.HTTP_TARGET_HOST,
747ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    target);
748ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            context.setAttribute(ExecutionContext.HTTP_PROXY_HOST,
749ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    proxy);
750ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            context.setAttribute(ExecutionContext.HTTP_CONNECTION,
751ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    managedConn);
752ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            context.setAttribute(ClientContext.TARGET_AUTH_STATE,
753ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    targetAuthState);
754ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            context.setAttribute(ClientContext.PROXY_AUTH_STATE,
755ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    proxyAuthState);
756ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            context.setAttribute(ExecutionContext.HTTP_REQUEST,
757ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    connect);
758ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
759ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            this.requestExec.preProcess(connect, this.httpProcessor, context);
760ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
761ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            response = this.requestExec.execute(connect, this.managedConn, context);
762ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
763ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            response.setParams(this.params);
764ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            this.requestExec.postProcess(response, this.httpProcessor, context);
765ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
766ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            int status = response.getStatusLine().getStatusCode();
767ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            if (status < 200) {
768ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                throw new HttpException("Unexpected response to CONNECT request: " +
769ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        response.getStatusLine());
770ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            }
771ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
772ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            CredentialsProvider credsProvider = (CredentialsProvider)
773ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                context.getAttribute(ClientContext.CREDS_PROVIDER);
774ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
775ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            if (credsProvider != null && HttpClientParams.isAuthenticating(params)) {
776ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                if (this.proxyAuthHandler.isAuthenticationRequested(response, context)) {
777ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
778ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    this.log.debug("Proxy requested authentication");
779ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    Map<String, Header> challenges = this.proxyAuthHandler.getChallenges(
780ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                            response, context);
781ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    try {
782ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        processChallenges(
783ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                                challenges, this.proxyAuthState, this.proxyAuthHandler,
784ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                                response, context);
785ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    } catch (AuthenticationException ex) {
786ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        if (this.log.isWarnEnabled()) {
787ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                            this.log.warn("Authentication error: " +  ex.getMessage());
788ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                            break;
789ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        }
790ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    }
791ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    updateAuthState(this.proxyAuthState, proxy, credsProvider);
792ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
793ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    if (this.proxyAuthState.getCredentials() != null) {
794ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        done = false;
795ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
796ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        // Retry request
797ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        if (this.reuseStrategy.keepAlive(response, context)) {
798ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                            this.log.debug("Connection kept alive");
799ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                            // Consume response content
800ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                            HttpEntity entity = response.getEntity();
801ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                            if (entity != null) {
802ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                                entity.consumeContent();
803ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                            }
804ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        } else {
805ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                            this.managedConn.close();
806ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        }
807ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
808ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    }
809ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
810ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                } else {
811ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    // Reset proxy auth scope
812ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    this.proxyAuthState.setAuthScope(null);
813ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                }
814ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            }
815ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        }
816ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
817ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        int status = response.getStatusLine().getStatusCode(); // can't be null
818ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
819ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        if (status > 299) {
820ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
821ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            // Buffer response content
822ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            HttpEntity entity = response.getEntity();
823ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            if (entity != null) {
824ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                response.setEntity(new BufferedHttpEntity(entity));
825ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            }
826ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
827ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            this.managedConn.close();
828ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            throw new TunnelRefusedException("CONNECT refused by proxy: " +
829ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    response.getStatusLine(), response);
830ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        }
831ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
832ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        this.managedConn.markReusable();
833ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
834ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        // How to decide on security of the tunnelled connection?
835ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        // The socket factory knows only about the segment to the proxy.
836ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        // Even if that is secure, the hop to the target may be insecure.
837ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        // Leave it to derived classes, consider insecure by default here.
838ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        return false;
839ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
840ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    } // createTunnelToTarget
841ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
842ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
843ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
844ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    /**
845ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * Creates a tunnel to an intermediate proxy.
846ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * This method is <i>not</i> implemented in this class.
847ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * It just throws an exception here.
848ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     *
849ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * @param route     the route to establish
850ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * @param hop       the hop in the route to establish now.
851ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     *                  <code>route.getHopTarget(hop)</code>
852ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     *                  will return the proxy to tunnel to.
853ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * @param context   the context for request execution
854ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     *
855ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * @return  <code>true</code> if the partially tunnelled connection
856ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     *          is secure, <code>false</code> otherwise.
857ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     *
858ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * @throws HttpException    in case of a problem
859ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * @throws IOException      in case of an IO problem
860ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     */
861ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    protected boolean createTunnelToProxy(HttpRoute route, int hop,
862ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                                          HttpContext context)
863ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        throws HttpException, IOException {
864ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
865ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        // Have a look at createTunnelToTarget and replicate the parts
866ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        // you need in a custom derived class. If your proxies don't require
867ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        // authentication, it is not too hard. But for the stock version of
868ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        // HttpClient, we cannot make such simplifying assumptions and would
869ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        // have to include proxy authentication code. The HttpComponents team
870ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        // is currently not in a position to support rarely used code of this
871ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        // complexity. Feel free to submit patches that refactor the code in
872ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        // createTunnelToTarget to facilitate re-use for proxy tunnelling.
873ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
874ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        throw new UnsupportedOperationException
875ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            ("Proxy chains are not supported.");
876ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    }
877ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
878ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
879ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
880ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    /**
881ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * Creates the CONNECT request for tunnelling.
882ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * Called by {@link #createTunnelToTarget createTunnelToTarget}.
883ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     *
884ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * @param route     the route to establish
885ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * @param context   the context for request execution
886ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     *
887ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * @return  the CONNECT request for tunnelling
888ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     */
889ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    protected HttpRequest createConnectRequest(HttpRoute route,
890ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                                               HttpContext context) {
891ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        // see RFC 2817, section 5.2 and
892ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        // INTERNET-DRAFT: Tunneling TCP based protocols through
893ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        // Web proxy servers
894ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
895ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        HttpHost target = route.getTargetHost();
896ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
897ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        String host = target.getHostName();
898ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        int port = target.getPort();
899ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        if (port < 0) {
900ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            Scheme scheme = connManager.getSchemeRegistry().
901ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                getScheme(target.getSchemeName());
902ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            port = scheme.getDefaultPort();
903ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        }
904ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
905ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        StringBuilder buffer = new StringBuilder(host.length() + 6);
906ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        buffer.append(host);
907ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        buffer.append(':');
908ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        buffer.append(Integer.toString(port));
909ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
910ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        String authority = buffer.toString();
911ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        ProtocolVersion ver = HttpProtocolParams.getVersion(params);
912ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        HttpRequest req = new BasicHttpRequest
913ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            ("CONNECT", authority, ver);
914ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
915ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        return req;
916ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    }
917ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
918ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
919ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    /**
920ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * Analyzes a response to check need for a followup.
921ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     *
922ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * @param roureq    the request and route.
923ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * @param response  the response to analayze
924ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * @param context   the context used for the current request execution
925ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     *
926ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * @return  the followup request and route if there is a followup, or
927ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     *          <code>null</code> if the response should be returned as is
928ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     *
929ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * @throws HttpException    in case of a problem
930ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * @throws IOException      in case of an IO problem
931ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     */
932ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    protected RoutedRequest handleResponse(RoutedRequest roureq,
933ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                                           HttpResponse response,
934ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                                           HttpContext context)
935ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        throws HttpException, IOException {
936ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
937ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        HttpRoute route = roureq.getRoute();
938ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        RequestWrapper request = roureq.getRequest();
939ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
940ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        HttpParams params = request.getParams();
941ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        if (HttpClientParams.isRedirecting(params) &&
942ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                this.redirectHandler.isRedirectRequested(response, context)) {
943ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
944ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            if (redirectCount >= maxRedirects) {
945ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                throw new RedirectException("Maximum redirects ("
946ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        + maxRedirects + ") exceeded");
947ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            }
948ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            redirectCount++;
949ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
950ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            // Virtual host cannot be used any longer
951ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            virtualHost = null;
952ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
953ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            URI uri = this.redirectHandler.getLocationURI(response, context);
954ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
955ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            HttpHost newTarget = new HttpHost(
956ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    uri.getHost(),
957ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    uri.getPort(),
958ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    uri.getScheme());
959ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
960ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            // Unset auth scope
961ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            targetAuthState.setAuthScope(null);
962ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            proxyAuthState.setAuthScope(null);
963ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
964ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            // Invalidate auth states if redirecting to another host
965ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            if (!route.getTargetHost().equals(newTarget)) {
966ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                targetAuthState.invalidate();
967ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                AuthScheme authScheme = proxyAuthState.getAuthScheme();
968ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                if (authScheme != null && authScheme.isConnectionBased()) {
969ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    proxyAuthState.invalidate();
970ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                }
971ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            }
972ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
973ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            HttpRedirect redirect = new HttpRedirect(request.getMethod(), uri);
974ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            HttpRequest orig = request.getOriginal();
975ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            redirect.setHeaders(orig.getAllHeaders());
976ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
977ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            RequestWrapper wrapper = new RequestWrapper(redirect);
978ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            wrapper.setParams(params);
979ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
980ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            HttpRoute newRoute = determineRoute(newTarget, wrapper, context);
981ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            RoutedRequest newRequest = new RoutedRequest(wrapper, newRoute);
982ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
983ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            if (this.log.isDebugEnabled()) {
984ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                this.log.debug("Redirecting to '" + uri + "' via " + newRoute);
985ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            }
986ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
987ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            return newRequest;
988ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        }
989ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
990ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        CredentialsProvider credsProvider = (CredentialsProvider)
991ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            context.getAttribute(ClientContext.CREDS_PROVIDER);
992ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
993ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        if (credsProvider != null && HttpClientParams.isAuthenticating(params)) {
994ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
995ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            if (this.targetAuthHandler.isAuthenticationRequested(response, context)) {
996ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
997ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                HttpHost target = (HttpHost)
998ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    context.getAttribute(ExecutionContext.HTTP_TARGET_HOST);
999ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                if (target == null) {
1000ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    target = route.getTargetHost();
1001ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                }
1002ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
1003ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                this.log.debug("Target requested authentication");
1004ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                Map<String, Header> challenges = this.targetAuthHandler.getChallenges(
1005ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        response, context);
1006ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                try {
1007ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    processChallenges(challenges,
1008ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                            this.targetAuthState, this.targetAuthHandler,
1009ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                            response, context);
1010ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                } catch (AuthenticationException ex) {
1011ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    if (this.log.isWarnEnabled()) {
1012ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        this.log.warn("Authentication error: " +  ex.getMessage());
1013ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        return null;
1014ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    }
1015ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                }
1016ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                updateAuthState(this.targetAuthState, target, credsProvider);
1017ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
1018ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                if (this.targetAuthState.getCredentials() != null) {
1019ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    // Re-try the same request via the same route
1020ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    return roureq;
1021ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                } else {
1022ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    return null;
1023ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                }
1024ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            } else {
1025ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                // Reset target auth scope
1026ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                this.targetAuthState.setAuthScope(null);
1027ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            }
1028ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
1029ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            if (this.proxyAuthHandler.isAuthenticationRequested(response, context)) {
1030ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
1031ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                HttpHost proxy = route.getProxyHost();
1032ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
1033ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                this.log.debug("Proxy requested authentication");
1034ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                Map<String, Header> challenges = this.proxyAuthHandler.getChallenges(
1035ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        response, context);
1036ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                try {
1037ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    processChallenges(challenges,
1038ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                            this.proxyAuthState, this.proxyAuthHandler,
1039ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                            response, context);
1040ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                } catch (AuthenticationException ex) {
1041ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    if (this.log.isWarnEnabled()) {
1042ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        this.log.warn("Authentication error: " +  ex.getMessage());
1043ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                        return null;
1044ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    }
1045ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                }
1046ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                updateAuthState(this.proxyAuthState, proxy, credsProvider);
1047ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
1048ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                if (this.proxyAuthState.getCredentials() != null) {
1049ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    // Re-try the same request via the same route
1050ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    return roureq;
1051ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                } else {
1052ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    return null;
1053ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                }
1054ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            } else {
1055ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                // Reset proxy auth scope
1056ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                this.proxyAuthState.setAuthScope(null);
1057ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            }
1058ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        }
1059ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        return null;
1060ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    } // handleResponse
1061ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
1062ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
1063ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    /**
1064ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * Shuts down the connection.
1065ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * This method is called from a <code>catch</code> block in
1066ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     * {@link #execute execute} during exception handling.
1067ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel     */
1068ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    private void abortConnection() {
1069ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        ManagedClientConnection mcc = managedConn;
1070ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        if (mcc != null) {
1071ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            // we got here as the result of an exception
1072ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            // no response will be returned, release the connection
1073ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            managedConn = null;
1074ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            try {
1075ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                mcc.abortConnection();
1076ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            } catch (IOException ex) {
1077ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                if (this.log.isDebugEnabled()) {
1078ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    this.log.debug(ex.getMessage(), ex);
1079ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                }
1080ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            }
1081ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            // ensure the connection manager properly releases this connection
1082ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            try {
1083ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                mcc.releaseConnection();
1084ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            } catch(IOException ignored) {
1085ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                this.log.debug("Error releasing connection", ignored);
1086ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            }
1087ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        }
1088ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    } // abortConnection
1089ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
1090ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
1091ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    private void processChallenges(
1092ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            final Map<String, Header> challenges,
1093ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            final AuthState authState,
1094ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            final AuthenticationHandler authHandler,
1095ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            final HttpResponse response,
1096ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            final HttpContext context)
1097ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                throws MalformedChallengeException, AuthenticationException {
1098ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
1099ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        AuthScheme authScheme = authState.getAuthScheme();
1100ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        if (authScheme == null) {
1101ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            // Authentication not attempted before
1102ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            authScheme = authHandler.selectScheme(challenges, response, context);
1103ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            authState.setAuthScheme(authScheme);
1104ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        }
1105ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        String id = authScheme.getSchemeName();
1106ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
1107ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        Header challenge = challenges.get(id.toLowerCase(Locale.ENGLISH));
1108ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        if (challenge == null) {
1109ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            throw new AuthenticationException(id +
1110ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                " authorization challenge expected, but not found");
1111ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        }
1112ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        authScheme.processChallenge(challenge);
1113ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        this.log.debug("Authorization challenge processed");
1114ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    }
1115ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
1116ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
1117ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    private void updateAuthState(
1118ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            final AuthState authState,
1119ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            final HttpHost host,
1120ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            final CredentialsProvider credsProvider) {
1121ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
1122ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        if (!authState.isValid()) {
1123ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            return;
1124ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        }
1125ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
1126ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        String hostname = host.getHostName();
1127ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        int port = host.getPort();
1128ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        if (port < 0) {
1129ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            Scheme scheme = connManager.getSchemeRegistry().getScheme(host);
1130ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            port = scheme.getDefaultPort();
1131ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        }
1132ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
1133ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        AuthScheme authScheme = authState.getAuthScheme();
1134ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        AuthScope authScope = new AuthScope(
1135ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                hostname,
1136ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                port,
1137ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                authScheme.getRealm(),
1138ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                authScheme.getSchemeName());
1139ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
1140ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        if (this.log.isDebugEnabled()) {
1141ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            this.log.debug("Authentication scope: " + authScope);
1142ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        }
1143ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        Credentials creds = authState.getCredentials();
1144ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        if (creds == null) {
1145ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            creds = credsProvider.getCredentials(authScope);
1146ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            if (this.log.isDebugEnabled()) {
1147ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                if (creds != null) {
1148ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    this.log.debug("Found credentials");
1149ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                } else {
1150ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                    this.log.debug("Credentials not found");
1151ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                }
1152ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            }
1153ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        } else {
1154ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            if (authScheme.isComplete()) {
1155ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                this.log.debug("Authentication failed");
1156ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel                creds = null;
1157ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel            }
1158ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        }
1159ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        authState.setAuthScope(authScope);
1160ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel        authState.setCredentials(creds);
1161ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel    }
1162ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel
1163ef24e85f87c30d8d1cbe6f7ca0c29a11bd7e4be4Jan Berkel} // class DefaultClientRequestDirector
1164