1 /*
2  * ====================================================================
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  * ====================================================================
20  *
21  * This software consists of voluntary contributions made by many
22  * individuals on behalf of the Apache Software Foundation.  For more
23  * information on the Apache Software Foundation, please see
24  * <http://www.apache.org/>.
25  *
26  */
27 
28 package ch.boye.httpclientandroidlib.impl.client;
29 
30 import java.io.IOException;
31 import java.lang.reflect.UndeclaredThrowableException;
32 
33 import ch.boye.httpclientandroidlib.androidextra.HttpClientAndroidLog;
34 /* LogFactory removed by HttpClient for Android script. */
35 import ch.boye.httpclientandroidlib.ConnectionReuseStrategy;
36 import ch.boye.httpclientandroidlib.HttpException;
37 import ch.boye.httpclientandroidlib.HttpHost;
38 import ch.boye.httpclientandroidlib.HttpRequest;
39 import ch.boye.httpclientandroidlib.HttpRequestInterceptor;
40 import ch.boye.httpclientandroidlib.HttpResponseInterceptor;
41 import ch.boye.httpclientandroidlib.annotation.GuardedBy;
42 import ch.boye.httpclientandroidlib.annotation.ThreadSafe;
43 import ch.boye.httpclientandroidlib.auth.AuthSchemeRegistry;
44 import ch.boye.httpclientandroidlib.client.AuthenticationHandler;
45 import ch.boye.httpclientandroidlib.client.AuthenticationStrategy;
46 import ch.boye.httpclientandroidlib.client.BackoffManager;
47 import ch.boye.httpclientandroidlib.client.ClientProtocolException;
48 import ch.boye.httpclientandroidlib.client.ConnectionBackoffStrategy;
49 import ch.boye.httpclientandroidlib.client.CookieStore;
50 import ch.boye.httpclientandroidlib.client.CredentialsProvider;
51 import ch.boye.httpclientandroidlib.client.HttpRequestRetryHandler;
52 import ch.boye.httpclientandroidlib.client.RedirectHandler;
53 import ch.boye.httpclientandroidlib.client.RedirectStrategy;
54 import ch.boye.httpclientandroidlib.client.RequestDirector;
55 import ch.boye.httpclientandroidlib.client.UserTokenHandler;
56 import ch.boye.httpclientandroidlib.client.config.RequestConfig;
57 import ch.boye.httpclientandroidlib.client.methods.CloseableHttpResponse;
58 import ch.boye.httpclientandroidlib.client.params.AuthPolicy;
59 import ch.boye.httpclientandroidlib.client.params.ClientPNames;
60 import ch.boye.httpclientandroidlib.client.params.CookiePolicy;
61 import ch.boye.httpclientandroidlib.client.params.HttpClientParamConfig;
62 import ch.boye.httpclientandroidlib.client.protocol.ClientContext;
63 import ch.boye.httpclientandroidlib.conn.ClientConnectionManager;
64 import ch.boye.httpclientandroidlib.conn.ClientConnectionManagerFactory;
65 import ch.boye.httpclientandroidlib.conn.ConnectionKeepAliveStrategy;
66 import ch.boye.httpclientandroidlib.conn.routing.HttpRoute;
67 import ch.boye.httpclientandroidlib.conn.routing.HttpRoutePlanner;
68 import ch.boye.httpclientandroidlib.conn.scheme.SchemeRegistry;
69 import ch.boye.httpclientandroidlib.cookie.CookieSpecRegistry;
70 import ch.boye.httpclientandroidlib.impl.DefaultConnectionReuseStrategy;
71 import ch.boye.httpclientandroidlib.impl.auth.BasicSchemeFactory;
72 import ch.boye.httpclientandroidlib.impl.auth.DigestSchemeFactory;
73 /* KerberosSchemeFactory removed by HttpClient for Android script. */
74 import ch.boye.httpclientandroidlib.impl.auth.NTLMSchemeFactory;
75 /* SPNegoSchemeFactory removed by HttpClient for Android script. */
76 import ch.boye.httpclientandroidlib.impl.conn.BasicClientConnectionManager;
77 import ch.boye.httpclientandroidlib.impl.conn.DefaultHttpRoutePlanner;
78 import ch.boye.httpclientandroidlib.impl.conn.SchemeRegistryFactory;
79 import ch.boye.httpclientandroidlib.impl.cookie.BestMatchSpecFactory;
80 import ch.boye.httpclientandroidlib.impl.cookie.BrowserCompatSpecFactory;
81 import ch.boye.httpclientandroidlib.impl.cookie.IgnoreSpecFactory;
82 import ch.boye.httpclientandroidlib.impl.cookie.NetscapeDraftSpecFactory;
83 import ch.boye.httpclientandroidlib.impl.cookie.RFC2109SpecFactory;
84 import ch.boye.httpclientandroidlib.impl.cookie.RFC2965SpecFactory;
85 import ch.boye.httpclientandroidlib.params.HttpParams;
86 import ch.boye.httpclientandroidlib.protocol.BasicHttpContext;
87 import ch.boye.httpclientandroidlib.protocol.BasicHttpProcessor;
88 import ch.boye.httpclientandroidlib.protocol.DefaultedHttpContext;
89 import ch.boye.httpclientandroidlib.protocol.HttpContext;
90 import ch.boye.httpclientandroidlib.protocol.HttpProcessor;
91 import ch.boye.httpclientandroidlib.protocol.HttpRequestExecutor;
92 import ch.boye.httpclientandroidlib.protocol.ImmutableHttpProcessor;
93 import ch.boye.httpclientandroidlib.util.Args;
94 
95 /**
96  * Base class for {@link ch.boye.httpclientandroidlib.client.HttpClient} implementations.
97  * This class acts as a facade to a number of special purpose handler or
98  * strategy implementations responsible for handling of a particular aspect
99  * of the HTTP protocol such as redirect or authentication handling or
100  * making decision about connection persistence and keep alive duration.
101  * This enables the users to selectively replace default implementation
102  * of those aspects with custom, application specific ones. This class
103  * also provides factory methods to instantiate those objects:
104  * <ul>
105  *   <li>{@link HttpRequestExecutor}</li> object used to transmit messages
106  *    over HTTP connections. The {@link #createRequestExecutor()} must be
107  *    implemented by concrete super classes to instantiate this object.
108  *   <li>{@link BasicHttpProcessor}</li> object to manage a list of protocol
109  *    interceptors and apply cross-cutting protocol logic to all incoming
110  *    and outgoing HTTP messages. The {@link #createHttpProcessor()} must be
111  *    implemented by concrete super classes to instantiate this object.
112  *   <li>{@link HttpRequestRetryHandler}</li> object used to decide whether
113  *    or not a failed HTTP request is safe to retry automatically.
114  *    The {@link #createHttpRequestRetryHandler()} must be
115  *    implemented by concrete super classes to instantiate this object.
116  *   <li>{@link ClientConnectionManager}</li> object used to manage
117  *    persistent HTTP connections.
118  *   <li>{@link ConnectionReuseStrategy}</li> object used to decide whether
119  *    or not a HTTP connection can be kept alive and re-used for subsequent
120  *    HTTP requests. The {@link #createConnectionReuseStrategy()} must be
121  *    implemented by concrete super classes to instantiate this object.
122  *   <li>{@link ConnectionKeepAliveStrategy}</li> object used to decide how
123  *    long a persistent HTTP connection can be kept alive.
124  *    The {@link #createConnectionKeepAliveStrategy()} must be
125  *    implemented by concrete super classes to instantiate this object.
126  *   <li>{@link CookieSpecRegistry}</li> object used to maintain a list of
127  *    supported cookie specifications.
128  *    The {@link #createCookieSpecRegistry()} must be implemented by concrete
129  *    super classes to instantiate this object.
130  *   <li>{@link CookieStore}</li> object used to maintain a collection of
131  *    cookies. The {@link #createCookieStore()} must be implemented by
132  *    concrete super classes to instantiate this object.
133  *   <li>{@link AuthSchemeRegistry}</li> object used to maintain a list of
134  *    supported authentication schemes.
135  *    The {@link #createAuthSchemeRegistry()} must be implemented by concrete
136  *    super classes to instantiate this object.
137  *   <li>{@link CredentialsProvider}</li> object used to maintain
138  *    a collection user credentials. The {@link #createCredentialsProvider()}
139  *    must be implemented by concrete super classes to instantiate
140  *    this object.
141  *   <li>{@link AuthenticationStrategy}</li> object used to authenticate
142  *    against the target host.
143  *    The {@link #createTargetAuthenticationStrategy()} must be implemented
144  *    by concrete super classes to instantiate this object.
145  *   <li>{@link AuthenticationStrategy}</li> object used to authenticate
146  *    against the proxy host.
147  *    The {@link #createProxyAuthenticationStrategy()} must be implemented
148  *    by concrete super classes to instantiate this object.
149  *   <li>{@link HttpRoutePlanner}</li> object used to calculate a route
150  *    for establishing a connection to the target host. The route
151  *    may involve multiple intermediate hops.
152  *    The {@link #createHttpRoutePlanner()} must be implemented
153  *    by concrete super classes to instantiate this object.
154  *   <li>{@link RedirectStrategy}</li> object used to determine if an HTTP
155  *    request should be redirected to a new location in response to an HTTP
156  *    response received from the target server.
157  *   <li>{@link UserTokenHandler}</li> object used to determine if the
158  *    execution context is user identity specific.
159  *    The {@link #createUserTokenHandler()} must be implemented by
160  *    concrete super classes to instantiate this object.
161  * </ul>
162  * <p>
163  *   This class also maintains a list of protocol interceptors intended
164  *   for processing outgoing requests and incoming responses and provides
165  *   methods for managing those interceptors. New protocol interceptors can be
166  *   introduced to the protocol processor chain or removed from it if needed.
167  *   Internally protocol interceptors are stored in a simple
168  *   {@link java.util.ArrayList}. They are executed in the same natural order
169  *   as they are added to the list.
170  * <p>
171  *   AbstractHttpClient is thread safe. It is recommended that the same
172  *   instance of this class is reused for multiple request executions.
173  *   When an instance of DefaultHttpClient is no longer needed and is about
174  *   to go out of scope the connection manager associated with it must be
175  *   shut down by calling {@link ClientConnectionManager#shutdown()}!
176  *
177  * @since 4.0
178  *
179  * @deprecated (4.3) use {@link HttpClientBuilder}.
180  */
181 @ThreadSafe
182 @Deprecated
183 public abstract class AbstractHttpClient extends CloseableHttpClient {
184 
185     public HttpClientAndroidLog log = new HttpClientAndroidLog(getClass());
186 
187     /** The parameters. */
188     @GuardedBy("this")
189     private HttpParams defaultParams;
190 
191     /** The request executor. */
192     @GuardedBy("this")
193     private HttpRequestExecutor requestExec;
194 
195     /** The connection manager. */
196     @GuardedBy("this")
197     private ClientConnectionManager connManager;
198 
199     /** The connection re-use strategy. */
200     @GuardedBy("this")
201     private ConnectionReuseStrategy reuseStrategy;
202 
203     /** The connection keep-alive strategy. */
204     @GuardedBy("this")
205     private ConnectionKeepAliveStrategy keepAliveStrategy;
206 
207     /** The cookie spec registry. */
208     @GuardedBy("this")
209     private CookieSpecRegistry supportedCookieSpecs;
210 
211     /** The authentication scheme registry. */
212     @GuardedBy("this")
213     private AuthSchemeRegistry supportedAuthSchemes;
214 
215     /** The HTTP protocol processor and its immutable copy. */
216     @GuardedBy("this")
217     private BasicHttpProcessor mutableProcessor;
218 
219     @GuardedBy("this")
220     private ImmutableHttpProcessor protocolProcessor;
221 
222     /** The request retry handler. */
223     @GuardedBy("this")
224     private HttpRequestRetryHandler retryHandler;
225 
226     /** The redirect handler. */
227     @GuardedBy("this")
228     private RedirectStrategy redirectStrategy;
229 
230     /** The target authentication handler. */
231     @GuardedBy("this")
232     private AuthenticationStrategy targetAuthStrategy;
233 
234     /** The proxy authentication handler. */
235     @GuardedBy("this")
236     private AuthenticationStrategy proxyAuthStrategy;
237 
238     /** The cookie store. */
239     @GuardedBy("this")
240     private CookieStore cookieStore;
241 
242     /** The credentials provider. */
243     @GuardedBy("this")
244     private CredentialsProvider credsProvider;
245 
246     /** The route planner. */
247     @GuardedBy("this")
248     private HttpRoutePlanner routePlanner;
249 
250     /** The user token handler. */
251     @GuardedBy("this")
252     private UserTokenHandler userTokenHandler;
253 
254     /** The connection backoff strategy. */
255     @GuardedBy("this")
256     private ConnectionBackoffStrategy connectionBackoffStrategy;
257 
258     /** The backoff manager. */
259     @GuardedBy("this")
260     private BackoffManager backoffManager;
261 
262     /**
263      * Creates a new HTTP client.
264      *
265      * @param conman    the connection manager
266      * @param params    the parameters
267      */
AbstractHttpClient( final ClientConnectionManager conman, final HttpParams params)268     protected AbstractHttpClient(
269             final ClientConnectionManager conman,
270             final HttpParams params) {
271         super();
272         defaultParams        = params;
273         connManager          = conman;
274     } // constructor
275 
276 
createHttpParams()277     protected abstract HttpParams createHttpParams();
278 
279 
createHttpProcessor()280     protected abstract BasicHttpProcessor createHttpProcessor();
281 
282 
createHttpContext()283     protected HttpContext createHttpContext() {
284         final HttpContext context = new BasicHttpContext();
285         context.setAttribute(
286                 ClientContext.SCHEME_REGISTRY,
287                 getConnectionManager().getSchemeRegistry());
288         context.setAttribute(
289                 ClientContext.AUTHSCHEME_REGISTRY,
290                 getAuthSchemes());
291         context.setAttribute(
292                 ClientContext.COOKIESPEC_REGISTRY,
293                 getCookieSpecs());
294         context.setAttribute(
295                 ClientContext.COOKIE_STORE,
296                 getCookieStore());
297         context.setAttribute(
298                 ClientContext.CREDS_PROVIDER,
299                 getCredentialsProvider());
300         return context;
301     }
302 
303 
createClientConnectionManager()304     protected ClientConnectionManager createClientConnectionManager() {
305         final SchemeRegistry registry = SchemeRegistryFactory.createDefault();
306 
307         ClientConnectionManager connManager = null;
308         final HttpParams params = getParams();
309 
310         ClientConnectionManagerFactory factory = null;
311 
312         final String className = (String) params.getParameter(
313                 ClientPNames.CONNECTION_MANAGER_FACTORY_CLASS_NAME);
314         if (className != null) {
315             try {
316                 final Class<?> clazz = Class.forName(className);
317                 factory = (ClientConnectionManagerFactory) clazz.newInstance();
318             } catch (final ClassNotFoundException ex) {
319                 throw new IllegalStateException("Invalid class name: " + className);
320             } catch (final IllegalAccessException ex) {
321                 throw new IllegalAccessError(ex.getMessage());
322             } catch (final InstantiationException ex) {
323                 throw new InstantiationError(ex.getMessage());
324             }
325         }
326         if (factory != null) {
327             connManager = factory.newInstance(params, registry);
328         } else {
329             connManager = new BasicClientConnectionManager(registry);
330         }
331 
332         return connManager;
333     }
334 
335 
createAuthSchemeRegistry()336     protected AuthSchemeRegistry createAuthSchemeRegistry() {
337         final AuthSchemeRegistry registry = new AuthSchemeRegistry();
338         registry.register(
339                 AuthPolicy.BASIC,
340                 new BasicSchemeFactory());
341         registry.register(
342                 AuthPolicy.DIGEST,
343                 new DigestSchemeFactory());
344         registry.register(
345                 AuthPolicy.NTLM,
346                 new NTLMSchemeFactory());
347         /* SPNegoSchemeFactory removed by HttpClient for Android script. */
348         /* KerberosSchemeFactory removed by HttpClient for Android script. */
349         return registry;
350     }
351 
352 
createCookieSpecRegistry()353     protected CookieSpecRegistry createCookieSpecRegistry() {
354         final CookieSpecRegistry registry = new CookieSpecRegistry();
355         registry.register(
356                 CookiePolicy.BEST_MATCH,
357                 new BestMatchSpecFactory());
358         registry.register(
359                 CookiePolicy.BROWSER_COMPATIBILITY,
360                 new BrowserCompatSpecFactory());
361         registry.register(
362                 CookiePolicy.NETSCAPE,
363                 new NetscapeDraftSpecFactory());
364         registry.register(
365                 CookiePolicy.RFC_2109,
366                 new RFC2109SpecFactory());
367         registry.register(
368                 CookiePolicy.RFC_2965,
369                 new RFC2965SpecFactory());
370         registry.register(
371                 CookiePolicy.IGNORE_COOKIES,
372                 new IgnoreSpecFactory());
373         return registry;
374     }
375 
createRequestExecutor()376     protected HttpRequestExecutor createRequestExecutor() {
377         return new HttpRequestExecutor();
378     }
379 
createConnectionReuseStrategy()380     protected ConnectionReuseStrategy createConnectionReuseStrategy() {
381         return new DefaultConnectionReuseStrategy();
382     }
383 
createConnectionKeepAliveStrategy()384     protected ConnectionKeepAliveStrategy createConnectionKeepAliveStrategy() {
385         return new DefaultConnectionKeepAliveStrategy();
386     }
387 
createHttpRequestRetryHandler()388     protected HttpRequestRetryHandler createHttpRequestRetryHandler() {
389         return new DefaultHttpRequestRetryHandler();
390     }
391 
392     /**
393      * @deprecated (4.1) do not use
394      */
395     @Deprecated
createRedirectHandler()396     protected RedirectHandler createRedirectHandler() {
397         return new DefaultRedirectHandler();
398     }
399 
createTargetAuthenticationStrategy()400     protected AuthenticationStrategy createTargetAuthenticationStrategy() {
401         return new TargetAuthenticationStrategy();
402     }
403 
404     /**
405      * @deprecated (4.2) do not use
406      */
407     @Deprecated
createTargetAuthenticationHandler()408     protected AuthenticationHandler createTargetAuthenticationHandler() {
409         return new DefaultTargetAuthenticationHandler();
410     }
411 
createProxyAuthenticationStrategy()412     protected AuthenticationStrategy createProxyAuthenticationStrategy() {
413         return new ProxyAuthenticationStrategy();
414     }
415 
416     /**
417      * @deprecated (4.2) do not use
418      */
419     @Deprecated
createProxyAuthenticationHandler()420     protected AuthenticationHandler createProxyAuthenticationHandler() {
421         return new DefaultProxyAuthenticationHandler();
422     }
423 
createCookieStore()424     protected CookieStore createCookieStore() {
425         return new BasicCookieStore();
426     }
427 
createCredentialsProvider()428     protected CredentialsProvider createCredentialsProvider() {
429         return new BasicCredentialsProvider();
430     }
431 
createHttpRoutePlanner()432     protected HttpRoutePlanner createHttpRoutePlanner() {
433         return new DefaultHttpRoutePlanner(getConnectionManager().getSchemeRegistry());
434     }
435 
createUserTokenHandler()436     protected UserTokenHandler createUserTokenHandler() {
437         return new DefaultUserTokenHandler();
438     }
439 
440     // non-javadoc, see interface HttpClient
getParams()441     public synchronized final HttpParams getParams() {
442         if (defaultParams == null) {
443             defaultParams = createHttpParams();
444         }
445         return defaultParams;
446     }
447 
448     /**
449      * Replaces the parameters.
450      * The implementation here does not update parameters of dependent objects.
451      *
452      * @param params    the new default parameters
453      */
setParams(final HttpParams params)454     public synchronized void setParams(final HttpParams params) {
455         defaultParams = params;
456     }
457 
458 
getConnectionManager()459     public synchronized final ClientConnectionManager getConnectionManager() {
460         if (connManager == null) {
461             connManager = createClientConnectionManager();
462         }
463         return connManager;
464     }
465 
466 
getRequestExecutor()467     public synchronized final HttpRequestExecutor getRequestExecutor() {
468         if (requestExec == null) {
469             requestExec = createRequestExecutor();
470         }
471         return requestExec;
472     }
473 
474 
getAuthSchemes()475     public synchronized final AuthSchemeRegistry getAuthSchemes() {
476         if (supportedAuthSchemes == null) {
477             supportedAuthSchemes = createAuthSchemeRegistry();
478         }
479         return supportedAuthSchemes;
480     }
481 
setAuthSchemes(final AuthSchemeRegistry registry)482     public synchronized void setAuthSchemes(final AuthSchemeRegistry registry) {
483         supportedAuthSchemes = registry;
484     }
485 
getConnectionBackoffStrategy()486     public synchronized final ConnectionBackoffStrategy getConnectionBackoffStrategy() {
487         return connectionBackoffStrategy;
488     }
489 
setConnectionBackoffStrategy(final ConnectionBackoffStrategy strategy)490     public synchronized void setConnectionBackoffStrategy(final ConnectionBackoffStrategy strategy) {
491         connectionBackoffStrategy = strategy;
492     }
493 
getCookieSpecs()494     public synchronized final CookieSpecRegistry getCookieSpecs() {
495         if (supportedCookieSpecs == null) {
496             supportedCookieSpecs = createCookieSpecRegistry();
497         }
498         return supportedCookieSpecs;
499     }
500 
getBackoffManager()501     public synchronized final BackoffManager getBackoffManager() {
502         return backoffManager;
503     }
504 
setBackoffManager(final BackoffManager manager)505     public synchronized void setBackoffManager(final BackoffManager manager) {
506         backoffManager = manager;
507     }
508 
setCookieSpecs(final CookieSpecRegistry registry)509     public synchronized void setCookieSpecs(final CookieSpecRegistry registry) {
510         supportedCookieSpecs = registry;
511     }
512 
getConnectionReuseStrategy()513     public synchronized final ConnectionReuseStrategy getConnectionReuseStrategy() {
514         if (reuseStrategy == null) {
515             reuseStrategy = createConnectionReuseStrategy();
516         }
517         return reuseStrategy;
518     }
519 
520 
setReuseStrategy(final ConnectionReuseStrategy strategy)521     public synchronized void setReuseStrategy(final ConnectionReuseStrategy strategy) {
522         this.reuseStrategy = strategy;
523     }
524 
525 
getConnectionKeepAliveStrategy()526     public synchronized final ConnectionKeepAliveStrategy getConnectionKeepAliveStrategy() {
527         if (keepAliveStrategy == null) {
528             keepAliveStrategy = createConnectionKeepAliveStrategy();
529         }
530         return keepAliveStrategy;
531     }
532 
533 
setKeepAliveStrategy(final ConnectionKeepAliveStrategy strategy)534     public synchronized void setKeepAliveStrategy(final ConnectionKeepAliveStrategy strategy) {
535         this.keepAliveStrategy = strategy;
536     }
537 
538 
getHttpRequestRetryHandler()539     public synchronized final HttpRequestRetryHandler getHttpRequestRetryHandler() {
540         if (retryHandler == null) {
541             retryHandler = createHttpRequestRetryHandler();
542         }
543         return retryHandler;
544     }
545 
setHttpRequestRetryHandler(final HttpRequestRetryHandler handler)546     public synchronized void setHttpRequestRetryHandler(final HttpRequestRetryHandler handler) {
547         this.retryHandler = handler;
548     }
549 
550     /**
551      * @deprecated (4.1) do not use
552      */
553     @Deprecated
getRedirectHandler()554     public synchronized final RedirectHandler getRedirectHandler() {
555         return createRedirectHandler();
556     }
557 
558     /**
559      * @deprecated (4.1) do not use
560      */
561     @Deprecated
setRedirectHandler(final RedirectHandler handler)562     public synchronized void setRedirectHandler(final RedirectHandler handler) {
563         this.redirectStrategy = new DefaultRedirectStrategyAdaptor(handler);
564     }
565 
566     /**
567      * @since 4.1
568      */
getRedirectStrategy()569     public synchronized final RedirectStrategy getRedirectStrategy() {
570         if (redirectStrategy == null) {
571             redirectStrategy = new DefaultRedirectStrategy();
572         }
573         return redirectStrategy;
574     }
575 
576     /**
577      * @since 4.1
578      */
setRedirectStrategy(final RedirectStrategy strategy)579     public synchronized void setRedirectStrategy(final RedirectStrategy strategy) {
580         this.redirectStrategy = strategy;
581     }
582 
583     /**
584      * @deprecated (4.2) do not use
585      */
586     @Deprecated
getTargetAuthenticationHandler()587     public synchronized final AuthenticationHandler getTargetAuthenticationHandler() {
588         return createTargetAuthenticationHandler();
589     }
590 
591     /**
592      * @deprecated (4.2) do not use
593      */
594     @Deprecated
setTargetAuthenticationHandler(final AuthenticationHandler handler)595     public synchronized void setTargetAuthenticationHandler(final AuthenticationHandler handler) {
596         this.targetAuthStrategy = new AuthenticationStrategyAdaptor(handler);
597     }
598 
599     /**
600      * @since 4.2
601      */
getTargetAuthenticationStrategy()602     public synchronized final AuthenticationStrategy getTargetAuthenticationStrategy() {
603         if (targetAuthStrategy == null) {
604             targetAuthStrategy = createTargetAuthenticationStrategy();
605         }
606         return targetAuthStrategy;
607     }
608 
609     /**
610      * @since 4.2
611      */
setTargetAuthenticationStrategy(final AuthenticationStrategy strategy)612     public synchronized void setTargetAuthenticationStrategy(final AuthenticationStrategy strategy) {
613         this.targetAuthStrategy = strategy;
614     }
615 
616     /**
617      * @deprecated (4.2) do not use
618      */
619     @Deprecated
getProxyAuthenticationHandler()620     public synchronized final AuthenticationHandler getProxyAuthenticationHandler() {
621         return createProxyAuthenticationHandler();
622     }
623 
624     /**
625      * @deprecated (4.2) do not use
626      */
627     @Deprecated
setProxyAuthenticationHandler(final AuthenticationHandler handler)628     public synchronized void setProxyAuthenticationHandler(final AuthenticationHandler handler) {
629         this.proxyAuthStrategy = new AuthenticationStrategyAdaptor(handler);
630     }
631 
632     /**
633      * @since 4.2
634      */
getProxyAuthenticationStrategy()635     public synchronized final AuthenticationStrategy getProxyAuthenticationStrategy() {
636         if (proxyAuthStrategy == null) {
637             proxyAuthStrategy = createProxyAuthenticationStrategy();
638         }
639         return proxyAuthStrategy;
640     }
641 
642     /**
643      * @since 4.2
644      */
setProxyAuthenticationStrategy(final AuthenticationStrategy strategy)645     public synchronized void setProxyAuthenticationStrategy(final AuthenticationStrategy strategy) {
646         this.proxyAuthStrategy = strategy;
647     }
648 
getCookieStore()649     public synchronized final CookieStore getCookieStore() {
650         if (cookieStore == null) {
651             cookieStore = createCookieStore();
652         }
653         return cookieStore;
654     }
655 
setCookieStore(final CookieStore cookieStore)656     public synchronized void setCookieStore(final CookieStore cookieStore) {
657         this.cookieStore = cookieStore;
658     }
659 
getCredentialsProvider()660     public synchronized final CredentialsProvider getCredentialsProvider() {
661         if (credsProvider == null) {
662             credsProvider = createCredentialsProvider();
663         }
664         return credsProvider;
665     }
666 
setCredentialsProvider(final CredentialsProvider credsProvider)667     public synchronized void setCredentialsProvider(final CredentialsProvider credsProvider) {
668         this.credsProvider = credsProvider;
669     }
670 
getRoutePlanner()671     public synchronized final HttpRoutePlanner getRoutePlanner() {
672         if (this.routePlanner == null) {
673             this.routePlanner = createHttpRoutePlanner();
674         }
675         return this.routePlanner;
676     }
677 
setRoutePlanner(final HttpRoutePlanner routePlanner)678     public synchronized void setRoutePlanner(final HttpRoutePlanner routePlanner) {
679         this.routePlanner = routePlanner;
680     }
681 
getUserTokenHandler()682     public synchronized final UserTokenHandler getUserTokenHandler() {
683         if (this.userTokenHandler == null) {
684             this.userTokenHandler = createUserTokenHandler();
685         }
686         return this.userTokenHandler;
687     }
688 
setUserTokenHandler(final UserTokenHandler handler)689     public synchronized void setUserTokenHandler(final UserTokenHandler handler) {
690         this.userTokenHandler = handler;
691     }
692 
getHttpProcessor()693     protected synchronized final BasicHttpProcessor getHttpProcessor() {
694         if (mutableProcessor == null) {
695             mutableProcessor = createHttpProcessor();
696         }
697         return mutableProcessor;
698     }
699 
getProtocolProcessor()700     private synchronized HttpProcessor getProtocolProcessor() {
701         if (protocolProcessor == null) {
702             // Get mutable HTTP processor
703             final BasicHttpProcessor proc = getHttpProcessor();
704             // and create an immutable copy of it
705             final int reqc = proc.getRequestInterceptorCount();
706             final HttpRequestInterceptor[] reqinterceptors = new HttpRequestInterceptor[reqc];
707             for (int i = 0; i < reqc; i++) {
708                 reqinterceptors[i] = proc.getRequestInterceptor(i);
709             }
710             final int resc = proc.getResponseInterceptorCount();
711             final HttpResponseInterceptor[] resinterceptors = new HttpResponseInterceptor[resc];
712             for (int i = 0; i < resc; i++) {
713                 resinterceptors[i] = proc.getResponseInterceptor(i);
714             }
715             protocolProcessor = new ImmutableHttpProcessor(reqinterceptors, resinterceptors);
716         }
717         return protocolProcessor;
718     }
719 
getResponseInterceptorCount()720     public synchronized int getResponseInterceptorCount() {
721         return getHttpProcessor().getResponseInterceptorCount();
722     }
723 
getResponseInterceptor(final int index)724     public synchronized HttpResponseInterceptor getResponseInterceptor(final int index) {
725         return getHttpProcessor().getResponseInterceptor(index);
726     }
727 
getRequestInterceptor(final int index)728     public synchronized HttpRequestInterceptor getRequestInterceptor(final int index) {
729         return getHttpProcessor().getRequestInterceptor(index);
730     }
731 
getRequestInterceptorCount()732     public synchronized int getRequestInterceptorCount() {
733         return getHttpProcessor().getRequestInterceptorCount();
734     }
735 
addResponseInterceptor(final HttpResponseInterceptor itcp)736     public synchronized void addResponseInterceptor(final HttpResponseInterceptor itcp) {
737         getHttpProcessor().addInterceptor(itcp);
738         protocolProcessor = null;
739     }
740 
addResponseInterceptor(final HttpResponseInterceptor itcp, final int index)741     public synchronized void addResponseInterceptor(final HttpResponseInterceptor itcp, final int index) {
742         getHttpProcessor().addInterceptor(itcp, index);
743         protocolProcessor = null;
744     }
745 
clearResponseInterceptors()746     public synchronized void clearResponseInterceptors() {
747         getHttpProcessor().clearResponseInterceptors();
748         protocolProcessor = null;
749     }
750 
removeResponseInterceptorByClass(final Class<? extends HttpResponseInterceptor> clazz)751     public synchronized void removeResponseInterceptorByClass(final Class<? extends HttpResponseInterceptor> clazz) {
752         getHttpProcessor().removeResponseInterceptorByClass(clazz);
753         protocolProcessor = null;
754     }
755 
addRequestInterceptor(final HttpRequestInterceptor itcp)756     public synchronized void addRequestInterceptor(final HttpRequestInterceptor itcp) {
757         getHttpProcessor().addInterceptor(itcp);
758         protocolProcessor = null;
759     }
760 
addRequestInterceptor(final HttpRequestInterceptor itcp, final int index)761     public synchronized void addRequestInterceptor(final HttpRequestInterceptor itcp, final int index) {
762         getHttpProcessor().addInterceptor(itcp, index);
763         protocolProcessor = null;
764     }
765 
clearRequestInterceptors()766     public synchronized void clearRequestInterceptors() {
767         getHttpProcessor().clearRequestInterceptors();
768         protocolProcessor = null;
769     }
770 
removeRequestInterceptorByClass(final Class<? extends HttpRequestInterceptor> clazz)771     public synchronized void removeRequestInterceptorByClass(final Class<? extends HttpRequestInterceptor> clazz) {
772         getHttpProcessor().removeRequestInterceptorByClass(clazz);
773         protocolProcessor = null;
774     }
775 
776     @Override
doExecute(final HttpHost target, final HttpRequest request, final HttpContext context)777     protected final CloseableHttpResponse doExecute(final HttpHost target, final HttpRequest request,
778                                       final HttpContext context)
779         throws IOException, ClientProtocolException {
780 
781         Args.notNull(request, "HTTP request");
782         // a null target may be acceptable, this depends on the route planner
783         // a null context is acceptable, default context created below
784 
785         HttpContext execContext = null;
786         RequestDirector director = null;
787         HttpRoutePlanner routePlanner = null;
788         ConnectionBackoffStrategy connectionBackoffStrategy = null;
789         BackoffManager backoffManager = null;
790 
791         // Initialize the request execution context making copies of
792         // all shared objects that are potentially threading unsafe.
793         synchronized (this) {
794 
795             final HttpContext defaultContext = createHttpContext();
796             if (context == null) {
797                 execContext = defaultContext;
798             } else {
799                 execContext = new DefaultedHttpContext(context, defaultContext);
800             }
801             final HttpParams params = determineParams(request);
802             final RequestConfig config = HttpClientParamConfig.getRequestConfig(params);
803             execContext.setAttribute(ClientContext.REQUEST_CONFIG, config);
804 
805             // Create a director for this request
806             director = createClientRequestDirector(
807                     getRequestExecutor(),
808                     getConnectionManager(),
809                     getConnectionReuseStrategy(),
810                     getConnectionKeepAliveStrategy(),
811                     getRoutePlanner(),
812                     getProtocolProcessor(),
813                     getHttpRequestRetryHandler(),
814                     getRedirectStrategy(),
815                     getTargetAuthenticationStrategy(),
816                     getProxyAuthenticationStrategy(),
817                     getUserTokenHandler(),
818                     params);
819             routePlanner = getRoutePlanner();
820             connectionBackoffStrategy = getConnectionBackoffStrategy();
821             backoffManager = getBackoffManager();
822         }
823 
824         try {
825             if (connectionBackoffStrategy != null && backoffManager != null) {
826                 final HttpHost targetForRoute = (target != null) ? target
827                         : (HttpHost) determineParams(request).getParameter(
828                                 ClientPNames.DEFAULT_HOST);
829                 final HttpRoute route = routePlanner.determineRoute(targetForRoute, request, execContext);
830 
831                 final CloseableHttpResponse out;
832                 try {
833                     out = CloseableHttpResponseProxy.newProxy(
834                             director.execute(target, request, execContext));
835                 } catch (final RuntimeException re) {
836                     if (connectionBackoffStrategy.shouldBackoff(re)) {
837                         backoffManager.backOff(route);
838                     }
839                     throw re;
840                 } catch (final Exception e) {
841                     if (connectionBackoffStrategy.shouldBackoff(e)) {
842                         backoffManager.backOff(route);
843                     }
844                     if (e instanceof HttpException) {
845                         throw (HttpException)e;
846                     }
847                     if (e instanceof IOException) {
848                         throw (IOException)e;
849                     }
850                     throw new UndeclaredThrowableException(e);
851                 }
852                 if (connectionBackoffStrategy.shouldBackoff(out)) {
853                     backoffManager.backOff(route);
854                 } else {
855                     backoffManager.probe(route);
856                 }
857                 return out;
858             } else {
859                 return CloseableHttpResponseProxy.newProxy(
860                         director.execute(target, request, execContext));
861             }
862         } catch(final HttpException httpException) {
863             throw new ClientProtocolException(httpException);
864         }
865     }
866 
867     /**
868      * @deprecated (4.1) do not use
869      */
870     @Deprecated
createClientRequestDirector( final HttpRequestExecutor requestExec, final ClientConnectionManager conman, final ConnectionReuseStrategy reustrat, final ConnectionKeepAliveStrategy kastrat, final HttpRoutePlanner rouplan, final HttpProcessor httpProcessor, final HttpRequestRetryHandler retryHandler, final RedirectHandler redirectHandler, final AuthenticationHandler targetAuthHandler, final AuthenticationHandler proxyAuthHandler, final UserTokenHandler userTokenHandler, final HttpParams params)871     protected RequestDirector createClientRequestDirector(
872             final HttpRequestExecutor requestExec,
873             final ClientConnectionManager conman,
874             final ConnectionReuseStrategy reustrat,
875             final ConnectionKeepAliveStrategy kastrat,
876             final HttpRoutePlanner rouplan,
877             final HttpProcessor httpProcessor,
878             final HttpRequestRetryHandler retryHandler,
879             final RedirectHandler redirectHandler,
880             final AuthenticationHandler targetAuthHandler,
881             final AuthenticationHandler proxyAuthHandler,
882             final UserTokenHandler userTokenHandler,
883             final HttpParams params) {
884         return new DefaultRequestDirector(
885                 requestExec,
886                 conman,
887                 reustrat,
888                 kastrat,
889                 rouplan,
890                 httpProcessor,
891                 retryHandler,
892                 redirectHandler,
893                 targetAuthHandler,
894                 proxyAuthHandler,
895                 userTokenHandler,
896                 params);
897     }
898 
899     /**
900      * @deprecated (4.2) do not use
901      */
902     @Deprecated
createClientRequestDirector( final HttpRequestExecutor requestExec, final ClientConnectionManager conman, final ConnectionReuseStrategy reustrat, final ConnectionKeepAliveStrategy kastrat, final HttpRoutePlanner rouplan, final HttpProcessor httpProcessor, final HttpRequestRetryHandler retryHandler, final RedirectStrategy redirectStrategy, final AuthenticationHandler targetAuthHandler, final AuthenticationHandler proxyAuthHandler, final UserTokenHandler userTokenHandler, final HttpParams params)903     protected RequestDirector createClientRequestDirector(
904             final HttpRequestExecutor requestExec,
905             final ClientConnectionManager conman,
906             final ConnectionReuseStrategy reustrat,
907             final ConnectionKeepAliveStrategy kastrat,
908             final HttpRoutePlanner rouplan,
909             final HttpProcessor httpProcessor,
910             final HttpRequestRetryHandler retryHandler,
911             final RedirectStrategy redirectStrategy,
912             final AuthenticationHandler targetAuthHandler,
913             final AuthenticationHandler proxyAuthHandler,
914             final UserTokenHandler userTokenHandler,
915             final HttpParams params) {
916         return new DefaultRequestDirector(
917                 log,
918                 requestExec,
919                 conman,
920                 reustrat,
921                 kastrat,
922                 rouplan,
923                 httpProcessor,
924                 retryHandler,
925                 redirectStrategy,
926                 targetAuthHandler,
927                 proxyAuthHandler,
928                 userTokenHandler,
929                 params);
930     }
931 
932 
933     /**
934      * @since 4.2
935      */
createClientRequestDirector( final HttpRequestExecutor requestExec, final ClientConnectionManager conman, final ConnectionReuseStrategy reustrat, final ConnectionKeepAliveStrategy kastrat, final HttpRoutePlanner rouplan, final HttpProcessor httpProcessor, final HttpRequestRetryHandler retryHandler, final RedirectStrategy redirectStrategy, final AuthenticationStrategy targetAuthStrategy, final AuthenticationStrategy proxyAuthStrategy, final UserTokenHandler userTokenHandler, final HttpParams params)936     protected RequestDirector createClientRequestDirector(
937             final HttpRequestExecutor requestExec,
938             final ClientConnectionManager conman,
939             final ConnectionReuseStrategy reustrat,
940             final ConnectionKeepAliveStrategy kastrat,
941             final HttpRoutePlanner rouplan,
942             final HttpProcessor httpProcessor,
943             final HttpRequestRetryHandler retryHandler,
944             final RedirectStrategy redirectStrategy,
945             final AuthenticationStrategy targetAuthStrategy,
946             final AuthenticationStrategy proxyAuthStrategy,
947             final UserTokenHandler userTokenHandler,
948             final HttpParams params) {
949         return new DefaultRequestDirector(
950                 log,
951                 requestExec,
952                 conman,
953                 reustrat,
954                 kastrat,
955                 rouplan,
956                 httpProcessor,
957                 retryHandler,
958                 redirectStrategy,
959                 targetAuthStrategy,
960                 proxyAuthStrategy,
961                 userTokenHandler,
962                 params);
963     }
964 
965     /**
966      * Obtains parameters for executing a request.
967      * The default implementation in this class creates a new
968      * {@link ClientParamsStack} from the request parameters
969      * and the client parameters.
970      * <br/>
971      * This method is called by the default implementation of
972      * {@link #execute(HttpHost,HttpRequest,HttpContext)}
973      * to obtain the parameters for the
974      * {@link DefaultRequestDirector}.
975      *
976      * @param req    the request that will be executed
977      *
978      * @return  the parameters to use
979      */
determineParams(final HttpRequest req)980     protected HttpParams determineParams(final HttpRequest req) {
981         return new ClientParamsStack
982             (null, getParams(), req.getParams(), null);
983     }
984 
985 
close()986     public void close() {
987         getConnectionManager().shutdown();
988     }
989 
990 }
991