Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
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 */
28 package ch.boye.httpclientandroidlib.impl.client;
30 import java.io.IOException;
31 import java.lang.reflect.UndeclaredThrowableException;
32 import java.net.URI;
34 import ch.boye.httpclientandroidlib.androidextra.HttpClientAndroidLog;
35 /* LogFactory removed by HttpClient for Android script. */
36 import ch.boye.httpclientandroidlib.ConnectionReuseStrategy;
37 import ch.boye.httpclientandroidlib.HttpEntity;
38 import ch.boye.httpclientandroidlib.HttpException;
39 import ch.boye.httpclientandroidlib.HttpHost;
40 import ch.boye.httpclientandroidlib.HttpRequest;
41 import ch.boye.httpclientandroidlib.HttpRequestInterceptor;
42 import ch.boye.httpclientandroidlib.HttpResponse;
43 import ch.boye.httpclientandroidlib.HttpResponseInterceptor;
44 import ch.boye.httpclientandroidlib.annotation.GuardedBy;
45 import ch.boye.httpclientandroidlib.annotation.ThreadSafe;
46 import ch.boye.httpclientandroidlib.auth.AuthSchemeRegistry;
47 import ch.boye.httpclientandroidlib.client.AuthenticationHandler;
48 import ch.boye.httpclientandroidlib.client.ClientProtocolException;
49 import ch.boye.httpclientandroidlib.client.CookieStore;
50 import ch.boye.httpclientandroidlib.client.CredentialsProvider;
51 import ch.boye.httpclientandroidlib.client.HttpClient;
52 import ch.boye.httpclientandroidlib.client.HttpRequestRetryHandler;
53 import ch.boye.httpclientandroidlib.client.RedirectHandler;
54 import ch.boye.httpclientandroidlib.client.RedirectStrategy;
55 import ch.boye.httpclientandroidlib.client.RequestDirector;
56 import ch.boye.httpclientandroidlib.client.ResponseHandler;
57 import ch.boye.httpclientandroidlib.client.UserTokenHandler;
58 import ch.boye.httpclientandroidlib.client.methods.HttpUriRequest;
59 import ch.boye.httpclientandroidlib.client.params.AuthPolicy;
60 import ch.boye.httpclientandroidlib.client.params.ClientPNames;
61 import ch.boye.httpclientandroidlib.client.params.CookiePolicy;
62 import ch.boye.httpclientandroidlib.client.protocol.ClientContext;
63 import ch.boye.httpclientandroidlib.client.utils.URIUtils;
64 import ch.boye.httpclientandroidlib.conn.ClientConnectionManager;
65 import ch.boye.httpclientandroidlib.conn.ClientConnectionManagerFactory;
66 import ch.boye.httpclientandroidlib.conn.ConnectionKeepAliveStrategy;
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 import ch.boye.httpclientandroidlib.impl.auth.NTLMSchemeFactory;
74 /* NegotiateSchemeFactory removed by HttpClient for Android script. */
75 import ch.boye.httpclientandroidlib.impl.conn.DefaultHttpRoutePlanner;
76 import ch.boye.httpclientandroidlib.impl.conn.SchemeRegistryFactory;
77 import ch.boye.httpclientandroidlib.impl.conn.SingleClientConnManager;
78 import ch.boye.httpclientandroidlib.impl.cookie.BestMatchSpecFactory;
79 import ch.boye.httpclientandroidlib.impl.cookie.BrowserCompatSpecFactory;
80 import ch.boye.httpclientandroidlib.impl.cookie.IgnoreSpecFactory;
81 import ch.boye.httpclientandroidlib.impl.cookie.NetscapeDraftSpecFactory;
82 import ch.boye.httpclientandroidlib.impl.cookie.RFC2109SpecFactory;
83 import ch.boye.httpclientandroidlib.impl.cookie.RFC2965SpecFactory;
84 import ch.boye.httpclientandroidlib.params.HttpParams;
85 import ch.boye.httpclientandroidlib.protocol.BasicHttpContext;
86 import ch.boye.httpclientandroidlib.protocol.BasicHttpProcessor;
87 import ch.boye.httpclientandroidlib.protocol.DefaultedHttpContext;
88 import ch.boye.httpclientandroidlib.protocol.HttpContext;
89 import ch.boye.httpclientandroidlib.protocol.HttpProcessor;
90 import ch.boye.httpclientandroidlib.protocol.HttpRequestExecutor;
91 import ch.boye.httpclientandroidlib.protocol.ImmutableHttpProcessor;
92 import ch.boye.httpclientandroidlib.util.EntityUtils;
94 /**
95 * Base class for {@link HttpClient} implementations. This class acts as
96 * a facade to a number of special purpose handler or strategy
97 * implementations responsible for handling of a particular aspect of
98 * the HTTP protocol such as redirect or authentication handling or
99 * making decision about connection persistence and keep alive duration.
100 * This enables the users to selectively replace default implementation
101 * of those aspects with custom, application specific ones. This class
102 * also provides factory methods to instantiate those objects:
103 * <ul>
104 * <li>{@link HttpRequestExecutor}</li> object used to transmit messages
105 * over HTTP connections. The {@link #createRequestExecutor()} must be
106 * implemented by concrete super classes to instantiate this object.
107 * <li>{@link BasicHttpProcessor}</li> object to manage a list of protocol
108 * interceptors and apply cross-cutting protocol logic to all incoming
109 * and outgoing HTTP messages. The {@link #createHttpProcessor()} must be
110 * implemented by concrete super classes to instantiate this object.
111 * <li>{@link HttpRequestRetryHandler}</li> object used to decide whether
112 * or not a failed HTTP request is safe to retry automatically.
113 * The {@link #createHttpRequestRetryHandler()} must be
114 * implemented by concrete super classes to instantiate this object.
115 * <li>{@link ClientConnectionManager}</li> object used to manage
116 * persistent HTTP connections.
117 * <li>{@link ConnectionReuseStrategy}</li> object used to decide whether
118 * or not a HTTP connection can be kept alive and re-used for subsequent
119 * HTTP requests. The {@link #createConnectionReuseStrategy()} must be
120 * implemented by concrete super classes to instantiate this object.
121 * <li>{@link ConnectionKeepAliveStrategy}</li> object used to decide how
122 * long a persistent HTTP connection can be kept alive.
123 * The {@link #createConnectionKeepAliveStrategy()} must be
124 * implemented by concrete super classes to instantiate this object.
125 * <li>{@link CookieSpecRegistry}</li> object used to maintain a list of
126 * supported cookie specifications.
127 * The {@link #createCookieSpecRegistry()} must be implemented by concrete
128 * super classes to instantiate this object.
129 * <li>{@link CookieStore}</li> object used to maintain a collection of
130 * cookies. The {@link #createCookieStore()} must be implemented by
131 * concrete super classes to instantiate this object.
132 * <li>{@link AuthSchemeRegistry}</li> object used to maintain a list of
133 * supported authentication schemes.
134 * The {@link #createAuthSchemeRegistry()} must be implemented by concrete
135 * super classes to instantiate this object.
136 * <li>{@link CredentialsProvider}</li> object used to maintain
137 * a collection user credentials. The {@link #createCredentialsProvider()}
138 * must be implemented by concrete super classes to instantiate
139 * this object.
140 * <li>{@link AuthenticationHandler}</li> object used to authenticate
141 * against the target host.
142 * The {@link #createTargetAuthenticationHandler()} must be implemented
143 * by concrete super classes to instantiate this object.
144 * <li>{@link AuthenticationHandler}</li> object used to authenticate
145 * against the proxy host.
146 * The {@link #createProxyAuthenticationHandler()} must be implemented
147 * by concrete super classes to instantiate this object.
148 * <li>{@link HttpRoutePlanner}</li> object used to calculate a route
149 * for establishing a connection to the target host. The route
150 * may involve multiple intermediate hops.
151 * The {@link #createHttpRoutePlanner()} must be implemented
152 * by concrete super classes to instantiate this object.
153 * <li>{@link RedirectStrategy}</li> object used to determine if an HTTP
154 * request should be redirected to a new location in response to an HTTP
155 * response received from the target server.
156 * <li>{@link UserTokenHandler}</li> object used to determine if the
157 * execution context is user identity specific.
158 * The {@link #createUserTokenHandler()} must be implemented by
159 * concrete super classes to instantiate this object.
160 * </ul>
161 * <p>
162 * This class also maintains a list of protocol interceptors intended
163 * for processing outgoing requests and incoming responses and provides
164 * methods for managing those interceptors. New protocol interceptors can be
165 * introduced to the protocol processor chain or removed from it if needed.
166 * Internally protocol interceptors are stored in a simple
167 * {@link java.util.ArrayList}. They are executed in the same natural order
168 * as they are added to the list.
169 * <p>
170 * AbstractHttpClient is thread safe. It is recommended that the same
171 * instance of this class is reused for multiple request executions.
172 * When an instance of DefaultHttpClient is no longer needed and is about
173 * to go out of scope the connection manager associated with it must be
174 * shut down by calling {@link ClientConnectionManager#shutdown()}!
175 *
176 * @since 4.0
177 */
178 @ThreadSafe
179 @SuppressWarnings("deprecation")
180 public abstract class AbstractHttpClient implements HttpClient {
182 public HttpClientAndroidLog log = new HttpClientAndroidLog(getClass());
184 /** The parameters. */
185 @GuardedBy("this")
186 private HttpParams defaultParams;
188 /** The request executor. */
189 @GuardedBy("this")
190 private HttpRequestExecutor requestExec;
192 /** The connection manager. */
193 @GuardedBy("this")
194 private ClientConnectionManager connManager;
196 /** The connection re-use strategy. */
197 @GuardedBy("this")
198 private ConnectionReuseStrategy reuseStrategy;
200 /** The connection keep-alive strategy. */
201 @GuardedBy("this")
202 private ConnectionKeepAliveStrategy keepAliveStrategy;
204 /** The cookie spec registry. */
205 @GuardedBy("this")
206 private CookieSpecRegistry supportedCookieSpecs;
208 /** The authentication scheme registry. */
209 @GuardedBy("this")
210 private AuthSchemeRegistry supportedAuthSchemes;
212 /** The HTTP protocol processor and its immutable copy. */
213 @GuardedBy("this")
214 private BasicHttpProcessor mutableProcessor;
216 @GuardedBy("this")
217 private ImmutableHttpProcessor protocolProcessor;
219 /** The request retry handler. */
220 @GuardedBy("this")
221 private HttpRequestRetryHandler retryHandler;
223 /** The redirect handler. */
224 @GuardedBy("this")
225 private RedirectStrategy redirectStrategy;
227 /** The target authentication handler. */
228 @GuardedBy("this")
229 private AuthenticationHandler targetAuthHandler;
231 /** The proxy authentication handler. */
232 @GuardedBy("this")
233 private AuthenticationHandler proxyAuthHandler;
235 /** The cookie store. */
236 @GuardedBy("this")
237 private CookieStore cookieStore;
239 /** The credentials provider. */
240 @GuardedBy("this")
241 private CredentialsProvider credsProvider;
243 /** The route planner. */
244 @GuardedBy("this")
245 private HttpRoutePlanner routePlanner;
247 /** The user token handler. */
248 @GuardedBy("this")
249 private UserTokenHandler userTokenHandler;
252 /**
253 * Creates a new HTTP client.
254 *
255 * @param conman the connection manager
256 * @param params the parameters
257 */
258 protected AbstractHttpClient(
259 final ClientConnectionManager conman,
260 final HttpParams params) {
261 defaultParams = params;
262 connManager = conman;
263 } // constructor
266 protected abstract HttpParams createHttpParams();
269 protected abstract BasicHttpProcessor createHttpProcessor();
272 protected HttpContext createHttpContext() {
273 HttpContext context = new BasicHttpContext();
274 context.setAttribute(
275 ClientContext.SCHEME_REGISTRY,
276 getConnectionManager().getSchemeRegistry());
277 context.setAttribute(
278 ClientContext.AUTHSCHEME_REGISTRY,
279 getAuthSchemes());
280 context.setAttribute(
281 ClientContext.COOKIESPEC_REGISTRY,
282 getCookieSpecs());
283 context.setAttribute(
284 ClientContext.COOKIE_STORE,
285 getCookieStore());
286 context.setAttribute(
287 ClientContext.CREDS_PROVIDER,
288 getCredentialsProvider());
289 return context;
290 }
293 protected ClientConnectionManager createClientConnectionManager() {
294 SchemeRegistry registry = SchemeRegistryFactory.createDefault();
296 ClientConnectionManager connManager = null;
297 HttpParams params = getParams();
299 ClientConnectionManagerFactory factory = null;
301 String className = (String) params.getParameter(
302 ClientPNames.CONNECTION_MANAGER_FACTORY_CLASS_NAME);
303 if (className != null) {
304 try {
305 Class<?> clazz = Class.forName(className);
306 factory = (ClientConnectionManagerFactory) clazz.newInstance();
307 } catch (ClassNotFoundException ex) {
308 throw new IllegalStateException("Invalid class name: " + className);
309 } catch (IllegalAccessException ex) {
310 throw new IllegalAccessError(ex.getMessage());
311 } catch (InstantiationException ex) {
312 throw new InstantiationError(ex.getMessage());
313 }
314 }
315 if (factory != null) {
316 connManager = factory.newInstance(params, registry);
317 } else {
318 connManager = new SingleClientConnManager(registry);
319 }
321 return connManager;
322 }
325 protected AuthSchemeRegistry createAuthSchemeRegistry() {
326 AuthSchemeRegistry registry = new AuthSchemeRegistry();
327 registry.register(
328 AuthPolicy.BASIC,
329 new BasicSchemeFactory());
330 registry.register(
331 AuthPolicy.DIGEST,
332 new DigestSchemeFactory());
333 registry.register(
334 AuthPolicy.NTLM,
335 new NTLMSchemeFactory());
336 /* NegotiateSchemeFactory removed by HttpClient for Android script. */
337 return registry;
338 }
341 protected CookieSpecRegistry createCookieSpecRegistry() {
342 CookieSpecRegistry registry = new CookieSpecRegistry();
343 registry.register(
344 CookiePolicy.BEST_MATCH,
345 new BestMatchSpecFactory());
346 registry.register(
347 CookiePolicy.BROWSER_COMPATIBILITY,
348 new BrowserCompatSpecFactory());
349 registry.register(
350 CookiePolicy.NETSCAPE,
351 new NetscapeDraftSpecFactory());
352 registry.register(
353 CookiePolicy.RFC_2109,
354 new RFC2109SpecFactory());
355 registry.register(
356 CookiePolicy.RFC_2965,
357 new RFC2965SpecFactory());
358 registry.register(
359 CookiePolicy.IGNORE_COOKIES,
360 new IgnoreSpecFactory());
361 return registry;
362 }
365 protected HttpRequestExecutor createRequestExecutor() {
366 return new HttpRequestExecutor();
367 }
370 protected ConnectionReuseStrategy createConnectionReuseStrategy() {
371 return new DefaultConnectionReuseStrategy();
372 }
375 protected ConnectionKeepAliveStrategy createConnectionKeepAliveStrategy() {
376 return new DefaultConnectionKeepAliveStrategy();
377 }
380 protected HttpRequestRetryHandler createHttpRequestRetryHandler() {
381 return new DefaultHttpRequestRetryHandler();
382 }
385 @Deprecated
386 protected RedirectHandler createRedirectHandler() {
387 return new DefaultRedirectHandler();
388 }
391 protected AuthenticationHandler createTargetAuthenticationHandler() {
392 return new DefaultTargetAuthenticationHandler();
393 }
396 protected AuthenticationHandler createProxyAuthenticationHandler() {
397 return new DefaultProxyAuthenticationHandler();
398 }
401 protected CookieStore createCookieStore() {
402 return new BasicCookieStore();
403 }
406 protected CredentialsProvider createCredentialsProvider() {
407 return new BasicCredentialsProvider();
408 }
411 protected HttpRoutePlanner createHttpRoutePlanner() {
412 return new DefaultHttpRoutePlanner(getConnectionManager().getSchemeRegistry());
413 }
416 protected UserTokenHandler createUserTokenHandler() {
417 return new DefaultUserTokenHandler();
418 }
421 // non-javadoc, see interface HttpClient
422 public synchronized final HttpParams getParams() {
423 if (defaultParams == null) {
424 defaultParams = createHttpParams();
425 }
426 return defaultParams;
427 }
430 /**
431 * Replaces the parameters.
432 * The implementation here does not update parameters of dependent objects.
433 *
434 * @param params the new default parameters
435 */
436 public synchronized void setParams(HttpParams params) {
437 defaultParams = params;
438 }
441 public synchronized final ClientConnectionManager getConnectionManager() {
442 if (connManager == null) {
443 connManager = createClientConnectionManager();
444 }
445 return connManager;
446 }
449 public synchronized final HttpRequestExecutor getRequestExecutor() {
450 if (requestExec == null) {
451 requestExec = createRequestExecutor();
452 }
453 return requestExec;
454 }
457 public synchronized final AuthSchemeRegistry getAuthSchemes() {
458 if (supportedAuthSchemes == null) {
459 supportedAuthSchemes = createAuthSchemeRegistry();
460 }
461 return supportedAuthSchemes;
462 }
465 public synchronized void setAuthSchemes(final AuthSchemeRegistry authSchemeRegistry) {
466 supportedAuthSchemes = authSchemeRegistry;
467 }
470 public synchronized final CookieSpecRegistry getCookieSpecs() {
471 if (supportedCookieSpecs == null) {
472 supportedCookieSpecs = createCookieSpecRegistry();
473 }
474 return supportedCookieSpecs;
475 }
478 public synchronized void setCookieSpecs(final CookieSpecRegistry cookieSpecRegistry) {
479 supportedCookieSpecs = cookieSpecRegistry;
480 }
483 public synchronized final ConnectionReuseStrategy getConnectionReuseStrategy() {
484 if (reuseStrategy == null) {
485 reuseStrategy = createConnectionReuseStrategy();
486 }
487 return reuseStrategy;
488 }
491 public synchronized void setReuseStrategy(final ConnectionReuseStrategy reuseStrategy) {
492 this.reuseStrategy = reuseStrategy;
493 }
496 public synchronized final ConnectionKeepAliveStrategy getConnectionKeepAliveStrategy() {
497 if (keepAliveStrategy == null) {
498 keepAliveStrategy = createConnectionKeepAliveStrategy();
499 }
500 return keepAliveStrategy;
501 }
504 public synchronized void setKeepAliveStrategy(final ConnectionKeepAliveStrategy keepAliveStrategy) {
505 this.keepAliveStrategy = keepAliveStrategy;
506 }
509 public synchronized final HttpRequestRetryHandler getHttpRequestRetryHandler() {
510 if (retryHandler == null) {
511 retryHandler = createHttpRequestRetryHandler();
512 }
513 return retryHandler;
514 }
517 public synchronized void setHttpRequestRetryHandler(final HttpRequestRetryHandler retryHandler) {
518 this.retryHandler = retryHandler;
519 }
522 @Deprecated
523 public synchronized final RedirectHandler getRedirectHandler() {
524 return createRedirectHandler();
525 }
528 @Deprecated
529 public synchronized void setRedirectHandler(final RedirectHandler redirectHandler) {
530 this.redirectStrategy = new DefaultRedirectStrategyAdaptor(redirectHandler);
531 }
533 /**
534 * @since 4.1
535 */
536 public synchronized final RedirectStrategy getRedirectStrategy() {
537 if (redirectStrategy == null) {
538 redirectStrategy = new DefaultRedirectStrategy();
539 }
540 return redirectStrategy;
541 }
543 /**
544 * @since 4.1
545 */
546 public synchronized void setRedirectStrategy(final RedirectStrategy redirectStrategy) {
547 this.redirectStrategy = redirectStrategy;
548 }
551 public synchronized final AuthenticationHandler getTargetAuthenticationHandler() {
552 if (targetAuthHandler == null) {
553 targetAuthHandler = createTargetAuthenticationHandler();
554 }
555 return targetAuthHandler;
556 }
559 public synchronized void setTargetAuthenticationHandler(
560 final AuthenticationHandler targetAuthHandler) {
561 this.targetAuthHandler = targetAuthHandler;
562 }
565 public synchronized final AuthenticationHandler getProxyAuthenticationHandler() {
566 if (proxyAuthHandler == null) {
567 proxyAuthHandler = createProxyAuthenticationHandler();
568 }
569 return proxyAuthHandler;
570 }
573 public synchronized void setProxyAuthenticationHandler(
574 final AuthenticationHandler proxyAuthHandler) {
575 this.proxyAuthHandler = proxyAuthHandler;
576 }
579 public synchronized final CookieStore getCookieStore() {
580 if (cookieStore == null) {
581 cookieStore = createCookieStore();
582 }
583 return cookieStore;
584 }
587 public synchronized void setCookieStore(final CookieStore cookieStore) {
588 this.cookieStore = cookieStore;
589 }
592 public synchronized final CredentialsProvider getCredentialsProvider() {
593 if (credsProvider == null) {
594 credsProvider = createCredentialsProvider();
595 }
596 return credsProvider;
597 }
600 public synchronized void setCredentialsProvider(final CredentialsProvider credsProvider) {
601 this.credsProvider = credsProvider;
602 }
605 public synchronized final HttpRoutePlanner getRoutePlanner() {
606 if (this.routePlanner == null) {
607 this.routePlanner = createHttpRoutePlanner();
608 }
609 return this.routePlanner;
610 }
613 public synchronized void setRoutePlanner(final HttpRoutePlanner routePlanner) {
614 this.routePlanner = routePlanner;
615 }
618 public synchronized final UserTokenHandler getUserTokenHandler() {
619 if (this.userTokenHandler == null) {
620 this.userTokenHandler = createUserTokenHandler();
621 }
622 return this.userTokenHandler;
623 }
626 public synchronized void setUserTokenHandler(final UserTokenHandler userTokenHandler) {
627 this.userTokenHandler = userTokenHandler;
628 }
631 protected synchronized final BasicHttpProcessor getHttpProcessor() {
632 if (mutableProcessor == null) {
633 mutableProcessor = createHttpProcessor();
634 }
635 return mutableProcessor;
636 }
639 private synchronized final HttpProcessor getProtocolProcessor() {
640 if (protocolProcessor == null) {
641 // Get mutable HTTP processor
642 BasicHttpProcessor proc = getHttpProcessor();
643 // and create an immutable copy of it
644 int reqc = proc.getRequestInterceptorCount();
645 HttpRequestInterceptor[] reqinterceptors = new HttpRequestInterceptor[reqc];
646 for (int i = 0; i < reqc; i++) {
647 reqinterceptors[i] = proc.getRequestInterceptor(i);
648 }
649 int resc = proc.getResponseInterceptorCount();
650 HttpResponseInterceptor[] resinterceptors = new HttpResponseInterceptor[resc];
651 for (int i = 0; i < resc; i++) {
652 resinterceptors[i] = proc.getResponseInterceptor(i);
653 }
654 protocolProcessor = new ImmutableHttpProcessor(reqinterceptors, resinterceptors);
655 }
656 return protocolProcessor;
657 }
660 public synchronized int getResponseInterceptorCount() {
661 return getHttpProcessor().getResponseInterceptorCount();
662 }
665 public synchronized HttpResponseInterceptor getResponseInterceptor(int index) {
666 return getHttpProcessor().getResponseInterceptor(index);
667 }
670 public synchronized HttpRequestInterceptor getRequestInterceptor(int index) {
671 return getHttpProcessor().getRequestInterceptor(index);
672 }
675 public synchronized int getRequestInterceptorCount() {
676 return getHttpProcessor().getRequestInterceptorCount();
677 }
680 public synchronized void addResponseInterceptor(final HttpResponseInterceptor itcp) {
681 getHttpProcessor().addInterceptor(itcp);
682 protocolProcessor = null;
683 }
686 public synchronized void addResponseInterceptor(final HttpResponseInterceptor itcp, int index) {
687 getHttpProcessor().addInterceptor(itcp, index);
688 protocolProcessor = null;
689 }
692 public synchronized void clearResponseInterceptors() {
693 getHttpProcessor().clearResponseInterceptors();
694 protocolProcessor = null;
695 }
698 public synchronized void removeResponseInterceptorByClass(Class<? extends HttpResponseInterceptor> clazz) {
699 getHttpProcessor().removeResponseInterceptorByClass(clazz);
700 protocolProcessor = null;
701 }
704 public synchronized void addRequestInterceptor(final HttpRequestInterceptor itcp) {
705 getHttpProcessor().addInterceptor(itcp);
706 protocolProcessor = null;
707 }
710 public synchronized void addRequestInterceptor(final HttpRequestInterceptor itcp, int index) {
711 getHttpProcessor().addInterceptor(itcp, index);
712 protocolProcessor = null;
713 }
716 public synchronized void clearRequestInterceptors() {
717 getHttpProcessor().clearRequestInterceptors();
718 protocolProcessor = null;
719 }
722 public synchronized void removeRequestInterceptorByClass(Class<? extends HttpRequestInterceptor> clazz) {
723 getHttpProcessor().removeRequestInterceptorByClass(clazz);
724 protocolProcessor = null;
725 }
727 public final HttpResponse execute(HttpUriRequest request)
728 throws IOException, ClientProtocolException {
730 return execute(request, (HttpContext) null);
731 }
734 /**
735 * Maps to {@link HttpClient#execute(HttpHost,HttpRequest,HttpContext)
736 * execute(target, request, context)}.
737 * The target is determined from the URI of the request.
738 *
739 * @param request the request to execute
740 * @param context the request-specific execution context,
741 * or <code>null</code> to use a default context
742 */
743 public final HttpResponse execute(HttpUriRequest request,
744 HttpContext context)
745 throws IOException, ClientProtocolException {
747 if (request == null) {
748 throw new IllegalArgumentException
749 ("Request must not be null.");
750 }
752 return execute(determineTarget(request), request, context);
753 }
755 private static HttpHost determineTarget(HttpUriRequest request) throws ClientProtocolException {
756 // A null target may be acceptable if there is a default target.
757 // Otherwise, the null target is detected in the director.
758 HttpHost target = null;
760 URI requestURI = request.getURI();
761 if (requestURI.isAbsolute()) {
762 target = URIUtils.extractHost(requestURI);
763 if (target == null) {
764 throw new ClientProtocolException(
765 "URI does not specify a valid host name: " + requestURI);
766 }
767 }
768 return target;
769 }
771 public final HttpResponse execute(HttpHost target, HttpRequest request)
772 throws IOException, ClientProtocolException {
774 return execute(target, request, (HttpContext) null);
775 }
777 public final HttpResponse execute(HttpHost target, HttpRequest request,
778 HttpContext context)
779 throws IOException, ClientProtocolException {
781 if (request == null) {
782 throw new IllegalArgumentException
783 ("Request must not be null.");
784 }
785 // a null target may be acceptable, this depends on the route planner
786 // a null context is acceptable, default context created below
788 HttpContext execContext = null;
789 RequestDirector director = null;
791 // Initialize the request execution context making copies of
792 // all shared objects that are potentially threading unsafe.
793 synchronized (this) {
795 HttpContext defaultContext = createHttpContext();
796 if (context == null) {
797 execContext = defaultContext;
798 } else {
799 execContext = new DefaultedHttpContext(context, defaultContext);
800 }
801 // Create a director for this request
802 director = createClientRequestDirector(
803 getRequestExecutor(),
804 getConnectionManager(),
805 getConnectionReuseStrategy(),
806 getConnectionKeepAliveStrategy(),
807 getRoutePlanner(),
808 getProtocolProcessor(),
809 getHttpRequestRetryHandler(),
810 getRedirectStrategy(),
811 getTargetAuthenticationHandler(),
812 getProxyAuthenticationHandler(),
813 getUserTokenHandler(),
814 determineParams(request));
815 }
817 try {
818 return director.execute(target, request, execContext);
819 } catch(HttpException httpException) {
820 throw new ClientProtocolException(httpException);
821 }
822 }
824 @Deprecated
825 protected RequestDirector createClientRequestDirector(
826 final HttpRequestExecutor requestExec,
827 final ClientConnectionManager conman,
828 final ConnectionReuseStrategy reustrat,
829 final ConnectionKeepAliveStrategy kastrat,
830 final HttpRoutePlanner rouplan,
831 final HttpProcessor httpProcessor,
832 final HttpRequestRetryHandler retryHandler,
833 final ch.boye.httpclientandroidlib.client.RedirectHandler redirectHandler,
834 final AuthenticationHandler targetAuthHandler,
835 final AuthenticationHandler proxyAuthHandler,
836 final UserTokenHandler stateHandler,
837 final HttpParams params) {
838 return new DefaultRequestDirector(
839 requestExec,
840 conman,
841 reustrat,
842 kastrat,
843 rouplan,
844 httpProcessor,
845 retryHandler,
846 redirectHandler,
847 targetAuthHandler,
848 proxyAuthHandler,
849 stateHandler,
850 params);
851 }
853 /**
854 * @since 4.1
855 */
856 protected RequestDirector createClientRequestDirector(
857 final HttpRequestExecutor requestExec,
858 final ClientConnectionManager conman,
859 final ConnectionReuseStrategy reustrat,
860 final ConnectionKeepAliveStrategy kastrat,
861 final HttpRoutePlanner rouplan,
862 final HttpProcessor httpProcessor,
863 final HttpRequestRetryHandler retryHandler,
864 final RedirectStrategy redirectStrategy,
865 final AuthenticationHandler targetAuthHandler,
866 final AuthenticationHandler proxyAuthHandler,
867 final UserTokenHandler stateHandler,
868 final HttpParams params) {
869 return new DefaultRequestDirector(
870 log,
871 requestExec,
872 conman,
873 reustrat,
874 kastrat,
875 rouplan,
876 httpProcessor,
877 retryHandler,
878 redirectStrategy,
879 targetAuthHandler,
880 proxyAuthHandler,
881 stateHandler,
882 params);
883 }
884 /**
885 * Obtains parameters for executing a request.
886 * The default implementation in this class creates a new
887 * {@link ClientParamsStack} from the request parameters
888 * and the client parameters.
889 * <br/>
890 * This method is called by the default implementation of
891 * {@link #execute(HttpHost,HttpRequest,HttpContext)}
892 * to obtain the parameters for the
893 * {@link DefaultRequestDirector}.
894 *
895 * @param req the request that will be executed
896 *
897 * @return the parameters to use
898 */
899 protected HttpParams determineParams(HttpRequest req) {
900 return new ClientParamsStack
901 (null, getParams(), req.getParams(), null);
902 }
904 public <T> T execute(
905 final HttpUriRequest request,
906 final ResponseHandler<? extends T> responseHandler)
907 throws IOException, ClientProtocolException {
908 return execute(request, responseHandler, null);
909 }
911 public <T> T execute(
912 final HttpUriRequest request,
913 final ResponseHandler<? extends T> responseHandler,
914 final HttpContext context)
915 throws IOException, ClientProtocolException {
916 HttpHost target = determineTarget(request);
917 return execute(target, request, responseHandler, context);
918 }
920 public <T> T execute(
921 final HttpHost target,
922 final HttpRequest request,
923 final ResponseHandler<? extends T> responseHandler)
924 throws IOException, ClientProtocolException {
925 return execute(target, request, responseHandler, null);
926 }
928 public <T> T execute(
929 final HttpHost target,
930 final HttpRequest request,
931 final ResponseHandler<? extends T> responseHandler,
932 final HttpContext context)
933 throws IOException, ClientProtocolException {
934 if (responseHandler == null) {
935 throw new IllegalArgumentException
936 ("Response handler must not be null.");
937 }
939 HttpResponse response = execute(target, request, context);
941 T result;
942 try {
943 result = responseHandler.handleResponse(response);
944 } catch (Throwable t) {
945 HttpEntity entity = response.getEntity();
946 try {
947 EntityUtils.consume(entity);
948 } catch (Exception t2) {
949 // Log this exception. The original exception is more
950 // important and will be thrown to the caller.
951 this.log.warn("Error consuming content after an exception.", t2);
952 }
954 if (t instanceof Error) {
955 throw (Error) t;
956 }
958 if (t instanceof RuntimeException) {
959 throw (RuntimeException) t;
960 }
962 if (t instanceof IOException) {
963 throw (IOException) t;
964 }
966 throw new UndeclaredThrowableException(t);
967 }
969 // Handling the response was successful. Ensure that the content has
970 // been fully consumed.
971 HttpEntity entity = response.getEntity();
972 EntityUtils.consume(entity);
973 return result;
974 }
976 }