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();
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 return false;
519 }
520 }
521
522 /***
523 * Fake response
524 * @param method
525 * @return
526 */
527
528 private void fakeResponse(final HttpMethod method)
529 throws IOException, HttpException {
530
531
532
533
534
535
536
537
538
539
540 LOG.debug("CONNECT failed, fake the response for the original method");
541
542
543
544
545
546
547
548 if (method instanceof HttpMethodBase) {
549 ((HttpMethodBase) method).fakeResponse(
550 this.connectMethod.getStatusLine(),
551 this.connectMethod.getResponseHeaderGroup(),
552 this.connectMethod.getResponseBodyAsStream()
553 );
554 method.getProxyAuthState().setAuthScheme(
555 this.connectMethod.getProxyAuthState().getAuthScheme());
556 this.connectMethod = null;
557 } else {
558 releaseConnection = true;
559 LOG.warn(
560 "Unable to fake response on method as it is not derived from HttpMethodBase.");
561 }
562 }
563
564 /***
565 * Process the redirect response.
566 *
567 * @return <code>true</code> if the redirect was successful
568 */
569 private boolean processRedirectResponse(final HttpMethod method)
570 throws RedirectException {
571
572 Header locationHeader = method.getResponseHeader("location");
573 if (locationHeader == null) {
574
575 LOG.error("Received redirect response " + method.getStatusCode()
576 + " but no location header");
577 return false;
578 }
579 String location = locationHeader.getValue();
580 if (LOG.isDebugEnabled()) {
581 LOG.debug("Redirect requested to location '" + location + "'");
582 }
583
584
585
586 URI redirectUri = null;
587 URI currentUri = null;
588
589 try {
590 currentUri = new URI(
591 this.conn.getProtocol().getScheme(),
592 null,
593 this.conn.getHost(),
594 this.conn.getPort(),
595 method.getPath()
596 );
597 redirectUri = new URI(location, true);
598 if (redirectUri.isRelativeURI()) {
599 if (this.params.isParameterTrue(HttpClientParams.REJECT_RELATIVE_REDIRECT)) {
600 LOG.warn("Relative redirect location '" + location + "' not allowed");
601 return false;
602 } else {
603
604 LOG.debug("Redirect URI is not absolute - parsing as relative");
605 redirectUri = new URI(currentUri, redirectUri);
606 }
607 } else {
608
609 method.getParams().setDefaults(this.params);
610 }
611 method.setURI(redirectUri);
612 hostConfiguration.setHost(redirectUri);
613 } catch (URIException e) {
614 LOG.warn("Redirected location '" + location + "' is malformed");
615 return false;
616 }
617
618 if (this.params.isParameterFalse(HttpClientParams.ALLOW_CIRCULAR_REDIRECTS)) {
619 if (this.redirectLocations == null) {
620 this.redirectLocations = new HashSet();
621 }
622 this.redirectLocations.add(currentUri);
623 try {
624 if(redirectUri.hasQuery()) {
625 redirectUri.setQuery(null);
626 }
627 } catch (URIException e) {
628
629 return false;
630 }
631
632 if (this.redirectLocations.contains(redirectUri)) {
633 throw new CircularRedirectException("Circular redirect to '" +
634 redirectUri + "'");
635 }
636 }
637
638 if (LOG.isDebugEnabled()) {
639 LOG.debug("Redirecting from '" + currentUri.getEscapedURI()
640 + "' to '" + redirectUri.getEscapedURI());
641 }
642
643 method.getHostAuthState().invalidate();
644 return true;
645 }
646
647 /***
648 * Processes a response that requires authentication
649 *
650 * @param method the current {@link HttpMethod HTTP method}
651 *
652 * @return <tt>true</tt> if the authentication challenge can be responsed to,
653 * (that is, at least one of the requested authentication scheme is supported,
654 * and matching credentials have been found), <tt>false</tt> otherwise.
655 */
656 private boolean processAuthenticationResponse(final HttpMethod method) {
657 LOG.trace("enter HttpMethodBase.processAuthenticationResponse("
658 + "HttpState, HttpConnection)");
659
660 try {
661 switch (method.getStatusCode()) {
662 case HttpStatus.SC_UNAUTHORIZED:
663 return processWWWAuthChallenge(method);
664 case HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED:
665 return processProxyAuthChallenge(method);
666 default:
667 return false;
668 }
669 } catch (Exception e) {
670 if (LOG.isErrorEnabled()) {
671 LOG.error(e.getMessage(), e);
672 }
673 return false;
674 }
675 }
676
677 private boolean processWWWAuthChallenge(final HttpMethod method)
678 throws MalformedChallengeException, AuthenticationException
679 {
680 AuthState authstate = method.getHostAuthState();
681 Map challenges = AuthChallengeParser.parseChallenges(
682 method.getResponseHeaders(WWW_AUTH_CHALLENGE));
683 if (challenges.isEmpty()) {
684 LOG.debug("Authentication challenge(s) not found");
685 return false;
686 }
687 AuthScheme authscheme = null;
688 try {
689 authscheme = this.authProcessor.processChallenge(authstate, challenges);
690 } catch (AuthChallengeException e) {
691 if (LOG.isWarnEnabled()) {
692 LOG.warn(e.getMessage());
693 }
694 }
695 if (authscheme == null) {
696 return false;
697 }
698 String host = method.getParams().getVirtualHost();
699 if (host == null) {
700 host = conn.getHost();
701 }
702 int port = conn.getPort();
703 AuthScope authscope = new AuthScope(
704 host, port,
705 authscheme.getRealm(),
706 authscheme.getSchemeName());
707
708 if (LOG.isDebugEnabled()) {
709 LOG.debug("Authentication scope: " + authscope);
710 }
711 if (authstate.isAuthAttempted() && authscheme.isComplete()) {
712
713 Credentials credentials = promptForCredentials(
714 authscheme, method.getParams(), authscope);
715 if (credentials == null) {
716 if (LOG.isInfoEnabled()) {
717 LOG.info("Failure authenticating with " + authscope);
718 }
719 return false;
720 } else {
721 return true;
722 }
723 } else {
724 authstate.setAuthAttempted(true);
725 Credentials credentials = this.state.getCredentials(authscope);
726 if (credentials == null) {
727 credentials = promptForCredentials(
728 authscheme, method.getParams(), authscope);
729 }
730 if (credentials == null) {
731 if (LOG.isInfoEnabled()) {
732 LOG.info("No credentials available for " + authscope);
733 }
734 return false;
735 } else {
736 return true;
737 }
738 }
739 }
740
741 private boolean processProxyAuthChallenge(final HttpMethod method)
742 throws MalformedChallengeException, AuthenticationException
743 {
744 AuthState authstate = method.getProxyAuthState();
745 Map proxyChallenges = AuthChallengeParser.parseChallenges(
746 method.getResponseHeaders(PROXY_AUTH_CHALLENGE));
747 if (proxyChallenges.isEmpty()) {
748 LOG.debug("Proxy authentication challenge(s) not found");
749 return false;
750 }
751 AuthScheme authscheme = null;
752 try {
753 authscheme = this.authProcessor.processChallenge(authstate, proxyChallenges);
754 } catch (AuthChallengeException e) {
755 if (LOG.isWarnEnabled()) {
756 LOG.warn(e.getMessage());
757 }
758 }
759 if (authscheme == null) {
760 return false;
761 }
762 AuthScope authscope = new AuthScope(
763 conn.getProxyHost(), conn.getProxyPort(),
764 authscheme.getRealm(),
765 authscheme.getSchemeName());
766
767 if (LOG.isDebugEnabled()) {
768 LOG.debug("Proxy authentication scope: " + authscope);
769 }
770 if (authstate.isAuthAttempted() && authscheme.isComplete()) {
771
772 Credentials credentials = promptForProxyCredentials(
773 authscheme, method.getParams(), authscope);
774 if (credentials == null) {
775 if (LOG.isInfoEnabled()) {
776 LOG.info("Failure authenticating with " + authscope);
777 }
778 return false;
779 } else {
780 return true;
781 }
782 } else {
783 authstate.setAuthAttempted(true);
784 Credentials credentials = this.state.getProxyCredentials(authscope);
785 if (credentials == null) {
786 credentials = promptForProxyCredentials(
787 authscheme, method.getParams(), authscope);
788 }
789 if (credentials == null) {
790 if (LOG.isInfoEnabled()) {
791 LOG.info("No credentials available for " + authscope);
792 }
793 return false;
794 } else {
795 return true;
796 }
797 }
798 }
799
800 /***
801 * Tests if the {@link HttpMethod method} requires a redirect to another location.
802 *
803 * @param method HTTP method
804 *
805 * @return boolean <tt>true</tt> if a retry is needed, <tt>false</tt> otherwise.
806 */
807 private boolean isRedirectNeeded(final HttpMethod method) {
808 switch (method.getStatusCode()) {
809 case HttpStatus.SC_MOVED_TEMPORARILY:
810 case HttpStatus.SC_MOVED_PERMANENTLY:
811 case HttpStatus.SC_SEE_OTHER:
812 case HttpStatus.SC_TEMPORARY_REDIRECT:
813 LOG.debug("Redirect required");
814 if (method.getFollowRedirects()) {
815 return true;
816 } else {
817 LOG.info("Redirect requested but followRedirects is "
818 + "disabled");
819 return false;
820 }
821 default:
822 return false;
823 }
824 }
825
826 /***
827 * Tests if the {@link HttpMethod method} requires authentication.
828 *
829 * @param method HTTP method
830 *
831 * @return boolean <tt>true</tt> if a retry is needed, <tt>false</tt> otherwise.
832 */
833 private boolean isAuthenticationNeeded(final HttpMethod method) {
834 method.getHostAuthState().setAuthRequested(
835 method.getStatusCode() == HttpStatus.SC_UNAUTHORIZED);
836 method.getProxyAuthState().setAuthRequested(
837 method.getStatusCode() == HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED);
838 if (method.getHostAuthState().isAuthRequested() ||
839 method.getProxyAuthState().isAuthRequested()) {
840 LOG.debug("Authorization required");
841 if (method.getDoAuthentication()) {
842 return true;
843 } else {
844 LOG.info("Authentication requested but doAuthentication is "
845 + "disabled");
846 return false;
847 }
848 } else {
849 return false;
850 }
851 }
852
853 private Credentials promptForCredentials(
854 final AuthScheme authScheme,
855 final HttpParams params,
856 final AuthScope authscope)
857 {
858 LOG.debug("Credentials required");
859 Credentials creds = null;
860 CredentialsProvider credProvider =
861 (CredentialsProvider)params.getParameter(CredentialsProvider.PROVIDER);
862 if (credProvider != null) {
863 try {
864 creds = credProvider.getCredentials(
865 authScheme, authscope.getHost(), authscope.getPort(), false);
866 } catch (CredentialsNotAvailableException e) {
867 LOG.warn(e.getMessage());
868 }
869 if (creds != null) {
870 this.state.setCredentials(authscope, creds);
871 if (LOG.isDebugEnabled()) {
872 LOG.debug(authscope + " new credentials given");
873 }
874 }
875 } else {
876 LOG.debug("Credentials provider not available");
877 }
878 return creds;
879 }
880
881 private Credentials promptForProxyCredentials(
882 final AuthScheme authScheme,
883 final HttpParams params,
884 final AuthScope authscope)
885 {
886 LOG.debug("Proxy credentials required");
887 Credentials creds = null;
888 CredentialsProvider credProvider =
889 (CredentialsProvider)params.getParameter(CredentialsProvider.PROVIDER);
890 if (credProvider != null) {
891 try {
892 creds = credProvider.getCredentials(
893 authScheme, authscope.getHost(), authscope.getPort(), true);
894 } catch (CredentialsNotAvailableException e) {
895 LOG.warn(e.getMessage());
896 }
897 if (creds != null) {
898 this.state.setProxyCredentials(authscope, creds);
899 if (LOG.isDebugEnabled()) {
900 LOG.debug(authscope + " new credentials given");
901 }
902 }
903 } else {
904 LOG.debug("Proxy credentials provider not available");
905 }
906 return creds;
907 }
908
909 /***
910 * @return
911 */
912 public HostConfiguration getHostConfiguration() {
913 return hostConfiguration;
914 }
915
916 /***
917 * @return
918 */
919 public HttpState getState() {
920 return state;
921 }
922
923 /***
924 * @return
925 */
926 public HttpConnectionManager getConnectionManager() {
927 return connectionManager;
928 }
929
930 /***
931 * @return
932 */
933 public HttpParams getParams() {
934 return this.params;
935 }
936 }