1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 package org.apache.commons.httpclient;
31
32 import java.io.IOException;
33 import java.util.Collection;
34 import java.util.HashSet;
35 import java.util.Iterator;
36 import java.util.Map;
37 import java.util.Set;
38
39 import org.apache.commons.httpclient.auth.AuthChallengeException;
40 import org.apache.commons.httpclient.auth.AuthChallengeParser;
41 import org.apache.commons.httpclient.auth.AuthChallengeProcessor;
42 import org.apache.commons.httpclient.auth.AuthScheme;
43 import org.apache.commons.httpclient.auth.AuthState;
44 import org.apache.commons.httpclient.auth.AuthenticationException;
45 import org.apache.commons.httpclient.auth.CredentialsProvider;
46 import org.apache.commons.httpclient.auth.CredentialsNotAvailableException;
47 import org.apache.commons.httpclient.auth.AuthScope;
48 import org.apache.commons.httpclient.auth.MalformedChallengeException;
49 import org.apache.commons.httpclient.params.HostParams;
50 import org.apache.commons.httpclient.params.HttpClientParams;
51 import org.apache.commons.httpclient.params.HttpConnectionParams;
52 import org.apache.commons.httpclient.params.HttpMethodParams;
53 import org.apache.commons.httpclient.params.HttpParams;
54 import org.apache.commons.logging.Log;
55 import org.apache.commons.logging.LogFactory;
56
57 /***
58 * Handles the process of executing a method including authentication, redirection and retries.
59 *
60 * @since 3.0
61 */
62 class HttpMethodDirector {
63
64 /*** The www authenticate challange header. */
65 public static final String WWW_AUTH_CHALLENGE = "WWW-Authenticate";
66
67 /*** The www authenticate response header. */
68 public static final String WWW_AUTH_RESP = "Authorization";
69
70 /*** The proxy authenticate challange header. */
71 public static final String PROXY_AUTH_CHALLENGE = "Proxy-Authenticate";
72
73 /*** The proxy authenticate response header. */
74 public static final String PROXY_AUTH_RESP = "Proxy-Authorization";
75
76 private static final Log LOG = LogFactory.getLog(HttpMethodDirector.class);
77
78 private ConnectMethod connectMethod;
79
80 private HttpState state;
81
82 private HostConfiguration hostConfiguration;
83
84 private HttpConnectionManager connectionManager;
85
86 private HttpClientParams params;
87
88 private HttpConnection conn;
89
90 /*** A flag to indicate if the connection should be released after the method is executed. */
91 private boolean releaseConnection = false;
92
93 /*** Authentication processor */
94 private AuthChallengeProcessor authProcessor = null;
95
96 private Set redirectLocations = null;
97
98 public HttpMethodDirector(
99 final HttpConnectionManager connectionManager,
100 final HostConfiguration hostConfiguration,
101 final HttpClientParams params,
102 final HttpState state
103 ) {
104 super();
105 this.connectionManager = connectionManager;
106 this.hostConfiguration = hostConfiguration;
107 this.params = params;
108 this.state = state;
109 this.authProcessor = new AuthChallengeProcessor(this.params);
110 }
111
112
113 /***
114 * Executes the method associated with this method director.
115 *
116 * @throws IOException
117 * @throws HttpException
118 */
119 public void executeMethod(final HttpMethod method) throws IOException, HttpException {
120 if (method == null) {
121 throw new IllegalArgumentException("Method may not be null");
122 }
123
124
125 this.hostConfiguration.getParams().setDefaults(this.params);
126 method.getParams().setDefaults(this.hostConfiguration.getParams());
127
128
129 Collection defaults = (Collection)this.hostConfiguration.getParams().
130 getParameter(HostParams.DEFAULT_HEADERS);
131 if (defaults != null) {
132 Iterator i = defaults.iterator();
133 while (i.hasNext()) {
134 method.addRequestHeader((Header)i.next());
135 }
136 }
137
138 try {
139 int maxRedirects = this.params.getIntParameter(HttpClientParams.MAX_REDIRECTS, 100);
140
141 for (int redirectCount = 0;;) {
142
143
144 if (this.conn != null && !hostConfiguration.hostEquals(this.conn)) {
145 this.conn.setLocked(false);
146 this.conn.releaseConnection();
147 this.conn = null;
148 }
149
150
151 if (this.conn == null) {
152 this.conn = connectionManager.getConnectionWithTimeout(
153 hostConfiguration,
154 this.params.getConnectionManagerTimeout()
155 );
156 this.conn.setLocked(true);
157 if (this.params.isAuthenticationPreemptive()
158 || this.state.isAuthenticationPreemptive())
159 {
160 LOG.debug("Preemptively sending default basic credentials");
161 method.getHostAuthState().setPreemptive();
162 method.getHostAuthState().setAuthAttempted(true);
163 if (this.conn.isProxied() && !this.conn.isSecure()) {
164 method.getProxyAuthState().setPreemptive();
165 method.getProxyAuthState().setAuthAttempted(true);
166 }
167 }
168 }
169 authenticate(method);
170 executeWithRetry(method);
171 if (this.connectMethod != null) {
172 fakeResponse(method);
173 break;
174 }
175
176 boolean retry = false;
177 if (isRedirectNeeded(method)) {
178 if (processRedirectResponse(method)) {
179 retry = true;
180 ++redirectCount;
181 if (redirectCount >= maxRedirects) {
182 LOG.error("Narrowly avoided an infinite loop in execute");
183 throw new RedirectException("Maximum redirects ("
184 + maxRedirects + ") exceeded");
185 }
186 if (LOG.isDebugEnabled()) {
187 LOG.debug("Execute redirect " + redirectCount + " of " + maxRedirects);
188 }
189 }
190 }
191 if (isAuthenticationNeeded(method)) {
192 if (processAuthenticationResponse(method)) {
193 LOG.debug("Retry authentication");
194 retry = true;
195 }
196 }
197 if (!retry) {
198 break;
199 }
200
201
202
203 if (method.getResponseBodyAsStream() != null) {
204 method.getResponseBodyAsStream().close();
205 }
206
207 }
208 } finally {
209 if (this.conn != null) {
210 this.conn.setLocked(false);
211 }
212
213
214
215
216
217 if (
218 (releaseConnection || method.getResponseBodyAsStream() == null)
219 && this.conn != null
220 ) {
221 this.conn.releaseConnection();
222 }
223 }
224
225 }
226
227
228 private void authenticate(final HttpMethod method) {
229 try {
230 if (this.conn.isProxied() && !this.conn.isSecure()) {
231 authenticateProxy(method);
232 }
233 authenticateHost(method);
234 } catch (AuthenticationException e) {
235 LOG.error(e.getMessage(), e);
236 }
237 }
238
239
240 private boolean cleanAuthHeaders(final HttpMethod method, final String name) {
241 Header[] authheaders = method.getRequestHeaders(name);
242 boolean clean = true;
243 for (int i = 0; i < authheaders.length; i++) {
244 Header authheader = authheaders[i];
245 if (authheader.isAutogenerated()) {
246 method.removeRequestHeader(authheader);
247 } else {
248 clean = false;
249 }
250 }
251 return clean;
252 }
253
254
255 private void authenticateHost(final HttpMethod method) throws AuthenticationException {
256
257 if (!cleanAuthHeaders(method, WWW_AUTH_RESP)) {
258
259 return;
260 }
261 AuthState authstate = method.getHostAuthState();
262 AuthScheme authscheme = authstate.getAuthScheme();
263 if (authscheme == null) {
264 return;
265 }
266 if (authstate.isAuthRequested() || !authscheme.isConnectionBased()) {
267 String host = method.getParams().getVirtualHost();
268 if (host == null) {
269 host = conn.getHost();
270 }
271 int port = conn.getPort();
272 AuthScope authscope = new AuthScope(
273 host, port,
274 authscheme.getRealm(),
275 authscheme.getSchemeName());
276 if (LOG.isDebugEnabled()) {
277 LOG.debug("Authenticating with " + authscope);
278 }
279 Credentials credentials = this.state.getCredentials(authscope);
280 if (credentials != null) {
281 String authstring = authscheme.authenticate(credentials, method);
282 if (authstring != null) {
283 method.addRequestHeader(new Header(WWW_AUTH_RESP, authstring, true));
284 }
285 } else {
286 if (LOG.isWarnEnabled()) {
287 LOG.warn("Required credentials not available for " + authscope);
288 if (method.getHostAuthState().isPreemptive()) {
289 LOG.warn("Preemptive authentication requested but no default " +
290 "credentials available");
291 }
292 }
293 }
294 }
295 }
296
297
298 private void authenticateProxy(final HttpMethod method) throws AuthenticationException {
299
300 if (!cleanAuthHeaders(method, PROXY_AUTH_RESP)) {
301
302 return;
303 }
304 AuthState authstate = method.getProxyAuthState();
305 AuthScheme authscheme = authstate.getAuthScheme();
306 if (authscheme == null) {
307 return;
308 }
309 if (authstate.isAuthRequested() || !authscheme.isConnectionBased()) {
310 AuthScope authscope = new AuthScope(
311 conn.getProxyHost(), conn.getProxyPort(),
312 authscheme.getRealm(),
313 authscheme.getSchemeName());
314 if (LOG.isDebugEnabled()) {
315 LOG.debug("Authenticating with " + authscope);
316 }
317 Credentials credentials = this.state.getProxyCredentials(authscope);
318 if (credentials != null) {
319 String authstring = authscheme.authenticate(credentials, method);
320 if (authstring != null) {
321 method.addRequestHeader(new Header(PROXY_AUTH_RESP, authstring, true));
322 }
323 } else {
324 if (LOG.isWarnEnabled()) {
325 LOG.warn("Required proxy credentials not available for " + authscope);
326 if (method.getProxyAuthState().isPreemptive()) {
327 LOG.warn("Preemptive authentication requested but no default " +
328 "proxy credentials available");
329 }
330 }
331 }
332 }
333 }
334
335
336 /***
337 * Applies connection parameters specified for a given method
338 *
339 * @param method HTTP method
340 *
341 * @throws IOException if an I/O occurs setting connection parameters
342 */
343 private void applyConnectionParams(final HttpMethod method) throws IOException {
344 int timeout = 0;
345
346 Object param = method.getParams().getParameter(HttpMethodParams.SO_TIMEOUT);
347 if (param == null) {
348
349 param = this.conn.getParams().getParameter(HttpConnectionParams.SO_TIMEOUT);
350 }
351 if (param != null) {
352 timeout = ((Integer)param).intValue();
353 }
354 this.conn.setSocketTimeout(timeout);
355 }
356
357 /***
358 * Executes a method with the current hostConfiguration.
359 *
360 * @throws IOException if an I/O (transport) error occurs. Some transport exceptions
361 * can be recovered from.
362 * @throws HttpException if a protocol exception occurs. Usually protocol exceptions
363 * cannot be recovered from.
364 */
365 private void executeWithRetry(final HttpMethod method)
366 throws IOException, HttpException {
367
368 /*** How many times did this transparently handle a recoverable exception? */
369 int execCount = 0;
370
371
372 try {
373 while (true) {
374 execCount++;
375 try {
376
377 if (LOG.isTraceEnabled()) {
378 LOG.trace("Attempt number " + execCount + " to process request");
379 }
380 if (this.conn.getParams().isStaleCheckingEnabled()) {
381 this.conn.closeIfStale();
382 }
383 if (!this.conn.isOpen()) {
384
385
386 this.conn.open();
387 if (this.conn.isProxied() && this.conn.isSecure()
388 && !(method instanceof ConnectMethod)) {
389
390 if (!executeConnect()) {
391
392 return;
393 }
394 }
395 }
396 applyConnectionParams(method);
397 method.execute(state, this.conn);
398 break;
399 } catch (HttpException e) {
400
401 throw e;
402 } catch (IOException e) {
403 LOG.debug("Closing the connection.");
404 this.conn.close();
405
406
407
408
409 if (method instanceof HttpMethodBase) {
410 MethodRetryHandler handler =
411 ((HttpMethodBase)method).getMethodRetryHandler();
412 if (handler != null) {
413 if (!handler.retryMethod(
414 method,
415 this.conn,
416 new HttpRecoverableException(e.getMessage()),
417 execCount,
418 method.isRequestSent())) {
419 LOG.debug("Method retry handler returned false. "
420 + "Automatic recovery will not be attempted");
421 throw e;
422 }
423 }
424 }
425
426 HttpMethodRetryHandler handler =
427 (HttpMethodRetryHandler)method.getParams().getParameter(
428 HttpMethodParams.RETRY_HANDLER);
429 if (handler == null) {
430 handler = new DefaultHttpMethodRetryHandler();
431 }
432 if (!handler.retryMethod(method, e, execCount)) {
433 LOG.debug("Method retry handler returned false. "
434 + "Automatic recovery will not be attempted");
435 throw e;
436 }
437 if (LOG.isInfoEnabled()) {
438 LOG.info("I/O exception ("+ e.getClass().getName() +") caught when processing request: "
439 + e.getMessage());
440 }
441 if (LOG.isDebugEnabled()) {
442 LOG.debug(e.getMessage(), e);
443 }
444 LOG.info("Retrying request");
445 }
446 }
447 } catch (IOException e) {
448 if (this.conn.isOpen()) {
449 LOG.debug("Closing the connection.");
450 this.conn.close();
451 }
452 releaseConnection = true;
453 throw e;
454 } catch (RuntimeException e) {
455 if (this.conn.isOpen) {
456 LOG.debug("Closing the connection.");
457 this.conn.close();
458 }
459 releaseConnection = true;
460 throw e;
461 }
462 }
463
464 /***
465 * Executes a ConnectMethod to establish a tunneled connection.
466 *
467 * @return <code>true</code> if the connect was successful
468 *
469 * @throws IOException
470 * @throws HttpException
471 */
472 private boolean executeConnect()
473 throws IOException, HttpException {
474
475 this.connectMethod = new ConnectMethod(this.hostConfiguration);
476 this.connectMethod.getParams().setDefaults(this.hostConfiguration.getParams());
477
478 int code;
479 for (;;) {
480 if (!this.conn.isOpen()) {
481 this.conn.open();
482 }
483 if (this.params.isAuthenticationPreemptive()
484 || this.state.isAuthenticationPreemptive()) {
485 LOG.debug("Preemptively sending default basic credentials");
486 this.connectMethod.getProxyAuthState().setPreemptive();
487 this.connectMethod.getProxyAuthState().setAuthAttempted(true);
488 }
489 try {
490 authenticateProxy(this.connectMethod);
491 } catch (AuthenticationException e) {
492 LOG.error(e.getMessage(), e);
493 }
494 applyConnectionParams(this.connectMethod);
495 this.connectMethod.execute(state, this.conn);
496 code = this.connectMethod.getStatusCode();
497 boolean retry = false;
498 AuthState authstate = this.connectMethod.getProxyAuthState();
499 authstate.setAuthRequested(code == HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED);
500 if (authstate.isAuthRequested()) {
501 if (processAuthenticationResponse(this.connectMethod)) {
502 retry = true;
503 }
504 }
505 if (!retry) {
506 break;
507 }
508 if (this.connectMethod.getResponseBodyAsStream() != null) {
509 this.connectMethod.getResponseBodyAsStream().close();
510 }
511 }
512 if ((code >= 200) && (code < 300)) {
513 this.conn.tunnelCreated();
514
515 this.connectMethod = null;
516 return true;
517 } else {
518 this.conn.close();
519 return false;
520 }
521 }
522
523 /***
524 * Fake response
525 * @param method
526 * @return
527 */
528
529 private void fakeResponse(final HttpMethod method)
530 throws IOException, HttpException {
531
532
533
534
535
536
537
538
539
540
541 LOG.debug("CONNECT failed, fake the response for the original method");
542
543
544
545
546
547
548
549 if (method instanceof HttpMethodBase) {
550 ((HttpMethodBase) method).fakeResponse(
551 this.connectMethod.getStatusLine(),
552 this.connectMethod.getResponseHeaderGroup(),
553 this.connectMethod.getResponseBodyAsStream()
554 );
555 method.getProxyAuthState().setAuthScheme(
556 this.connectMethod.getProxyAuthState().getAuthScheme());
557 this.connectMethod = null;
558 } else {
559 releaseConnection = true;
560 LOG.warn(
561 "Unable to fake response on method as it is not derived from HttpMethodBase.");
562 }
563 }
564
565 /***
566 * Process the redirect response.
567 *
568 * @return <code>true</code> if the redirect was successful
569 */
570 private boolean processRedirectResponse(final HttpMethod method)
571 throws RedirectException {
572
573 Header locationHeader = method.getResponseHeader("location");
574 if (locationHeader == null) {
575
576 LOG.error("Received redirect response " + method.getStatusCode()
577 + " but no location header");
578 return false;
579 }
580 String location = locationHeader.getValue();
581 if (LOG.isDebugEnabled()) {
582 LOG.debug("Redirect requested to location '" + location + "'");
583 }
584
585
586
587 URI redirectUri = null;
588 URI currentUri = null;
589
590 try {
591 currentUri = new URI(
592 this.conn.getProtocol().getScheme(),
593 null,
594 this.conn.getHost(),
595 this.conn.getPort(),
596 method.getPath()
597 );
598 redirectUri = new URI(location, true);
599 if (redirectUri.isRelativeURI()) {
600 if (this.params.isParameterTrue(HttpClientParams.REJECT_RELATIVE_REDIRECT)) {
601 LOG.warn("Relative redirect location '" + location + "' not allowed");
602 return false;
603 } else {
604
605 LOG.debug("Redirect URI is not absolute - parsing as relative");
606 redirectUri = new URI(currentUri, redirectUri);
607 }
608 } else {
609
610 method.getParams().setDefaults(this.params);
611 }
612 method.setURI(redirectUri);
613 hostConfiguration.setHost(redirectUri);
614 } catch (URIException ex) {
615 throw new InvalidRedirectLocationException(
616 "Invalid redirect location: " + location, location, ex);
617 }
618
619 if (this.params.isParameterFalse(HttpClientParams.ALLOW_CIRCULAR_REDIRECTS)) {
620 if (this.redirectLocations == null) {
621 this.redirectLocations = new HashSet();
622 }
623 this.redirectLocations.add(currentUri);
624 try {
625 if(redirectUri.hasQuery()) {
626 redirectUri.setQuery(null);
627 }
628 } catch (URIException e) {
629
630 return false;
631 }
632
633 if (this.redirectLocations.contains(redirectUri)) {
634 throw new CircularRedirectException("Circular redirect to '" +
635 redirectUri + "'");
636 }
637 }
638
639 if (LOG.isDebugEnabled()) {
640 LOG.debug("Redirecting from '" + currentUri.getEscapedURI()
641 + "' to '" + redirectUri.getEscapedURI());
642 }
643
644 method.getHostAuthState().invalidate();
645 return true;
646 }
647
648 /***
649 * Processes a response that requires authentication
650 *
651 * @param method the current {@link HttpMethod HTTP method}
652 *
653 * @return <tt>true</tt> if the authentication challenge can be responsed to,
654 * (that is, at least one of the requested authentication scheme is supported,
655 * and matching credentials have been found), <tt>false</tt> otherwise.
656 */
657 private boolean processAuthenticationResponse(final HttpMethod method) {
658 LOG.trace("enter HttpMethodBase.processAuthenticationResponse("
659 + "HttpState, HttpConnection)");
660
661 try {
662 switch (method.getStatusCode()) {
663 case HttpStatus.SC_UNAUTHORIZED:
664 return processWWWAuthChallenge(method);
665 case HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED:
666 return processProxyAuthChallenge(method);
667 default:
668 return false;
669 }
670 } catch (Exception e) {
671 if (LOG.isErrorEnabled()) {
672 LOG.error(e.getMessage(), e);
673 }
674 return false;
675 }
676 }
677
678 private boolean processWWWAuthChallenge(final HttpMethod method)
679 throws MalformedChallengeException, AuthenticationException
680 {
681 AuthState authstate = method.getHostAuthState();
682 Map challenges = AuthChallengeParser.parseChallenges(
683 method.getResponseHeaders(WWW_AUTH_CHALLENGE));
684 if (challenges.isEmpty()) {
685 LOG.debug("Authentication challenge(s) not found");
686 return false;
687 }
688 AuthScheme authscheme = null;
689 try {
690 authscheme = this.authProcessor.processChallenge(authstate, challenges);
691 } catch (AuthChallengeException e) {
692 if (LOG.isWarnEnabled()) {
693 LOG.warn(e.getMessage());
694 }
695 }
696 if (authscheme == null) {
697 return false;
698 }
699 String host = method.getParams().getVirtualHost();
700 if (host == null) {
701 host = conn.getHost();
702 }
703 int port = conn.getPort();
704 AuthScope authscope = new AuthScope(
705 host, port,
706 authscheme.getRealm(),
707 authscheme.getSchemeName());
708
709 if (LOG.isDebugEnabled()) {
710 LOG.debug("Authentication scope: " + authscope);
711 }
712 if (authstate.isAuthAttempted() && authscheme.isComplete()) {
713
714 Credentials credentials = promptForCredentials(
715 authscheme, method.getParams(), authscope);
716 if (credentials == null) {
717 if (LOG.isInfoEnabled()) {
718 LOG.info("Failure authenticating with " + authscope);
719 }
720 return false;
721 } else {
722 return true;
723 }
724 } else {
725 authstate.setAuthAttempted(true);
726 Credentials credentials = this.state.getCredentials(authscope);
727 if (credentials == null) {
728 credentials = promptForCredentials(
729 authscheme, method.getParams(), authscope);
730 }
731 if (credentials == null) {
732 if (LOG.isInfoEnabled()) {
733 LOG.info("No credentials available for " + authscope);
734 }
735 return false;
736 } else {
737 return true;
738 }
739 }
740 }
741
742 private boolean processProxyAuthChallenge(final HttpMethod method)
743 throws MalformedChallengeException, AuthenticationException
744 {
745 AuthState authstate = method.getProxyAuthState();
746 Map proxyChallenges = AuthChallengeParser.parseChallenges(
747 method.getResponseHeaders(PROXY_AUTH_CHALLENGE));
748 if (proxyChallenges.isEmpty()) {
749 LOG.debug("Proxy authentication challenge(s) not found");
750 return false;
751 }
752 AuthScheme authscheme = null;
753 try {
754 authscheme = this.authProcessor.processChallenge(authstate, proxyChallenges);
755 } catch (AuthChallengeException e) {
756 if (LOG.isWarnEnabled()) {
757 LOG.warn(e.getMessage());
758 }
759 }
760 if (authscheme == null) {
761 return false;
762 }
763 AuthScope authscope = new AuthScope(
764 conn.getProxyHost(), conn.getProxyPort(),
765 authscheme.getRealm(),
766 authscheme.getSchemeName());
767
768 if (LOG.isDebugEnabled()) {
769 LOG.debug("Proxy authentication scope: " + authscope);
770 }
771 if (authstate.isAuthAttempted() && authscheme.isComplete()) {
772
773 Credentials credentials = promptForProxyCredentials(
774 authscheme, method.getParams(), authscope);
775 if (credentials == null) {
776 if (LOG.isInfoEnabled()) {
777 LOG.info("Failure authenticating with " + authscope);
778 }
779 return false;
780 } else {
781 return true;
782 }
783 } else {
784 authstate.setAuthAttempted(true);
785 Credentials credentials = this.state.getProxyCredentials(authscope);
786 if (credentials == null) {
787 credentials = promptForProxyCredentials(
788 authscheme, method.getParams(), authscope);
789 }
790 if (credentials == null) {
791 if (LOG.isInfoEnabled()) {
792 LOG.info("No credentials available for " + authscope);
793 }
794 return false;
795 } else {
796 return true;
797 }
798 }
799 }
800
801 /***
802 * Tests if the {@link HttpMethod method} requires a redirect to another location.
803 *
804 * @param method HTTP method
805 *
806 * @return boolean <tt>true</tt> if a retry is needed, <tt>false</tt> otherwise.
807 */
808 private boolean isRedirectNeeded(final HttpMethod method) {
809 switch (method.getStatusCode()) {
810 case HttpStatus.SC_MOVED_TEMPORARILY:
811 case HttpStatus.SC_MOVED_PERMANENTLY:
812 case HttpStatus.SC_SEE_OTHER:
813 case HttpStatus.SC_TEMPORARY_REDIRECT:
814 LOG.debug("Redirect required");
815 if (method.getFollowRedirects()) {
816 return true;
817 } else {
818 return false;
819 }
820 default:
821 return false;
822 }
823 }
824
825 /***
826 * Tests if the {@link HttpMethod method} requires authentication.
827 *
828 * @param method HTTP method
829 *
830 * @return boolean <tt>true</tt> if a retry is needed, <tt>false</tt> otherwise.
831 */
832 private boolean isAuthenticationNeeded(final HttpMethod method) {
833 method.getHostAuthState().setAuthRequested(
834 method.getStatusCode() == HttpStatus.SC_UNAUTHORIZED);
835 method.getProxyAuthState().setAuthRequested(
836 method.getStatusCode() == HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED);
837 if (method.getHostAuthState().isAuthRequested() ||
838 method.getProxyAuthState().isAuthRequested()) {
839 LOG.debug("Authorization required");
840 if (method.getDoAuthentication()) {
841 return true;
842 } else {
843 LOG.info("Authentication requested but doAuthentication is "
844 + "disabled");
845 return false;
846 }
847 } else {
848 return false;
849 }
850 }
851
852 private Credentials promptForCredentials(
853 final AuthScheme authScheme,
854 final HttpParams params,
855 final AuthScope authscope)
856 {
857 LOG.debug("Credentials required");
858 Credentials creds = null;
859 CredentialsProvider credProvider =
860 (CredentialsProvider)params.getParameter(CredentialsProvider.PROVIDER);
861 if (credProvider != null) {
862 try {
863 creds = credProvider.getCredentials(
864 authScheme, authscope.getHost(), authscope.getPort(), false);
865 } catch (CredentialsNotAvailableException e) {
866 LOG.warn(e.getMessage());
867 }
868 if (creds != null) {
869 this.state.setCredentials(authscope, creds);
870 if (LOG.isDebugEnabled()) {
871 LOG.debug(authscope + " new credentials given");
872 }
873 }
874 } else {
875 LOG.debug("Credentials provider not available");
876 }
877 return creds;
878 }
879
880 private Credentials promptForProxyCredentials(
881 final AuthScheme authScheme,
882 final HttpParams params,
883 final AuthScope authscope)
884 {
885 LOG.debug("Proxy credentials required");
886 Credentials creds = null;
887 CredentialsProvider credProvider =
888 (CredentialsProvider)params.getParameter(CredentialsProvider.PROVIDER);
889 if (credProvider != null) {
890 try {
891 creds = credProvider.getCredentials(
892 authScheme, authscope.getHost(), authscope.getPort(), true);
893 } catch (CredentialsNotAvailableException e) {
894 LOG.warn(e.getMessage());
895 }
896 if (creds != null) {
897 this.state.setProxyCredentials(authscope, creds);
898 if (LOG.isDebugEnabled()) {
899 LOG.debug(authscope + " new credentials given");
900 }
901 }
902 } else {
903 LOG.debug("Proxy credentials provider not available");
904 }
905 return creds;
906 }
907
908 /***
909 * @return
910 */
911 public HostConfiguration getHostConfiguration() {
912 return hostConfiguration;
913 }
914
915 /***
916 * @return
917 */
918 public HttpState getState() {
919 return state;
920 }
921
922 /***
923 * @return
924 */
925 public HttpConnectionManager getConnectionManager() {
926 return connectionManager;
927 }
928
929 /***
930 * @return
931 */
932 public HttpParams getParams() {
933 return this.params;
934 }
935 }