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 package org.apache.http.impl.nio.client;
28
29 import java.io.IOException;
30 import java.net.URI;
31 import java.net.URISyntaxException;
32 import java.nio.ByteBuffer;
33 import java.util.List;
34
35 import org.apache.commons.logging.Log;
36 import org.apache.commons.logging.LogFactory;
37 import org.apache.http.HttpException;
38 import org.apache.http.HttpHost;
39 import org.apache.http.HttpRequest;
40 import org.apache.http.HttpResponse;
41 import org.apache.http.HttpStatus;
42 import org.apache.http.HttpVersion;
43 import org.apache.http.ProtocolException;
44 import org.apache.http.auth.AUTH;
45 import org.apache.http.auth.AuthProtocolState;
46 import org.apache.http.auth.AuthScheme;
47 import org.apache.http.auth.AuthScope;
48 import org.apache.http.auth.AuthState;
49 import org.apache.http.auth.UsernamePasswordCredentials;
50 import org.apache.http.client.AuthenticationStrategy;
51 import org.apache.http.client.CredentialsProvider;
52 import org.apache.http.client.NonRepeatableRequestException;
53 import org.apache.http.client.RedirectException;
54 import org.apache.http.client.RedirectStrategy;
55 import org.apache.http.client.UserTokenHandler;
56 import org.apache.http.client.config.RequestConfig;
57 import org.apache.http.client.methods.Configurable;
58 import org.apache.http.client.methods.HttpRequestWrapper;
59 import org.apache.http.client.methods.HttpUriRequest;
60 import org.apache.http.client.protocol.HttpClientContext;
61 import org.apache.http.client.protocol.RequestClientConnControl;
62 import org.apache.http.client.utils.URIUtils;
63 import org.apache.http.conn.routing.BasicRouteDirector;
64 import org.apache.http.conn.routing.HttpRoute;
65 import org.apache.http.conn.routing.HttpRouteDirector;
66 import org.apache.http.conn.routing.HttpRoutePlanner;
67 import org.apache.http.impl.auth.HttpAuthenticator;
68 import org.apache.http.message.BasicHttpRequest;
69 import org.apache.http.nio.ContentDecoder;
70 import org.apache.http.nio.ContentEncoder;
71 import org.apache.http.nio.IOControl;
72 import org.apache.http.nio.NHttpClientConnection;
73 import org.apache.http.nio.protocol.HttpAsyncRequestProducer;
74 import org.apache.http.nio.protocol.HttpAsyncResponseConsumer;
75 import org.apache.http.protocol.HttpCoreContext;
76 import org.apache.http.protocol.HttpProcessor;
77 import org.apache.http.protocol.ImmutableHttpProcessor;
78 import org.apache.http.protocol.RequestTargetHost;
79
80 class MainClientExec implements InternalClientExec {
81
82 private final Log log = LogFactory.getLog(getClass());
83
84 private final HttpProcessor httpProcessor;
85 private final HttpProcessor proxyHttpProcessor;
86 private final HttpRoutePlanner routePlanner;
87 private final AuthenticationStrategy targetAuthStrategy;
88 private final AuthenticationStrategy proxyAuthStrategy;
89 private final UserTokenHandler userTokenHandler;
90 private final RedirectStrategy redirectStrategy;
91 private final HttpRouteDirector routeDirector;
92 private final HttpAuthenticator authenticator;
93
94 public MainClientExec(
95 final HttpProcessor httpProcessor,
96 final HttpRoutePlanner routePlanner,
97 final RedirectStrategy redirectStrategy,
98 final AuthenticationStrategy targetAuthStrategy,
99 final AuthenticationStrategy proxyAuthStrategy,
100 final UserTokenHandler userTokenHandler) {
101 super();
102 this.httpProcessor = httpProcessor;
103 this.proxyHttpProcessor = new ImmutableHttpProcessor(
104 new RequestTargetHost(), new RequestClientConnControl());
105 this.routePlanner = routePlanner;
106 this.redirectStrategy = redirectStrategy;
107 this.targetAuthStrategy = targetAuthStrategy;
108 this.proxyAuthStrategy = proxyAuthStrategy;
109 this.userTokenHandler = userTokenHandler;
110 this.routeDirector = new BasicRouteDirector();
111 this.authenticator = new HttpAuthenticator(log);
112 }
113
114 @Override
115 public void prepare(
116 final HttpHost target,
117 final HttpRequest original,
118 final InternalState state,
119 final AbstractClientExchangeHandler handler) throws HttpException, IOException {
120 if (this.log.isDebugEnabled()) {
121 this.log.debug("[exchange: " + state.getId() + "] start execution");
122 }
123
124 final HttpClientContext localContext = state.getLocalContext();
125
126 if (original instanceof Configurable) {
127 final RequestConfig config = ((Configurable) original).getConfig();
128 if (config != null) {
129 localContext.setRequestConfig(config);
130 }
131 }
132
133 final List<URI> redirectLocations = localContext.getRedirectLocations();
134 if (redirectLocations != null) {
135 redirectLocations.clear();
136 }
137
138 final HttpRequestWrapper request = HttpRequestWrapper.wrap(original);
139 final HttpRoute route = this.routePlanner.determineRoute(target, request, localContext);
140
141 handler.setRoute(route);
142
143 state.setMainRequest(request);
144 handler.setCurrentRequest(request);
145
146 prepareRequest(state, handler);
147 }
148
149 @Override
150 public HttpRequest generateRequest(
151 final InternalState state,
152 final AbstractClientExchangeHandler handler) throws IOException, HttpException {
153
154 final HttpRoute route = handler.getRoute();
155
156 handler.verifytRoute();
157
158 if (!handler.isRouteEstablished()) {
159 int step;
160 loop:
161 do {
162 final HttpRoute fact = handler.getActualRoute();
163 step = this.routeDirector.nextStep(route, fact);
164 switch (step) {
165 case HttpRouteDirector.CONNECT_TARGET:
166 handler.onRouteToTarget();
167 break;
168 case HttpRouteDirector.CONNECT_PROXY:
169 handler.onRouteToProxy();
170 break;
171 case HttpRouteDirector.TUNNEL_TARGET:
172 if (this.log.isDebugEnabled()) {
173 this.log.debug("[exchange: " + state.getId() + "] Tunnel required");
174 }
175 final HttpRequest connect = createConnectRequest(route, state);
176 handler.setCurrentRequest(HttpRequestWrapper.wrap(connect));
177 break loop;
178 case HttpRouteDirector.TUNNEL_PROXY:
179 throw new HttpException("Proxy chains are not supported");
180 case HttpRouteDirector.LAYER_PROTOCOL:
181 handler.onRouteUpgrade();
182 break;
183 case HttpRouteDirector.UNREACHABLE:
184 throw new HttpException("Unable to establish route: " +
185 "planned = " + route + "; current = " + fact);
186 case HttpRouteDirector.COMPLETE:
187 handler.onRouteComplete();
188 this.log.debug("[exchange: " + state.getId() + "] Connection route established");
189 break;
190 default:
191 throw new IllegalStateException("Unknown step indicator "
192 + step + " from RouteDirector.");
193 }
194 } while (step > HttpRouteDirector.COMPLETE);
195 }
196
197 final HttpClientContext localContext = state.getLocalContext();
198 HttpRequestWrapper currentRequest = handler.getCurrentRequest();
199 if (currentRequest == null) {
200 currentRequest = state.getMainRequest();
201 handler.setCurrentRequest(currentRequest);
202 }
203
204 if (handler.isRouteEstablished()) {
205 state.incrementExecCount();
206 if (state.getExecCount() > 1) {
207 final HttpAsyncRequestProducer requestProducer = state.getRequestProducer();
208 if (!requestProducer.isRepeatable() && state.isRequestContentProduced()) {
209 throw new NonRepeatableRequestException("Cannot retry request " +
210 "with a non-repeatable request entity.");
211 }
212 requestProducer.resetRequest();
213 }
214 if (this.log.isDebugEnabled()) {
215 this.log.debug("[exchange: " + state.getId() + "] Attempt " + state.getExecCount() +
216 " to execute request");
217 }
218
219 if (!currentRequest.containsHeader(AUTH.WWW_AUTH_RESP)) {
220 final AuthState targetAuthState = localContext.getTargetAuthState();
221 if (this.log.isDebugEnabled()) {
222 this.log.debug("[exchange: " + state.getId() + "] Target auth state: " + targetAuthState.getState());
223 }
224 this.authenticator.generateAuthResponse(currentRequest, targetAuthState, localContext);
225 }
226 if (!currentRequest.containsHeader(AUTH.PROXY_AUTH_RESP) && !route.isTunnelled()) {
227 final AuthState proxyAuthState = localContext.getProxyAuthState();
228 if (this.log.isDebugEnabled()) {
229 this.log.debug("[exchange: " + state.getId() + "] Proxy auth state: " + proxyAuthState.getState());
230 }
231 this.authenticator.generateAuthResponse(currentRequest, proxyAuthState, localContext);
232 }
233 } else {
234 if (!currentRequest.containsHeader(AUTH.PROXY_AUTH_RESP)) {
235 final AuthState proxyAuthState = localContext.getProxyAuthState();
236 if (this.log.isDebugEnabled()) {
237 this.log.debug("[exchange: " + state.getId() + "] Proxy auth state: " + proxyAuthState.getState());
238 }
239 this.authenticator.generateAuthResponse(currentRequest, proxyAuthState, localContext);
240 }
241 }
242
243 final NHttpClientConnection managedConn = handler.getConnection();
244 localContext.setAttribute(HttpCoreContext.HTTP_CONNECTION, managedConn);
245 final RequestConfig config = localContext.getRequestConfig();
246 if (config.getSocketTimeout() > 0) {
247 managedConn.setSocketTimeout(config.getSocketTimeout());
248 }
249 return currentRequest;
250 }
251
252 @Override
253 public void produceContent(
254 final InternalState state,
255 final ContentEncoder encoder,
256 final IOControl ioControl) throws IOException {
257 if (this.log.isDebugEnabled()) {
258 this.log.debug("[exchange: " + state.getId() + "] produce content");
259 }
260 final HttpAsyncRequestProducer requestProducer = state.getRequestProducer();
261 state.setRequestContentProduced();
262 requestProducer.produceContent(encoder, ioControl);
263 if (encoder.isCompleted()) {
264 requestProducer.resetRequest();
265 }
266 }
267
268 @Override
269 public void requestCompleted(
270 final InternalState state,
271 final AbstractClientExchangeHandler handler) {
272 if (this.log.isDebugEnabled()) {
273 this.log.debug("[exchange: " + state.getId() + "] Request completed");
274 }
275 final HttpClientContext localContext = state.getLocalContext();
276 final HttpAsyncRequestProducer requestProducer = state.getRequestProducer();
277 requestProducer.requestCompleted(localContext);
278 }
279
280 @Override
281 public void responseReceived(
282 final HttpResponse response,
283 final InternalState state,
284 final AbstractClientExchangeHandler handler) throws IOException, HttpException {
285 if (this.log.isDebugEnabled()) {
286 this.log.debug("[exchange: " + state.getId() + "] Response received " + response.getStatusLine());
287 }
288 final HttpClientContext context = state.getLocalContext();
289 context.setAttribute(HttpCoreContext.HTTP_RESPONSE, response);
290 this.httpProcessor.process(response, context);
291
292 handler.setCurrentResponse(response);
293
294 if (!handler.isRouteEstablished()) {
295 final int status = response.getStatusLine().getStatusCode();
296 if (status < 200) {
297 throw new HttpException("Unexpected response to CONNECT request: " +
298 response.getStatusLine());
299 }
300 if (status == HttpStatus.SC_OK) {
301 handler.onRouteTunnelToTarget();
302 handler.setCurrentRequest(null);
303 } else {
304 if (!handleConnectResponse(state, handler)) {
305 state.setFinalResponse(response);
306 }
307 }
308 } else {
309 if (!handleResponse(state, handler)) {
310 state.setFinalResponse(response);
311 }
312 }
313 if (state.getFinalResponse() != null) {
314 final HttpAsyncResponseConsumer<?> responseConsumer = state.getResponseConsumer();
315 responseConsumer.responseReceived(response);
316 }
317 }
318
319 @Override
320 public void consumeContent(
321 final InternalState state,
322 final ContentDecoder decoder,
323 final IOControl ioControl) throws IOException {
324 if (this.log.isDebugEnabled()) {
325 this.log.debug("[exchange: " + state.getId() + "] Consume content");
326 }
327 if (state.getFinalResponse() != null) {
328 final HttpAsyncResponseConsumer<?> responseConsumer = state.getResponseConsumer();
329 responseConsumer.consumeContent(decoder, ioControl);
330 } else {
331 final ByteBuffer tmpbuf = state.getTmpbuf();
332 tmpbuf.clear();
333 decoder.read(tmpbuf);
334 }
335 }
336
337 @Override
338 public void responseCompleted(
339 final InternalState state,
340 final AbstractClientExchangeHandler handler) throws IOException, HttpException {
341 final HttpClientContext localContext = state.getLocalContext();
342 final HttpResponse currentResponse = handler.getCurrentResponse();
343
344 if (!handler.isRouteEstablished()) {
345 final int status = currentResponse.getStatusLine().getStatusCode();
346 if (status == HttpStatus.SC_OK) {
347 handler.setCurrentResponse(null);
348 return;
349 }
350 }
351
352 final boolean keepAlive = handler.manageConnectionPersistence();
353 if (!keepAlive) {
354 handler.releaseConnection();
355 final AuthState proxyAuthState = localContext.getProxyAuthState();
356 if (proxyAuthState.getState() == AuthProtocolState.SUCCESS
357 && proxyAuthState.getAuthScheme() != null
358 && proxyAuthState.getAuthScheme().isConnectionBased()) {
359 if (this.log.isDebugEnabled()) {
360 this.log.debug("[exchange: " + state.getId() + "] Resetting proxy auth state");
361 }
362 proxyAuthState.reset();
363 }
364 final AuthState targetAuthState = localContext.getTargetAuthState();
365 if (targetAuthState.getState() == AuthProtocolState.SUCCESS
366 && targetAuthState.getAuthScheme() != null
367 && targetAuthState.getAuthScheme().isConnectionBased()) {
368 if (this.log.isDebugEnabled()) {
369 this.log.debug("[exchange: " + state.getId() + "] Resetting target auth state");
370 }
371 targetAuthState.reset();
372 }
373 }
374
375 Object userToken = localContext.getUserToken();
376 if (userToken == null) {
377 userToken = this.userTokenHandler.getUserToken(localContext);
378 localContext.setAttribute(HttpClientContext.USER_TOKEN, userToken);
379 }
380
381 if (state.getFinalResponse() != null) {
382 final HttpAsyncResponseConsumer<?> responseConsumer = state.getResponseConsumer();
383 responseConsumer.responseCompleted(localContext);
384 if (this.log.isDebugEnabled()) {
385 this.log.debug("[exchange: " + state.getId() + "] Response processed");
386 }
387 handler.releaseConnection();
388 } else {
389 if (state.getRedirect() != null) {
390 final HttpUriRequest redirect = state.getRedirect();
391 final URI uri = redirect.getURI();
392 if (this.log.isDebugEnabled()) {
393 this.log.debug("[exchange: " + state.getId() + "] Redirecting to '" + uri + "'");
394 }
395 state.setRedirect(null);
396
397 final HttpHost newTarget = URIUtils.extractHost(uri);
398 if (newTarget == null) {
399 throw new ProtocolException("Redirect URI does not specify a valid host name: " + uri);
400 }
401
402
403 final HttpRoute route = handler.getRoute();
404 if (!route.getTargetHost().equals(newTarget)) {
405 final AuthState targetAuthState = localContext.getTargetAuthState();
406 if (this.log.isDebugEnabled()) {
407 this.log.debug("[exchange: " + state.getId() + "] Resetting target auth state");
408 }
409 targetAuthState.reset();
410 final AuthState proxyAuthState = localContext.getProxyAuthState();
411 final AuthScheme authScheme = proxyAuthState.getAuthScheme();
412 if (authScheme != null && authScheme.isConnectionBased()) {
413 if (this.log.isDebugEnabled()) {
414 this.log.debug("[exchange: " + state.getId() + "] Resetting proxy auth state");
415 }
416 proxyAuthState.reset();
417 }
418 }
419
420 if (!redirect.headerIterator().hasNext()) {
421 final HttpRequest original = state.getMainRequest().getOriginal();
422 redirect.setHeaders(original.getAllHeaders());
423 }
424
425 final HttpRequestWrapper newRequest = HttpRequestWrapper.wrap(redirect);
426 final HttpRoute newRoute = this.routePlanner.determineRoute(
427 newTarget, newRequest, localContext);
428 if (!route.equals(newRoute)) {
429 handler.releaseConnection();
430 }
431 handler.setRoute(newRoute);
432 handler.setCurrentRequest(newRequest);
433 state.setMainRequest(newRequest);
434 prepareRequest(state, handler);
435 }
436 }
437 handler.setCurrentResponse(null);
438 }
439
440 private void rewriteRequestURI(
441 final HttpRequestWrapper request,
442 final HttpRoute route) throws ProtocolException {
443 try {
444 URI uri = request.getURI();
445 if (uri != null) {
446 if (route.getProxyHost() != null && !route.isTunnelled()) {
447
448 if (!uri.isAbsolute()) {
449 final HttpHost target = route.getTargetHost();
450 uri = URIUtils.rewriteURI(uri, target, true);
451 } else {
452 uri = URIUtils.rewriteURI(uri);
453 }
454 } else {
455
456 if (uri.isAbsolute()) {
457 uri = URIUtils.rewriteURI(uri, null, true);
458 } else {
459 uri = URIUtils.rewriteURI(uri);
460 }
461 }
462 request.setURI(uri);
463 }
464 } catch (final URISyntaxException ex) {
465 throw new ProtocolException("Invalid URI: " +
466 request.getRequestLine().getUri(), ex);
467 }
468 }
469
470 private void prepareRequest(
471 final InternalState state,
472 final AbstractClientExchangeHandler handler) throws IOException, HttpException {
473 final HttpClientContext localContext = state.getLocalContext();
474 final HttpRequestWrapper currentRequest = handler.getCurrentRequest();
475 final HttpRoute route = handler.getRoute();
476
477 final HttpRequest original = currentRequest.getOriginal();
478 URI uri = null;
479 if (original instanceof HttpUriRequest) {
480 uri = ((HttpUriRequest) original).getURI();
481 } else {
482 final String uriString = original.getRequestLine().getUri();
483 try {
484 uri = URI.create(uriString);
485 } catch (final IllegalArgumentException ex) {
486 if (this.log.isDebugEnabled()) {
487 this.log.debug("[exchange: " + state.getId() + "] Unable to parse '" + uriString +
488 "' as a valid URI; request URI and Host header may be inconsistent", ex);
489 }
490 }
491
492 }
493 currentRequest.setURI(uri);
494
495
496 rewriteRequestURI(currentRequest, route);
497
498 HttpHost target = null;
499 if (uri != null && uri.isAbsolute() && uri.getHost() != null) {
500 target = new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme());
501 }
502 if (target == null) {
503 target = route.getTargetHost();
504 }
505
506
507 if (uri != null) {
508 final String userinfo = uri.getUserInfo();
509 if (userinfo != null) {
510 final CredentialsProvider credsProvider = localContext.getCredentialsProvider();
511 credsProvider.setCredentials(
512 new AuthScope(target),
513 new UsernamePasswordCredentials(userinfo));
514 }
515 }
516
517 localContext.setAttribute(HttpCoreContext.HTTP_REQUEST, currentRequest);
518 localContext.setAttribute(HttpCoreContext.HTTP_TARGET_HOST, target);
519 localContext.setAttribute(HttpClientContext.HTTP_ROUTE, route);
520 this.httpProcessor.process(currentRequest, localContext);
521 }
522
523 private HttpRequest createConnectRequest(
524 final HttpRoute route, final InternalState state) throws IOException, HttpException {
525
526
527
528 final HttpHost target = route.getTargetHost();
529 final String host = target.getHostName();
530 final int port = target.getPort();
531 final StringBuilder buffer = new StringBuilder(host.length() + 6);
532 buffer.append(host);
533 buffer.append(':');
534 buffer.append(Integer.toString(port));
535 final HttpRequest request = new BasicHttpRequest("CONNECT", buffer.toString(), HttpVersion.HTTP_1_1);
536 final HttpClientContext localContext = state.getLocalContext();
537 this.proxyHttpProcessor.process(request, localContext);
538 return request;
539 }
540
541 private boolean handleConnectResponse(
542 final InternalState state,
543 final AbstractClientExchangeHandler handler) {
544 final HttpClientContext localContext = state.getLocalContext();
545 final RequestConfig config = localContext.getRequestConfig();
546 if (config.isAuthenticationEnabled()) {
547 final CredentialsProvider credsProvider = localContext.getCredentialsProvider();
548 if (credsProvider != null) {
549 final HttpRoute route = handler.getRoute();
550 final HttpHost proxy = route.getProxyHost();
551 final HttpResponse currentResponse = handler.getCurrentResponse();
552 final AuthState proxyAuthState = localContext.getProxyAuthState();
553 if (this.authenticator.isAuthenticationRequested(proxy, currentResponse,
554 this.proxyAuthStrategy, proxyAuthState, localContext)) {
555 return this.authenticator.handleAuthChallenge(proxy, currentResponse,
556 this.proxyAuthStrategy, proxyAuthState, localContext);
557 }
558 }
559 }
560 return false;
561 }
562
563 private boolean handleResponse(
564 final InternalState state,
565 final AbstractClientExchangeHandler handler) throws HttpException {
566 final HttpClientContext localContext = state.getLocalContext();
567 final RequestConfig config = localContext.getRequestConfig();
568 if (config.isAuthenticationEnabled()) {
569 if (needAuthentication(state, handler)) {
570
571 final HttpRequestWrapper currentRequest = handler.getCurrentRequest();
572 final HttpRequest original = currentRequest.getOriginal();
573 if (!original.containsHeader(AUTH.WWW_AUTH_RESP)) {
574 currentRequest.removeHeaders(AUTH.WWW_AUTH_RESP);
575 }
576 if (!original.containsHeader(AUTH.PROXY_AUTH_RESP)) {
577 currentRequest.removeHeaders(AUTH.PROXY_AUTH_RESP);
578 }
579 return true;
580 }
581 }
582 if (config.isRedirectsEnabled()) {
583 final HttpRequestWrapper currentRequest = handler.getCurrentRequest();
584 final HttpResponse currentResponse = handler.getCurrentResponse();
585 if (this.redirectStrategy.isRedirected(currentRequest, currentResponse, localContext)) {
586 final int maxRedirects = config.getMaxRedirects() >= 0 ? config.getMaxRedirects() : 100;
587 if (state.getRedirectCount() >= maxRedirects) {
588 throw new RedirectException("Maximum redirects (" + maxRedirects + ") exceeded");
589 }
590 state.incrementRedirectCount();
591 final HttpUriRequest redirect = this.redirectStrategy.getRedirect(currentRequest.getOriginal(), currentResponse,
592 localContext);
593 state.setRedirect(redirect);
594 return true;
595 }
596 }
597 return false;
598 }
599
600 private boolean needAuthentication(
601 final InternalState state,
602 final AbstractClientExchangeHandler handler) {
603 final HttpClientContext localContext = state.getLocalContext();
604 final CredentialsProvider credsProvider = localContext.getCredentialsProvider();
605 if (credsProvider != null) {
606 final HttpRoute route = handler.getRoute();
607 final HttpResponse currentResponse = handler.getCurrentResponse();
608 HttpHost target = localContext.getTargetHost();
609 if (target == null) {
610 target = route.getTargetHost();
611 }
612 if (target.getPort() < 0) {
613 target = new HttpHost(
614 target.getHostName(),
615 route.getTargetHost().getPort(),
616 target.getSchemeName());
617 }
618 final AuthState targetAuthState = localContext.getTargetAuthState();
619 final AuthState proxyAuthState = localContext.getProxyAuthState();
620
621 final boolean targetAuthRequested = this.authenticator.isAuthenticationRequested(
622 target, currentResponse, this.targetAuthStrategy, targetAuthState, localContext);
623
624 HttpHost proxy = route.getProxyHost();
625
626 if (proxy == null) {
627 proxy = route.getTargetHost();
628 }
629 final boolean proxyAuthRequested = this.authenticator.isAuthenticationRequested(
630 proxy, currentResponse, this.proxyAuthStrategy, proxyAuthState, localContext);
631
632 if (targetAuthRequested) {
633 return this.authenticator.handleAuthChallenge(target, currentResponse,
634 this.targetAuthStrategy, targetAuthState, localContext);
635 }
636 if (proxyAuthRequested) {
637 return this.authenticator.handleAuthChallenge(proxy, currentResponse,
638 this.proxyAuthStrategy, proxyAuthState, localContext);
639 }
640 }
641 return false;
642 }
643
644 }