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