|
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 import java.net.URI; |
|
33 |
|
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; |
|
93 |
|
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 { |
|
181 |
|
182 public HttpClientAndroidLog log = new HttpClientAndroidLog(getClass()); |
|
183 |
|
184 /** The parameters. */ |
|
185 @GuardedBy("this") |
|
186 private HttpParams defaultParams; |
|
187 |
|
188 /** The request executor. */ |
|
189 @GuardedBy("this") |
|
190 private HttpRequestExecutor requestExec; |
|
191 |
|
192 /** The connection manager. */ |
|
193 @GuardedBy("this") |
|
194 private ClientConnectionManager connManager; |
|
195 |
|
196 /** The connection re-use strategy. */ |
|
197 @GuardedBy("this") |
|
198 private ConnectionReuseStrategy reuseStrategy; |
|
199 |
|
200 /** The connection keep-alive strategy. */ |
|
201 @GuardedBy("this") |
|
202 private ConnectionKeepAliveStrategy keepAliveStrategy; |
|
203 |
|
204 /** The cookie spec registry. */ |
|
205 @GuardedBy("this") |
|
206 private CookieSpecRegistry supportedCookieSpecs; |
|
207 |
|
208 /** The authentication scheme registry. */ |
|
209 @GuardedBy("this") |
|
210 private AuthSchemeRegistry supportedAuthSchemes; |
|
211 |
|
212 /** The HTTP protocol processor and its immutable copy. */ |
|
213 @GuardedBy("this") |
|
214 private BasicHttpProcessor mutableProcessor; |
|
215 |
|
216 @GuardedBy("this") |
|
217 private ImmutableHttpProcessor protocolProcessor; |
|
218 |
|
219 /** The request retry handler. */ |
|
220 @GuardedBy("this") |
|
221 private HttpRequestRetryHandler retryHandler; |
|
222 |
|
223 /** The redirect handler. */ |
|
224 @GuardedBy("this") |
|
225 private RedirectStrategy redirectStrategy; |
|
226 |
|
227 /** The target authentication handler. */ |
|
228 @GuardedBy("this") |
|
229 private AuthenticationHandler targetAuthHandler; |
|
230 |
|
231 /** The proxy authentication handler. */ |
|
232 @GuardedBy("this") |
|
233 private AuthenticationHandler proxyAuthHandler; |
|
234 |
|
235 /** The cookie store. */ |
|
236 @GuardedBy("this") |
|
237 private CookieStore cookieStore; |
|
238 |
|
239 /** The credentials provider. */ |
|
240 @GuardedBy("this") |
|
241 private CredentialsProvider credsProvider; |
|
242 |
|
243 /** The route planner. */ |
|
244 @GuardedBy("this") |
|
245 private HttpRoutePlanner routePlanner; |
|
246 |
|
247 /** The user token handler. */ |
|
248 @GuardedBy("this") |
|
249 private UserTokenHandler userTokenHandler; |
|
250 |
|
251 |
|
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 |
|
264 |
|
265 |
|
266 protected abstract HttpParams createHttpParams(); |
|
267 |
|
268 |
|
269 protected abstract BasicHttpProcessor createHttpProcessor(); |
|
270 |
|
271 |
|
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 } |
|
291 |
|
292 |
|
293 protected ClientConnectionManager createClientConnectionManager() { |
|
294 SchemeRegistry registry = SchemeRegistryFactory.createDefault(); |
|
295 |
|
296 ClientConnectionManager connManager = null; |
|
297 HttpParams params = getParams(); |
|
298 |
|
299 ClientConnectionManagerFactory factory = null; |
|
300 |
|
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 } |
|
320 |
|
321 return connManager; |
|
322 } |
|
323 |
|
324 |
|
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 } |
|
339 |
|
340 |
|
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 } |
|
363 |
|
364 |
|
365 protected HttpRequestExecutor createRequestExecutor() { |
|
366 return new HttpRequestExecutor(); |
|
367 } |
|
368 |
|
369 |
|
370 protected ConnectionReuseStrategy createConnectionReuseStrategy() { |
|
371 return new DefaultConnectionReuseStrategy(); |
|
372 } |
|
373 |
|
374 |
|
375 protected ConnectionKeepAliveStrategy createConnectionKeepAliveStrategy() { |
|
376 return new DefaultConnectionKeepAliveStrategy(); |
|
377 } |
|
378 |
|
379 |
|
380 protected HttpRequestRetryHandler createHttpRequestRetryHandler() { |
|
381 return new DefaultHttpRequestRetryHandler(); |
|
382 } |
|
383 |
|
384 |
|
385 @Deprecated |
|
386 protected RedirectHandler createRedirectHandler() { |
|
387 return new DefaultRedirectHandler(); |
|
388 } |
|
389 |
|
390 |
|
391 protected AuthenticationHandler createTargetAuthenticationHandler() { |
|
392 return new DefaultTargetAuthenticationHandler(); |
|
393 } |
|
394 |
|
395 |
|
396 protected AuthenticationHandler createProxyAuthenticationHandler() { |
|
397 return new DefaultProxyAuthenticationHandler(); |
|
398 } |
|
399 |
|
400 |
|
401 protected CookieStore createCookieStore() { |
|
402 return new BasicCookieStore(); |
|
403 } |
|
404 |
|
405 |
|
406 protected CredentialsProvider createCredentialsProvider() { |
|
407 return new BasicCredentialsProvider(); |
|
408 } |
|
409 |
|
410 |
|
411 protected HttpRoutePlanner createHttpRoutePlanner() { |
|
412 return new DefaultHttpRoutePlanner(getConnectionManager().getSchemeRegistry()); |
|
413 } |
|
414 |
|
415 |
|
416 protected UserTokenHandler createUserTokenHandler() { |
|
417 return new DefaultUserTokenHandler(); |
|
418 } |
|
419 |
|
420 |
|
421 // non-javadoc, see interface HttpClient |
|
422 public synchronized final HttpParams getParams() { |
|
423 if (defaultParams == null) { |
|
424 defaultParams = createHttpParams(); |
|
425 } |
|
426 return defaultParams; |
|
427 } |
|
428 |
|
429 |
|
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 } |
|
439 |
|
440 |
|
441 public synchronized final ClientConnectionManager getConnectionManager() { |
|
442 if (connManager == null) { |
|
443 connManager = createClientConnectionManager(); |
|
444 } |
|
445 return connManager; |
|
446 } |
|
447 |
|
448 |
|
449 public synchronized final HttpRequestExecutor getRequestExecutor() { |
|
450 if (requestExec == null) { |
|
451 requestExec = createRequestExecutor(); |
|
452 } |
|
453 return requestExec; |
|
454 } |
|
455 |
|
456 |
|
457 public synchronized final AuthSchemeRegistry getAuthSchemes() { |
|
458 if (supportedAuthSchemes == null) { |
|
459 supportedAuthSchemes = createAuthSchemeRegistry(); |
|
460 } |
|
461 return supportedAuthSchemes; |
|
462 } |
|
463 |
|
464 |
|
465 public synchronized void setAuthSchemes(final AuthSchemeRegistry authSchemeRegistry) { |
|
466 supportedAuthSchemes = authSchemeRegistry; |
|
467 } |
|
468 |
|
469 |
|
470 public synchronized final CookieSpecRegistry getCookieSpecs() { |
|
471 if (supportedCookieSpecs == null) { |
|
472 supportedCookieSpecs = createCookieSpecRegistry(); |
|
473 } |
|
474 return supportedCookieSpecs; |
|
475 } |
|
476 |
|
477 |
|
478 public synchronized void setCookieSpecs(final CookieSpecRegistry cookieSpecRegistry) { |
|
479 supportedCookieSpecs = cookieSpecRegistry; |
|
480 } |
|
481 |
|
482 |
|
483 public synchronized final ConnectionReuseStrategy getConnectionReuseStrategy() { |
|
484 if (reuseStrategy == null) { |
|
485 reuseStrategy = createConnectionReuseStrategy(); |
|
486 } |
|
487 return reuseStrategy; |
|
488 } |
|
489 |
|
490 |
|
491 public synchronized void setReuseStrategy(final ConnectionReuseStrategy reuseStrategy) { |
|
492 this.reuseStrategy = reuseStrategy; |
|
493 } |
|
494 |
|
495 |
|
496 public synchronized final ConnectionKeepAliveStrategy getConnectionKeepAliveStrategy() { |
|
497 if (keepAliveStrategy == null) { |
|
498 keepAliveStrategy = createConnectionKeepAliveStrategy(); |
|
499 } |
|
500 return keepAliveStrategy; |
|
501 } |
|
502 |
|
503 |
|
504 public synchronized void setKeepAliveStrategy(final ConnectionKeepAliveStrategy keepAliveStrategy) { |
|
505 this.keepAliveStrategy = keepAliveStrategy; |
|
506 } |
|
507 |
|
508 |
|
509 public synchronized final HttpRequestRetryHandler getHttpRequestRetryHandler() { |
|
510 if (retryHandler == null) { |
|
511 retryHandler = createHttpRequestRetryHandler(); |
|
512 } |
|
513 return retryHandler; |
|
514 } |
|
515 |
|
516 |
|
517 public synchronized void setHttpRequestRetryHandler(final HttpRequestRetryHandler retryHandler) { |
|
518 this.retryHandler = retryHandler; |
|
519 } |
|
520 |
|
521 |
|
522 @Deprecated |
|
523 public synchronized final RedirectHandler getRedirectHandler() { |
|
524 return createRedirectHandler(); |
|
525 } |
|
526 |
|
527 |
|
528 @Deprecated |
|
529 public synchronized void setRedirectHandler(final RedirectHandler redirectHandler) { |
|
530 this.redirectStrategy = new DefaultRedirectStrategyAdaptor(redirectHandler); |
|
531 } |
|
532 |
|
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 } |
|
542 |
|
543 /** |
|
544 * @since 4.1 |
|
545 */ |
|
546 public synchronized void setRedirectStrategy(final RedirectStrategy redirectStrategy) { |
|
547 this.redirectStrategy = redirectStrategy; |
|
548 } |
|
549 |
|
550 |
|
551 public synchronized final AuthenticationHandler getTargetAuthenticationHandler() { |
|
552 if (targetAuthHandler == null) { |
|
553 targetAuthHandler = createTargetAuthenticationHandler(); |
|
554 } |
|
555 return targetAuthHandler; |
|
556 } |
|
557 |
|
558 |
|
559 public synchronized void setTargetAuthenticationHandler( |
|
560 final AuthenticationHandler targetAuthHandler) { |
|
561 this.targetAuthHandler = targetAuthHandler; |
|
562 } |
|
563 |
|
564 |
|
565 public synchronized final AuthenticationHandler getProxyAuthenticationHandler() { |
|
566 if (proxyAuthHandler == null) { |
|
567 proxyAuthHandler = createProxyAuthenticationHandler(); |
|
568 } |
|
569 return proxyAuthHandler; |
|
570 } |
|
571 |
|
572 |
|
573 public synchronized void setProxyAuthenticationHandler( |
|
574 final AuthenticationHandler proxyAuthHandler) { |
|
575 this.proxyAuthHandler = proxyAuthHandler; |
|
576 } |
|
577 |
|
578 |
|
579 public synchronized final CookieStore getCookieStore() { |
|
580 if (cookieStore == null) { |
|
581 cookieStore = createCookieStore(); |
|
582 } |
|
583 return cookieStore; |
|
584 } |
|
585 |
|
586 |
|
587 public synchronized void setCookieStore(final CookieStore cookieStore) { |
|
588 this.cookieStore = cookieStore; |
|
589 } |
|
590 |
|
591 |
|
592 public synchronized final CredentialsProvider getCredentialsProvider() { |
|
593 if (credsProvider == null) { |
|
594 credsProvider = createCredentialsProvider(); |
|
595 } |
|
596 return credsProvider; |
|
597 } |
|
598 |
|
599 |
|
600 public synchronized void setCredentialsProvider(final CredentialsProvider credsProvider) { |
|
601 this.credsProvider = credsProvider; |
|
602 } |
|
603 |
|
604 |
|
605 public synchronized final HttpRoutePlanner getRoutePlanner() { |
|
606 if (this.routePlanner == null) { |
|
607 this.routePlanner = createHttpRoutePlanner(); |
|
608 } |
|
609 return this.routePlanner; |
|
610 } |
|
611 |
|
612 |
|
613 public synchronized void setRoutePlanner(final HttpRoutePlanner routePlanner) { |
|
614 this.routePlanner = routePlanner; |
|
615 } |
|
616 |
|
617 |
|
618 public synchronized final UserTokenHandler getUserTokenHandler() { |
|
619 if (this.userTokenHandler == null) { |
|
620 this.userTokenHandler = createUserTokenHandler(); |
|
621 } |
|
622 return this.userTokenHandler; |
|
623 } |
|
624 |
|
625 |
|
626 public synchronized void setUserTokenHandler(final UserTokenHandler userTokenHandler) { |
|
627 this.userTokenHandler = userTokenHandler; |
|
628 } |
|
629 |
|
630 |
|
631 protected synchronized final BasicHttpProcessor getHttpProcessor() { |
|
632 if (mutableProcessor == null) { |
|
633 mutableProcessor = createHttpProcessor(); |
|
634 } |
|
635 return mutableProcessor; |
|
636 } |
|
637 |
|
638 |
|
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 } |
|
658 |
|
659 |
|
660 public synchronized int getResponseInterceptorCount() { |
|
661 return getHttpProcessor().getResponseInterceptorCount(); |
|
662 } |
|
663 |
|
664 |
|
665 public synchronized HttpResponseInterceptor getResponseInterceptor(int index) { |
|
666 return getHttpProcessor().getResponseInterceptor(index); |
|
667 } |
|
668 |
|
669 |
|
670 public synchronized HttpRequestInterceptor getRequestInterceptor(int index) { |
|
671 return getHttpProcessor().getRequestInterceptor(index); |
|
672 } |
|
673 |
|
674 |
|
675 public synchronized int getRequestInterceptorCount() { |
|
676 return getHttpProcessor().getRequestInterceptorCount(); |
|
677 } |
|
678 |
|
679 |
|
680 public synchronized void addResponseInterceptor(final HttpResponseInterceptor itcp) { |
|
681 getHttpProcessor().addInterceptor(itcp); |
|
682 protocolProcessor = null; |
|
683 } |
|
684 |
|
685 |
|
686 public synchronized void addResponseInterceptor(final HttpResponseInterceptor itcp, int index) { |
|
687 getHttpProcessor().addInterceptor(itcp, index); |
|
688 protocolProcessor = null; |
|
689 } |
|
690 |
|
691 |
|
692 public synchronized void clearResponseInterceptors() { |
|
693 getHttpProcessor().clearResponseInterceptors(); |
|
694 protocolProcessor = null; |
|
695 } |
|
696 |
|
697 |
|
698 public synchronized void removeResponseInterceptorByClass(Class<? extends HttpResponseInterceptor> clazz) { |
|
699 getHttpProcessor().removeResponseInterceptorByClass(clazz); |
|
700 protocolProcessor = null; |
|
701 } |
|
702 |
|
703 |
|
704 public synchronized void addRequestInterceptor(final HttpRequestInterceptor itcp) { |
|
705 getHttpProcessor().addInterceptor(itcp); |
|
706 protocolProcessor = null; |
|
707 } |
|
708 |
|
709 |
|
710 public synchronized void addRequestInterceptor(final HttpRequestInterceptor itcp, int index) { |
|
711 getHttpProcessor().addInterceptor(itcp, index); |
|
712 protocolProcessor = null; |
|
713 } |
|
714 |
|
715 |
|
716 public synchronized void clearRequestInterceptors() { |
|
717 getHttpProcessor().clearRequestInterceptors(); |
|
718 protocolProcessor = null; |
|
719 } |
|
720 |
|
721 |
|
722 public synchronized void removeRequestInterceptorByClass(Class<? extends HttpRequestInterceptor> clazz) { |
|
723 getHttpProcessor().removeRequestInterceptorByClass(clazz); |
|
724 protocolProcessor = null; |
|
725 } |
|
726 |
|
727 public final HttpResponse execute(HttpUriRequest request) |
|
728 throws IOException, ClientProtocolException { |
|
729 |
|
730 return execute(request, (HttpContext) null); |
|
731 } |
|
732 |
|
733 |
|
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 { |
|
746 |
|
747 if (request == null) { |
|
748 throw new IllegalArgumentException |
|
749 ("Request must not be null."); |
|
750 } |
|
751 |
|
752 return execute(determineTarget(request), request, context); |
|
753 } |
|
754 |
|
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; |
|
759 |
|
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 } |
|
770 |
|
771 public final HttpResponse execute(HttpHost target, HttpRequest request) |
|
772 throws IOException, ClientProtocolException { |
|
773 |
|
774 return execute(target, request, (HttpContext) null); |
|
775 } |
|
776 |
|
777 public final HttpResponse execute(HttpHost target, HttpRequest request, |
|
778 HttpContext context) |
|
779 throws IOException, ClientProtocolException { |
|
780 |
|
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 |
|
787 |
|
788 HttpContext execContext = null; |
|
789 RequestDirector director = 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 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 } |
|
816 |
|
817 try { |
|
818 return director.execute(target, request, execContext); |
|
819 } catch(HttpException httpException) { |
|
820 throw new ClientProtocolException(httpException); |
|
821 } |
|
822 } |
|
823 |
|
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 } |
|
852 |
|
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 } |
|
903 |
|
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 } |
|
910 |
|
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 } |
|
919 |
|
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 } |
|
927 |
|
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 } |
|
938 |
|
939 HttpResponse response = execute(target, request, context); |
|
940 |
|
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 } |
|
953 |
|
954 if (t instanceof Error) { |
|
955 throw (Error) t; |
|
956 } |
|
957 |
|
958 if (t instanceof RuntimeException) { |
|
959 throw (RuntimeException) t; |
|
960 } |
|
961 |
|
962 if (t instanceof IOException) { |
|
963 throw (IOException) t; |
|
964 } |
|
965 |
|
966 throw new UndeclaredThrowableException(t); |
|
967 } |
|
968 |
|
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 } |
|
975 |
|
976 } |