View Javadoc

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 org.apache.http.impl.client;
29  
30  import java.io.IOException;
31  import java.lang.reflect.UndeclaredThrowableException;
32  import java.net.URI;
33  
34  import org.apache.commons.logging.Log;
35  import org.apache.commons.logging.LogFactory;
36  import org.apache.http.ConnectionReuseStrategy;
37  import org.apache.http.HttpEntity;
38  import org.apache.http.HttpException;
39  import org.apache.http.HttpHost;
40  import org.apache.http.HttpRequest;
41  import org.apache.http.HttpRequestInterceptor;
42  import org.apache.http.HttpResponse;
43  import org.apache.http.HttpResponseInterceptor;
44  import org.apache.http.annotation.GuardedBy;
45  import org.apache.http.annotation.ThreadSafe;
46  import org.apache.http.auth.AuthSchemeRegistry;
47  import org.apache.http.client.AuthenticationHandler;
48  import org.apache.http.client.AuthenticationStrategy;
49  import org.apache.http.client.BackoffManager;
50  import org.apache.http.client.ClientProtocolException;
51  import org.apache.http.client.ConnectionBackoffStrategy;
52  import org.apache.http.client.CookieStore;
53  import org.apache.http.client.CredentialsProvider;
54  import org.apache.http.client.HttpClient;
55  import org.apache.http.client.HttpRequestRetryHandler;
56  import org.apache.http.client.RedirectHandler;
57  import org.apache.http.client.RedirectStrategy;
58  import org.apache.http.client.RequestDirector;
59  import org.apache.http.client.ResponseHandler;
60  import org.apache.http.client.UserTokenHandler;
61  import org.apache.http.client.methods.HttpUriRequest;
62  import org.apache.http.client.params.AuthPolicy;
63  import org.apache.http.client.params.ClientPNames;
64  import org.apache.http.client.params.CookiePolicy;
65  import org.apache.http.client.protocol.ClientContext;
66  import org.apache.http.client.utils.URIUtils;
67  import org.apache.http.conn.ClientConnectionManager;
68  import org.apache.http.conn.ClientConnectionManagerFactory;
69  import org.apache.http.conn.ConnectionKeepAliveStrategy;
70  import org.apache.http.conn.routing.HttpRoute;
71  import org.apache.http.conn.routing.HttpRoutePlanner;
72  import org.apache.http.conn.scheme.SchemeRegistry;
73  import org.apache.http.cookie.CookieSpecRegistry;
74  import org.apache.http.impl.DefaultConnectionReuseStrategy;
75  import org.apache.http.impl.auth.BasicSchemeFactory;
76  import org.apache.http.impl.auth.DigestSchemeFactory;
77  import org.apache.http.impl.auth.KerberosSchemeFactory;
78  import org.apache.http.impl.auth.NTLMSchemeFactory;
79  import org.apache.http.impl.auth.SPNegoSchemeFactory;
80  import org.apache.http.impl.conn.BasicClientConnectionManager;
81  import org.apache.http.impl.conn.DefaultHttpRoutePlanner;
82  import org.apache.http.impl.conn.SchemeRegistryFactory;
83  import org.apache.http.impl.cookie.BestMatchSpecFactory;
84  import org.apache.http.impl.cookie.BrowserCompatSpecFactory;
85  import org.apache.http.impl.cookie.IgnoreSpecFactory;
86  import org.apache.http.impl.cookie.NetscapeDraftSpecFactory;
87  import org.apache.http.impl.cookie.RFC2109SpecFactory;
88  import org.apache.http.impl.cookie.RFC2965SpecFactory;
89  import org.apache.http.params.HttpParams;
90  import org.apache.http.protocol.BasicHttpContext;
91  import org.apache.http.protocol.BasicHttpProcessor;
92  import org.apache.http.protocol.DefaultedHttpContext;
93  import org.apache.http.protocol.HttpContext;
94  import org.apache.http.protocol.HttpProcessor;
95  import org.apache.http.protocol.HttpRequestExecutor;
96  import org.apache.http.protocol.ImmutableHttpProcessor;
97  import org.apache.http.util.EntityUtils;
98  
99  /**
100  * Base class for {@link HttpClient} implementations. This class acts as
101  * a facade to a number of special purpose handler or strategy
102  * implementations responsible for handling of a particular aspect of
103  * the HTTP protocol such as redirect or authentication handling or
104  * making decision about connection persistence and keep alive duration.
105  * This enables the users to selectively replace default implementation
106  * of those aspects with custom, application specific ones. This class
107  * also provides factory methods to instantiate those objects:
108  * <ul>
109  *   <li>{@link HttpRequestExecutor}</li> object used to transmit messages
110  *    over HTTP connections. The {@link #createRequestExecutor()} must be
111  *    implemented by concrete super classes to instantiate this object.
112  *   <li>{@link BasicHttpProcessor}</li> object to manage a list of protocol
113  *    interceptors and apply cross-cutting protocol logic to all incoming
114  *    and outgoing HTTP messages. The {@link #createHttpProcessor()} must be
115  *    implemented by concrete super classes to instantiate this object.
116  *   <li>{@link HttpRequestRetryHandler}</li> object used to decide whether
117  *    or not a failed HTTP request is safe to retry automatically.
118  *    The {@link #createHttpRequestRetryHandler()} must be
119  *    implemented by concrete super classes to instantiate this object.
120  *   <li>{@link ClientConnectionManager}</li> object used to manage
121  *    persistent HTTP connections.
122  *   <li>{@link ConnectionReuseStrategy}</li> object used to decide whether
123  *    or not a HTTP connection can be kept alive and re-used for subsequent
124  *    HTTP requests. The {@link #createConnectionReuseStrategy()} must be
125  *    implemented by concrete super classes to instantiate this object.
126  *   <li>{@link ConnectionKeepAliveStrategy}</li> object used to decide how
127  *    long a persistent HTTP connection can be kept alive.
128  *    The {@link #createConnectionKeepAliveStrategy()} must be
129  *    implemented by concrete super classes to instantiate this object.
130  *   <li>{@link CookieSpecRegistry}</li> object used to maintain a list of
131  *    supported cookie specifications.
132  *    The {@link #createCookieSpecRegistry()} must be implemented by concrete
133  *    super classes to instantiate this object.
134  *   <li>{@link CookieStore}</li> object used to maintain a collection of
135  *    cookies. The {@link #createCookieStore()} must be implemented by
136  *    concrete super classes to instantiate this object.
137  *   <li>{@link AuthSchemeRegistry}</li> object used to maintain a list of
138  *    supported authentication schemes.
139  *    The {@link #createAuthSchemeRegistry()} must be implemented by concrete
140  *    super classes to instantiate this object.
141  *   <li>{@link CredentialsProvider}</li> object used to maintain
142  *    a collection user credentials. The {@link #createCredentialsProvider()}
143  *    must be implemented by concrete super classes to instantiate
144  *    this object.
145  *   <li>{@link AuthenticationStrategy}</li> object used to authenticate
146  *    against the target host.
147  *    The {@link #createTargetAuthenticationStrategy()} must be implemented
148  *    by concrete super classes to instantiate this object.
149  *   <li>{@link AuthenticationStrategy}</li> object used to authenticate
150  *    against the proxy host.
151  *    The {@link #createProxyAuthenticationStrategy()} must be implemented
152  *    by concrete super classes to instantiate this object.
153  *   <li>{@link HttpRoutePlanner}</li> object used to calculate a route
154  *    for establishing a connection to the target host. The route
155  *    may involve multiple intermediate hops.
156  *    The {@link #createHttpRoutePlanner()} must be implemented
157  *    by concrete super classes to instantiate this object.
158  *   <li>{@link RedirectStrategy}</li> object used to determine if an HTTP
159  *    request should be redirected to a new location in response to an HTTP
160  *    response received from the target server.
161  *   <li>{@link UserTokenHandler}</li> object used to determine if the
162  *    execution context is user identity specific.
163  *    The {@link #createUserTokenHandler()} must be implemented by
164  *    concrete super classes to instantiate this object.
165  * </ul>
166  * <p>
167  *   This class also maintains a list of protocol interceptors intended
168  *   for processing outgoing requests and incoming responses and provides
169  *   methods for managing those interceptors. New protocol interceptors can be
170  *   introduced to the protocol processor chain or removed from it if needed.
171  *   Internally protocol interceptors are stored in a simple
172  *   {@link java.util.ArrayList}. They are executed in the same natural order
173  *   as they are added to the list.
174  * <p>
175  *   AbstractHttpClient is thread safe. It is recommended that the same
176  *   instance of this class is reused for multiple request executions.
177  *   When an instance of DefaultHttpClient is no longer needed and is about
178  *   to go out of scope the connection manager associated with it must be
179  *   shut down by calling {@link ClientConnectionManager#shutdown()}!
180  *
181  * @since 4.0
182  */
183 @SuppressWarnings("deprecation")
184 @ThreadSafe
185 public abstract class AbstractHttpClient implements HttpClient {
186 
187     private final Log log = LogFactory.getLog(getClass());
188 
189     /** The parameters. */
190     @GuardedBy("this")
191     private HttpParams defaultParams;
192 
193     /** The request executor. */
194     @GuardedBy("this")
195     private HttpRequestExecutor requestExec;
196 
197     /** The connection manager. */
198     @GuardedBy("this")
199     private ClientConnectionManager connManager;
200 
201     /** The connection re-use strategy. */
202     @GuardedBy("this")
203     private ConnectionReuseStrategy reuseStrategy;
204 
205     /** The connection keep-alive strategy. */
206     @GuardedBy("this")
207     private ConnectionKeepAliveStrategy keepAliveStrategy;
208 
209     /** The cookie spec registry. */
210     @GuardedBy("this")
211     private CookieSpecRegistry supportedCookieSpecs;
212 
213     /** The authentication scheme registry. */
214     @GuardedBy("this")
215     private AuthSchemeRegistry supportedAuthSchemes;
216 
217     /** The HTTP protocol processor and its immutable copy. */
218     @GuardedBy("this")
219     private BasicHttpProcessor mutableProcessor;
220 
221     @GuardedBy("this")
222     private ImmutableHttpProcessor protocolProcessor;
223 
224     /** The request retry handler. */
225     @GuardedBy("this")
226     private HttpRequestRetryHandler retryHandler;
227 
228     /** The redirect handler. */
229     @GuardedBy("this")
230     private RedirectStrategy redirectStrategy;
231 
232     /** The target authentication handler. */
233     @GuardedBy("this")
234     private AuthenticationStrategy targetAuthStrategy;
235 
236     /** The proxy authentication handler. */
237     @GuardedBy("this")
238     private AuthenticationStrategy proxyAuthStrategy;
239 
240     /** The cookie store. */
241     @GuardedBy("this")
242     private CookieStore cookieStore;
243 
244     /** The credentials provider. */
245     @GuardedBy("this")
246     private CredentialsProvider credsProvider;
247 
248     /** The route planner. */
249     @GuardedBy("this")
250     private HttpRoutePlanner routePlanner;
251 
252     /** The user token handler. */
253     @GuardedBy("this")
254     private UserTokenHandler userTokenHandler;
255 
256     /** The connection backoff strategy. */
257     @GuardedBy("this")
258     private ConnectionBackoffStrategy connectionBackoffStrategy;
259 
260     /** The backoff manager. */
261     @GuardedBy("this")
262     private BackoffManager backoffManager;
263 
264     /**
265      * Creates a new HTTP client.
266      *
267      * @param conman    the connection manager
268      * @param params    the parameters
269      */
270     protected AbstractHttpClient(
271             final ClientConnectionManager conman,
272             final HttpParams params) {
273         defaultParams        = params;
274         connManager          = conman;
275     } // constructor
276 
277 
278     protected abstract HttpParams createHttpParams();
279 
280 
281     protected abstract BasicHttpProcessor createHttpProcessor();
282 
283 
284     protected HttpContext createHttpContext() {
285         final HttpContext context = new BasicHttpContext();
286         context.setAttribute(
287                 ClientContext.SCHEME_REGISTRY,
288                 getConnectionManager().getSchemeRegistry());
289         context.setAttribute(
290                 ClientContext.AUTHSCHEME_REGISTRY,
291                 getAuthSchemes());
292         context.setAttribute(
293                 ClientContext.COOKIESPEC_REGISTRY,
294                 getCookieSpecs());
295         context.setAttribute(
296                 ClientContext.COOKIE_STORE,
297                 getCookieStore());
298         context.setAttribute(
299                 ClientContext.CREDS_PROVIDER,
300                 getCredentialsProvider());
301         return context;
302     }
303 
304 
305     protected ClientConnectionManager createClientConnectionManager() {
306         final SchemeRegistry registry = SchemeRegistryFactory.createDefault();
307 
308         ClientConnectionManager connManager = null;
309         final HttpParams params = getParams();
310 
311         ClientConnectionManagerFactory factory = null;
312 
313         final String className = (String) params.getParameter(
314                 ClientPNames.CONNECTION_MANAGER_FACTORY_CLASS_NAME);
315         if (className != null) {
316             try {
317                 final Class<?> clazz = Class.forName(className);
318                 factory = (ClientConnectionManagerFactory) clazz.newInstance();
319             } catch (final ClassNotFoundException ex) {
320                 throw new IllegalStateException("Invalid class name: " + className);
321             } catch (final IllegalAccessException ex) {
322                 throw new IllegalAccessError(ex.getMessage());
323             } catch (final InstantiationException ex) {
324                 throw new InstantiationError(ex.getMessage());
325             }
326         }
327         if (factory != null) {
328             connManager = factory.newInstance(params, registry);
329         } else {
330             connManager = new BasicClientConnectionManager(registry);
331         }
332 
333         return connManager;
334     }
335 
336 
337     protected AuthSchemeRegistry createAuthSchemeRegistry() {
338         final AuthSchemeRegistry registry = new AuthSchemeRegistry();
339         registry.register(
340                 AuthPolicy.BASIC,
341                 new BasicSchemeFactory());
342         registry.register(
343                 AuthPolicy.DIGEST,
344                 new DigestSchemeFactory());
345         registry.register(
346                 AuthPolicy.NTLM,
347                 new NTLMSchemeFactory());
348         registry.register(
349                 AuthPolicy.SPNEGO,
350                 new SPNegoSchemeFactory());
351         registry.register(
352                 AuthPolicy.KERBEROS,
353                 new KerberosSchemeFactory());
354         return registry;
355     }
356 
357 
358     protected CookieSpecRegistry createCookieSpecRegistry() {
359         final CookieSpecRegistry registry = new CookieSpecRegistry();
360         registry.register(
361                 CookiePolicy.BEST_MATCH,
362                 new BestMatchSpecFactory());
363         registry.register(
364                 CookiePolicy.BROWSER_COMPATIBILITY,
365                 new BrowserCompatSpecFactory());
366         registry.register(
367                 CookiePolicy.NETSCAPE,
368                 new NetscapeDraftSpecFactory());
369         registry.register(
370                 CookiePolicy.RFC_2109,
371                 new RFC2109SpecFactory());
372         registry.register(
373                 CookiePolicy.RFC_2965,
374                 new RFC2965SpecFactory());
375         registry.register(
376                 CookiePolicy.IGNORE_COOKIES,
377                 new IgnoreSpecFactory());
378         return registry;
379     }
380 
381     protected HttpRequestExecutor createRequestExecutor() {
382         return new HttpRequestExecutor();
383     }
384 
385     protected ConnectionReuseStrategy createConnectionReuseStrategy() {
386         return new DefaultConnectionReuseStrategy();
387     }
388 
389     protected ConnectionKeepAliveStrategy createConnectionKeepAliveStrategy() {
390         return new DefaultConnectionKeepAliveStrategy();
391     }
392 
393     protected HttpRequestRetryHandler createHttpRequestRetryHandler() {
394         return new DefaultHttpRequestRetryHandler();
395     }
396 
397     /**
398      * @deprecated (4.1) do not use
399      */
400     @Deprecated
401     protected RedirectHandler createRedirectHandler() {
402         return new DefaultRedirectHandler();
403     }
404 
405     protected AuthenticationStrategy createTargetAuthenticationStrategy() {
406         return new TargetAuthenticationStrategy();
407     }
408 
409     /**
410      * @deprecated (4.2) do not use
411      */
412     @Deprecated
413     protected AuthenticationHandler createTargetAuthenticationHandler() {
414         return new DefaultTargetAuthenticationHandler();
415     }
416 
417     protected AuthenticationStrategy createProxyAuthenticationStrategy() {
418         return new ProxyAuthenticationStrategy();
419     }
420 
421     /**
422      * @deprecated (4.2) do not use
423      */
424     @Deprecated
425     protected AuthenticationHandler createProxyAuthenticationHandler() {
426         return new DefaultProxyAuthenticationHandler();
427     }
428 
429     protected CookieStore createCookieStore() {
430         return new BasicCookieStore();
431     }
432 
433     protected CredentialsProvider createCredentialsProvider() {
434         return new BasicCredentialsProvider();
435     }
436 
437     protected HttpRoutePlanner createHttpRoutePlanner() {
438         return new DefaultHttpRoutePlanner(getConnectionManager().getSchemeRegistry());
439     }
440 
441     protected UserTokenHandler createUserTokenHandler() {
442         return new DefaultUserTokenHandler();
443     }
444 
445     // non-javadoc, see interface HttpClient
446     public synchronized final HttpParams getParams() {
447         if (defaultParams == null) {
448             defaultParams = createHttpParams();
449         }
450         return defaultParams;
451     }
452 
453     /**
454      * Replaces the parameters.
455      * The implementation here does not update parameters of dependent objects.
456      *
457      * @param params    the new default parameters
458      */
459     public synchronized void setParams(final HttpParams params) {
460         defaultParams = params;
461     }
462 
463 
464     public synchronized final ClientConnectionManager getConnectionManager() {
465         if (connManager == null) {
466             connManager = createClientConnectionManager();
467         }
468         return connManager;
469     }
470 
471 
472     public synchronized final HttpRequestExecutor getRequestExecutor() {
473         if (requestExec == null) {
474             requestExec = createRequestExecutor();
475         }
476         return requestExec;
477     }
478 
479 
480     public synchronized final AuthSchemeRegistry getAuthSchemes() {
481         if (supportedAuthSchemes == null) {
482             supportedAuthSchemes = createAuthSchemeRegistry();
483         }
484         return supportedAuthSchemes;
485     }
486 
487     public synchronized void setAuthSchemes(final AuthSchemeRegistry registry) {
488         supportedAuthSchemes = registry;
489     }
490 
491     public synchronized final ConnectionBackoffStrategy getConnectionBackoffStrategy() {
492         return connectionBackoffStrategy;
493     }
494 
495     public synchronized void setConnectionBackoffStrategy(final ConnectionBackoffStrategy strategy) {
496         connectionBackoffStrategy = strategy;
497     }
498 
499     public synchronized final CookieSpecRegistry getCookieSpecs() {
500         if (supportedCookieSpecs == null) {
501             supportedCookieSpecs = createCookieSpecRegistry();
502         }
503         return supportedCookieSpecs;
504     }
505 
506     public synchronized final BackoffManager getBackoffManager() {
507         return backoffManager;
508     }
509 
510     public synchronized void setBackoffManager(final BackoffManager manager) {
511         backoffManager = manager;
512     }
513 
514     public synchronized void setCookieSpecs(final CookieSpecRegistry registry) {
515         supportedCookieSpecs = registry;
516     }
517 
518     public synchronized final ConnectionReuseStrategy getConnectionReuseStrategy() {
519         if (reuseStrategy == null) {
520             reuseStrategy = createConnectionReuseStrategy();
521         }
522         return reuseStrategy;
523     }
524 
525 
526     public synchronized void setReuseStrategy(final ConnectionReuseStrategy strategy) {
527         this.reuseStrategy = strategy;
528     }
529 
530 
531     public synchronized final ConnectionKeepAliveStrategy getConnectionKeepAliveStrategy() {
532         if (keepAliveStrategy == null) {
533             keepAliveStrategy = createConnectionKeepAliveStrategy();
534         }
535         return keepAliveStrategy;
536     }
537 
538 
539     public synchronized void setKeepAliveStrategy(final ConnectionKeepAliveStrategy strategy) {
540         this.keepAliveStrategy = strategy;
541     }
542 
543 
544     public synchronized final HttpRequestRetryHandler getHttpRequestRetryHandler() {
545         if (retryHandler == null) {
546             retryHandler = createHttpRequestRetryHandler();
547         }
548         return retryHandler;
549     }
550 
551     public synchronized void setHttpRequestRetryHandler(final HttpRequestRetryHandler handler) {
552         this.retryHandler = handler;
553     }
554 
555     /**
556      * @deprecated (4.1) do not use
557      */
558     @Deprecated
559     public synchronized final RedirectHandler getRedirectHandler() {
560         return createRedirectHandler();
561     }
562 
563     /**
564      * @deprecated (4.1) do not use
565      */
566     @Deprecated
567     public synchronized void setRedirectHandler(final RedirectHandler handler) {
568         this.redirectStrategy = new DefaultRedirectStrategyAdaptor(handler);
569     }
570 
571     /**
572      * @since 4.1
573      */
574     public synchronized final RedirectStrategy getRedirectStrategy() {
575         if (redirectStrategy == null) {
576             redirectStrategy = new DefaultRedirectStrategy();
577         }
578         return redirectStrategy;
579     }
580 
581     /**
582      * @since 4.1
583      */
584     public synchronized void setRedirectStrategy(final RedirectStrategy strategy) {
585         this.redirectStrategy = strategy;
586     }
587 
588     /**
589      * @deprecated (4.2) do not use
590      */
591     @Deprecated
592     public synchronized final AuthenticationHandler getTargetAuthenticationHandler() {
593         return createTargetAuthenticationHandler();
594     }
595 
596     /**
597      * @deprecated (4.2) do not use
598      */
599     @Deprecated
600     public synchronized void setTargetAuthenticationHandler(final AuthenticationHandler handler) {
601         this.targetAuthStrategy = new AuthenticationStrategyAdaptor(handler);
602     }
603 
604     /**
605      * @since 4.2
606      */
607     public synchronized final AuthenticationStrategy getTargetAuthenticationStrategy() {
608         if (targetAuthStrategy == null) {
609             targetAuthStrategy = createTargetAuthenticationStrategy();
610         }
611         return targetAuthStrategy;
612     }
613 
614     /**
615      * @since 4.2
616      */
617     public synchronized void setTargetAuthenticationStrategy(final AuthenticationStrategy strategy) {
618         this.targetAuthStrategy = strategy;
619     }
620 
621     /**
622      * @deprecated (4.2) do not use
623      */
624     @Deprecated
625     public synchronized final AuthenticationHandler getProxyAuthenticationHandler() {
626         return createProxyAuthenticationHandler();
627     }
628 
629     /**
630      * @deprecated (4.2) do not use
631      */
632     @Deprecated
633     public synchronized void setProxyAuthenticationHandler(final AuthenticationHandler handler) {
634         this.proxyAuthStrategy = new AuthenticationStrategyAdaptor(handler);
635     }
636 
637     /**
638      * @since 4.2
639      */
640     public synchronized final AuthenticationStrategy getProxyAuthenticationStrategy() {
641         if (proxyAuthStrategy == null) {
642             proxyAuthStrategy = createProxyAuthenticationStrategy();
643         }
644         return proxyAuthStrategy;
645     }
646 
647     /**
648      * @since 4.2
649      */
650     public synchronized void setProxyAuthenticationStrategy(final AuthenticationStrategy strategy) {
651         this.proxyAuthStrategy = strategy;
652     }
653 
654     public synchronized final CookieStore getCookieStore() {
655         if (cookieStore == null) {
656             cookieStore = createCookieStore();
657         }
658         return cookieStore;
659     }
660 
661     public synchronized void setCookieStore(final CookieStore cookieStore) {
662         this.cookieStore = cookieStore;
663     }
664 
665     public synchronized final CredentialsProvider getCredentialsProvider() {
666         if (credsProvider == null) {
667             credsProvider = createCredentialsProvider();
668         }
669         return credsProvider;
670     }
671 
672     public synchronized void setCredentialsProvider(final CredentialsProvider credsProvider) {
673         this.credsProvider = credsProvider;
674     }
675 
676     public synchronized final HttpRoutePlanner getRoutePlanner() {
677         if (this.routePlanner == null) {
678             this.routePlanner = createHttpRoutePlanner();
679         }
680         return this.routePlanner;
681     }
682 
683     public synchronized void setRoutePlanner(final HttpRoutePlanner routePlanner) {
684         this.routePlanner = routePlanner;
685     }
686 
687     public synchronized final UserTokenHandler getUserTokenHandler() {
688         if (this.userTokenHandler == null) {
689             this.userTokenHandler = createUserTokenHandler();
690         }
691         return this.userTokenHandler;
692     }
693 
694     public synchronized void setUserTokenHandler(final UserTokenHandler handler) {
695         this.userTokenHandler = handler;
696     }
697 
698     protected synchronized final BasicHttpProcessor getHttpProcessor() {
699         if (mutableProcessor == null) {
700             mutableProcessor = createHttpProcessor();
701         }
702         return mutableProcessor;
703     }
704 
705     private synchronized final HttpProcessor getProtocolProcessor() {
706         if (protocolProcessor == null) {
707             // Get mutable HTTP processor
708             final BasicHttpProcessor proc = getHttpProcessor();
709             // and create an immutable copy of it
710             final int reqc = proc.getRequestInterceptorCount();
711             final HttpRequestInterceptor[] reqinterceptors = new HttpRequestInterceptor[reqc];
712             for (int i = 0; i < reqc; i++) {
713                 reqinterceptors[i] = proc.getRequestInterceptor(i);
714             }
715             final int resc = proc.getResponseInterceptorCount();
716             final HttpResponseInterceptor[] resinterceptors = new HttpResponseInterceptor[resc];
717             for (int i = 0; i < resc; i++) {
718                 resinterceptors[i] = proc.getResponseInterceptor(i);
719             }
720             protocolProcessor = new ImmutableHttpProcessor(reqinterceptors, resinterceptors);
721         }
722         return protocolProcessor;
723     }
724 
725     public synchronized int getResponseInterceptorCount() {
726         return getHttpProcessor().getResponseInterceptorCount();
727     }
728 
729     public synchronized HttpResponseInterceptor getResponseInterceptor(final int index) {
730         return getHttpProcessor().getResponseInterceptor(index);
731     }
732 
733     public synchronized HttpRequestInterceptor getRequestInterceptor(final int index) {
734         return getHttpProcessor().getRequestInterceptor(index);
735     }
736 
737     public synchronized int getRequestInterceptorCount() {
738         return getHttpProcessor().getRequestInterceptorCount();
739     }
740 
741     public synchronized void addResponseInterceptor(final HttpResponseInterceptor itcp) {
742         getHttpProcessor().addInterceptor(itcp);
743         protocolProcessor = null;
744     }
745 
746     public synchronized void addResponseInterceptor(final HttpResponseInterceptor itcp, final int index) {
747         getHttpProcessor().addInterceptor(itcp, index);
748         protocolProcessor = null;
749     }
750 
751     public synchronized void clearResponseInterceptors() {
752         getHttpProcessor().clearResponseInterceptors();
753         protocolProcessor = null;
754     }
755 
756     public synchronized void removeResponseInterceptorByClass(final Class<? extends HttpResponseInterceptor> clazz) {
757         getHttpProcessor().removeResponseInterceptorByClass(clazz);
758         protocolProcessor = null;
759     }
760 
761     public synchronized void addRequestInterceptor(final HttpRequestInterceptor itcp) {
762         getHttpProcessor().addInterceptor(itcp);
763         protocolProcessor = null;
764     }
765 
766     public synchronized void addRequestInterceptor(final HttpRequestInterceptor itcp, final int index) {
767         getHttpProcessor().addInterceptor(itcp, index);
768         protocolProcessor = null;
769     }
770 
771     public synchronized void clearRequestInterceptors() {
772         getHttpProcessor().clearRequestInterceptors();
773         protocolProcessor = null;
774     }
775 
776     public synchronized void removeRequestInterceptorByClass(final Class<? extends HttpRequestInterceptor> clazz) {
777         getHttpProcessor().removeRequestInterceptorByClass(clazz);
778         protocolProcessor = null;
779     }
780 
781     public final HttpResponse execute(final HttpUriRequest request)
782         throws IOException, ClientProtocolException {
783 
784         return execute(request, (HttpContext) null);
785     }
786 
787     /**
788      * Maps to {@link HttpClient#execute(HttpHost,HttpRequest,HttpContext)
789      *                           execute(target, request, context)}.
790      * The target is determined from the URI of the request.
791      *
792      * @param request   the request to execute
793      * @param context   the request-specific execution context,
794      *                  or <code>null</code> to use a default context
795      */
796     public final HttpResponse execute(final HttpUriRequest request,
797                                       final HttpContext context)
798         throws IOException, ClientProtocolException {
799 
800         if (request == null) {
801             throw new IllegalArgumentException
802                 ("Request must not be null.");
803         }
804 
805         return execute(determineTarget(request), request, context);
806     }
807 
808     private static HttpHost determineTarget(final HttpUriRequest request) throws ClientProtocolException {
809         // A null target may be acceptable if there is a default target.
810         // Otherwise, the null target is detected in the director.
811         HttpHost target = null;
812 
813         final URI requestURI = request.getURI();
814         if (requestURI.isAbsolute()) {
815             target = URIUtils.extractHost(requestURI);
816             if (target == null) {
817                 throw new ClientProtocolException(
818                         "URI does not specify a valid host name: " + requestURI);
819             }
820         }
821         return target;
822     }
823 
824     public final HttpResponse execute(final HttpHost target, final HttpRequest request)
825         throws IOException, ClientProtocolException {
826 
827         return execute(target, request, (HttpContext) null);
828     }
829 
830     public final HttpResponse execute(final HttpHost target, final HttpRequest request,
831                                       final HttpContext context)
832         throws IOException, ClientProtocolException {
833 
834         if (request == null) {
835             throw new IllegalArgumentException
836                 ("Request must not be null.");
837         }
838         // a null target may be acceptable, this depends on the route planner
839         // a null context is acceptable, default context created below
840 
841         HttpContext execContext = null;
842         RequestDirector director = null;
843         HttpRoutePlanner routePlanner = null;
844         ConnectionBackoffStrategy connectionBackoffStrategy = null;
845         BackoffManager backoffManager = null;
846 
847         // Initialize the request execution context making copies of
848         // all shared objects that are potentially threading unsafe.
849         synchronized (this) {
850 
851             final HttpContext defaultContext = createHttpContext();
852             if (context == null) {
853                 execContext = defaultContext;
854             } else {
855                 execContext = new DefaultedHttpContext(context, defaultContext);
856             }
857             // Create a director for this request
858             director = createClientRequestDirector(
859                     getRequestExecutor(),
860                     getConnectionManager(),
861                     getConnectionReuseStrategy(),
862                     getConnectionKeepAliveStrategy(),
863                     getRoutePlanner(),
864                     getProtocolProcessor(),
865                     getHttpRequestRetryHandler(),
866                     getRedirectStrategy(),
867                     getTargetAuthenticationStrategy(),
868                     getProxyAuthenticationStrategy(),
869                     getUserTokenHandler(),
870                     determineParams(request));
871             routePlanner = getRoutePlanner();
872             connectionBackoffStrategy = getConnectionBackoffStrategy();
873             backoffManager = getBackoffManager();
874         }
875 
876         try {
877             if (connectionBackoffStrategy != null && backoffManager != null) {
878                 final HttpHost targetForRoute = (target != null) ? target
879                         : (HttpHost) determineParams(request).getParameter(
880                                 ClientPNames.DEFAULT_HOST);
881                 final HttpRoute route = routePlanner.determineRoute(targetForRoute, request, execContext);
882 
883                 HttpResponse out;
884                 try {
885                     out = director.execute(target, request, execContext);
886                 } catch (final RuntimeException re) {
887                     if (connectionBackoffStrategy.shouldBackoff(re)) {
888                         backoffManager.backOff(route);
889                     }
890                     throw re;
891                 } catch (final Exception e) {
892                     if (connectionBackoffStrategy.shouldBackoff(e)) {
893                         backoffManager.backOff(route);
894                     }
895                     if (e instanceof HttpException) throw (HttpException)e;
896                     if (e instanceof IOException) throw (IOException)e;
897                     throw new UndeclaredThrowableException(e);
898                 }
899                 if (connectionBackoffStrategy.shouldBackoff(out)) {
900                     backoffManager.backOff(route);
901                 } else {
902                     backoffManager.probe(route);
903                 }
904                 return out;
905             } else {
906                 return director.execute(target, request, execContext);
907             }
908         } catch(final HttpException httpException) {
909             throw new ClientProtocolException(httpException);
910         }
911     }
912 
913     /**
914      * @deprecated (4.1) do not use
915      */
916     @Deprecated
917     protected RequestDirector createClientRequestDirector(
918             final HttpRequestExecutor requestExec,
919             final ClientConnectionManager conman,
920             final ConnectionReuseStrategy reustrat,
921             final ConnectionKeepAliveStrategy kastrat,
922             final HttpRoutePlanner rouplan,
923             final HttpProcessor httpProcessor,
924             final HttpRequestRetryHandler retryHandler,
925             final RedirectHandler redirectHandler,
926             final AuthenticationHandler targetAuthHandler,
927             final AuthenticationHandler proxyAuthHandler,
928             final UserTokenHandler userTokenHandler,
929             final HttpParams params) {
930         return new DefaultRequestDirector(
931                 requestExec,
932                 conman,
933                 reustrat,
934                 kastrat,
935                 rouplan,
936                 httpProcessor,
937                 retryHandler,
938                 redirectHandler,
939                 targetAuthHandler,
940                 proxyAuthHandler,
941                 userTokenHandler,
942                 params);
943     }
944 
945     /**
946      * @deprecated (4.2) do not use
947      */
948     @Deprecated
949     protected RequestDirector createClientRequestDirector(
950             final HttpRequestExecutor requestExec,
951             final ClientConnectionManager conman,
952             final ConnectionReuseStrategy reustrat,
953             final ConnectionKeepAliveStrategy kastrat,
954             final HttpRoutePlanner rouplan,
955             final HttpProcessor httpProcessor,
956             final HttpRequestRetryHandler retryHandler,
957             final RedirectStrategy redirectStrategy,
958             final AuthenticationHandler targetAuthHandler,
959             final AuthenticationHandler proxyAuthHandler,
960             final UserTokenHandler userTokenHandler,
961             final HttpParams params) {
962         return new DefaultRequestDirector(
963                 log,
964                 requestExec,
965                 conman,
966                 reustrat,
967                 kastrat,
968                 rouplan,
969                 httpProcessor,
970                 retryHandler,
971                 redirectStrategy,
972                 targetAuthHandler,
973                 proxyAuthHandler,
974                 userTokenHandler,
975                 params);
976     }
977 
978 
979     /**
980      * @since 4.2
981      */
982     protected RequestDirector createClientRequestDirector(
983             final HttpRequestExecutor requestExec,
984             final ClientConnectionManager conman,
985             final ConnectionReuseStrategy reustrat,
986             final ConnectionKeepAliveStrategy kastrat,
987             final HttpRoutePlanner rouplan,
988             final HttpProcessor httpProcessor,
989             final HttpRequestRetryHandler retryHandler,
990             final RedirectStrategy redirectStrategy,
991             final AuthenticationStrategy targetAuthStrategy,
992             final AuthenticationStrategy proxyAuthStrategy,
993             final UserTokenHandler userTokenHandler,
994             final HttpParams params) {
995         return new DefaultRequestDirector(
996                 log,
997                 requestExec,
998                 conman,
999                 reustrat,
1000                 kastrat,
1001                 rouplan,
1002                 httpProcessor,
1003                 retryHandler,
1004                 redirectStrategy,
1005                 targetAuthStrategy,
1006                 proxyAuthStrategy,
1007                 userTokenHandler,
1008                 params);
1009     }
1010 
1011     /**
1012      * Obtains parameters for executing a request.
1013      * The default implementation in this class creates a new
1014      * {@link ClientParamsStack} from the request parameters
1015      * and the client parameters.
1016      * <br/>
1017      * This method is called by the default implementation of
1018      * {@link #execute(HttpHost,HttpRequest,HttpContext)}
1019      * to obtain the parameters for the
1020      * {@link DefaultRequestDirector}.
1021      *
1022      * @param req    the request that will be executed
1023      *
1024      * @return  the parameters to use
1025      */
1026     protected HttpParams determineParams(final HttpRequest req) {
1027         return new ClientParamsStack
1028             (null, getParams(), req.getParams(), null);
1029     }
1030 
1031     /**
1032      * Executes a request using the default context and processes the
1033      * response using the given response handler. The content entity associated
1034      * with the response is fully consumed and the underlying connection is
1035      * released back to the connection manager automatically in all cases
1036      * relieving individual {@link ResponseHandler}s from having to manage
1037      * resource deallocation internally.
1038      *
1039      * @param request   the request to execute
1040      * @param responseHandler the response handler
1041      *
1042      * @return  the response object as generated by the response handler.
1043      * @throws IOException in case of a problem or the connection was aborted
1044      * @throws ClientProtocolException in case of an http protocol error
1045      */
1046     public <T> T execute(
1047             final HttpUriRequest request,
1048             final ResponseHandler<? extends T> responseHandler)
1049                 throws IOException, ClientProtocolException {
1050         return execute(request, responseHandler, null);
1051     }
1052 
1053     /**
1054      * Executes a request using the default context and processes the
1055      * response using the given response handler. The content entity associated
1056      * with the response is fully consumed and the underlying connection is
1057      * released back to the connection manager automatically in all cases
1058      * relieving individual {@link ResponseHandler}s from having to manage
1059      * resource deallocation internally.
1060      *
1061      * @param request   the request to execute
1062      * @param responseHandler the response handler
1063      * @param context   the context to use for the execution, or
1064      *                  <code>null</code> to use the default context
1065      *
1066      * @return  the response object as generated by the response handler.
1067      * @throws IOException in case of a problem or the connection was aborted
1068      * @throws ClientProtocolException in case of an http protocol error
1069      */
1070     public <T> T execute(
1071             final HttpUriRequest request,
1072             final ResponseHandler<? extends T> responseHandler,
1073             final HttpContext context)
1074                 throws IOException, ClientProtocolException {
1075         final HttpHost target = determineTarget(request);
1076         return execute(target, request, responseHandler, context);
1077     }
1078 
1079     /**
1080      * Executes a request using the default context and processes the
1081      * response using the given response handler. The content entity associated
1082      * with the response is fully consumed and the underlying connection is
1083      * released back to the connection manager automatically in all cases
1084      * relieving individual {@link ResponseHandler}s from having to manage
1085      * resource deallocation internally.
1086      *
1087      * @param target    the target host for the request.
1088      *                  Implementations may accept <code>null</code>
1089      *                  if they can still determine a route, for example
1090      *                  to a default target or by inspecting the request.
1091      * @param request   the request to execute
1092      * @param responseHandler the response handler
1093      *
1094      * @return  the response object as generated by the response handler.
1095      * @throws IOException in case of a problem or the connection was aborted
1096      * @throws ClientProtocolException in case of an http protocol error
1097      */
1098     public <T> T execute(
1099             final HttpHost target,
1100             final HttpRequest request,
1101             final ResponseHandler<? extends T> responseHandler)
1102                 throws IOException, ClientProtocolException {
1103         return execute(target, request, responseHandler, null);
1104     }
1105 
1106     /**
1107      * Executes a request using the default context and processes the
1108      * response using the given response handler. The content entity associated
1109      * with the response is fully consumed and the underlying connection is
1110      * released back to the connection manager automatically in all cases
1111      * relieving individual {@link ResponseHandler}s from having to manage
1112      * resource deallocation internally.
1113      *
1114      * @param target    the target host for the request.
1115      *                  Implementations may accept <code>null</code>
1116      *                  if they can still determine a route, for example
1117      *                  to a default target or by inspecting the request.
1118      * @param request   the request to execute
1119      * @param responseHandler the response handler
1120      * @param context   the context to use for the execution, or
1121      *                  <code>null</code> to use the default context
1122      *
1123      * @return  the response object as generated by the response handler.
1124      * @throws IOException in case of a problem or the connection was aborted
1125      * @throws ClientProtocolException in case of an http protocol error
1126      */
1127     public <T> T execute(
1128             final HttpHost target,
1129             final HttpRequest request,
1130             final ResponseHandler<? extends T> responseHandler,
1131             final HttpContext context)
1132                 throws IOException, ClientProtocolException {
1133         if (responseHandler == null) {
1134             throw new IllegalArgumentException
1135                 ("Response handler must not be null.");
1136         }
1137 
1138         final HttpResponse response = execute(target, request, context);
1139 
1140         T result;
1141         try {
1142             result = responseHandler.handleResponse(response);
1143         } catch (final Exception t) {
1144             final HttpEntity entity = response.getEntity();
1145             try {
1146                 EntityUtils.consume(entity);
1147             } catch (final Exception t2) {
1148                 // Log this exception. The original exception is more
1149                 // important and will be thrown to the caller.
1150                 this.log.warn("Error consuming content after an exception.", t2);
1151             }
1152             if (t instanceof RuntimeException) {
1153                 throw (RuntimeException) t;
1154             }
1155             if (t instanceof IOException) {
1156                 throw (IOException) t;
1157             }
1158             throw new UndeclaredThrowableException(t);
1159         }
1160 
1161         // Handling the response was successful. Ensure that the content has
1162         // been fully consumed.
1163         final HttpEntity entity = response.getEntity();
1164         EntityUtils.consume(entity);
1165         return result;
1166     }
1167 
1168 }