[
https://issues.apache.org/jira/browse/HTTPASYNC-110?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15422376#comment-15422376
]
Oleg Kalnichevski commented on HTTPASYNC-110:
---------------------------------------------
I do not think that requesting connection from the pool is a problem. In fact
why should the client open a new connection if there are re-usable connections
kept alive in the pool? The problem is that the default exchange handler fails
to update its internal state correctly and detect that it should forgo CONNECT
handshake if it gets a fully initialized connection back from the pool.
Oleg
> Proxy reuses a fully established routed authenticated connection in attempt
> to CONNECT to target again causing 400 and NPE
> --------------------------------------------------------------------------------------------------------------------------
>
> Key: HTTPASYNC-110
> URL: https://issues.apache.org/jira/browse/HTTPASYNC-110
> Project: HttpComponents HttpAsyncClient
> Issue Type: Bug
> Reporter: Andrey K
> Attachments: buglog.txt
>
>
> First I noticed I was getting sporadic errors when attempting to make an
> HTTPS call via HTTP Proxy that requires authentication:
> java.lang.IllegalArgumentException: Auth scheme may not be null
> at org.apache.http.util.Args.notNull(Args.java:54)
> at
> org.apache.http.impl.client.AuthenticationStrategyImpl.authSucceeded(AuthenticationStrategyImpl.java:215)
> at
> org.apache.http.impl.client.ProxyAuthenticationStrategy.authSucceeded(ProxyAuthenticationStrategy.java:43)
> at
> org.apache.http.impl.auth.HttpAuthenticator.isAuthenticationRequested(HttpAuthenticator.java:88)
> at
> org.apache.http.impl.nio.client.MainClientExec.needAuthentication(MainClientExec.java:629)
> at
> org.apache.http.impl.nio.client.MainClientExec.handleResponse(MainClientExec.java:569)
> at
> org.apache.http.impl.nio.client.MainClientExec.responseReceived(MainClientExec.java:309)
> at
> org.apache.http.impl.nio.client.DefaultClientExchangeHandlerImpl.responseReceived(DefaultClientExchangeHandlerImpl.java:147)
> at
> org.apache.http.nio.protocol.HttpAsyncRequestExecutor.responseReceived(HttpAsyncRequestExecutor.java:303)
> at
> org.apache.http.impl.nio.DefaultNHttpClientConnection.consumeInput(DefaultNHttpClientConnection.java:255)
> at
> org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(InternalIODispatch.java:81)
> at
> org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(InternalIODispatch.java:39)
> at
> org.apache.http.impl.nio.reactor.AbstractIODispatch.inputReady(AbstractIODispatch.java:121)
> at
> org.apache.http.impl.nio.reactor.BaseIOReactor.readable(BaseIOReactor.java:162)
> at
> org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvent(AbstractIOReactor.java:337)
> at
> org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvents(AbstractIOReactor.java:315)
> at
> org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:276)
> at
> org.apache.http.impl.nio.reactor.BaseIOReactor.execute(BaseIOReactor.java:104)
> at
> org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run(AbstractMultiworkerIOReactor.java:588)
> Upon closer look with trace debug, I saw that it was breaking on an
> unexpected 400 status code coming back against a CONNECT+AUTH request. When I
> traced the connection that was used for this connect, I saw that it was a
> fully connected routed connection. What happened was the HttpClient got a 407
> after attempting to do a CONNECT and that 407 contained instruction to close
> connection. HttpClient discarded the connection and obtained a new one from
> the pool but the one that was leased was already fully authenticated and
> tunneled. Thus the CONNECT request was sent to the actual tunneled target and
> returned with a 400.
> As a workaround I have enhanced a custom ProxyAuthenticationStrategy to
> rename the USER_TOKEN context value to a temporary unique value to prevent
> reusing a fully established connection and then revert it back after
> authentication is sucessful:
> static AtomicLong counter = new AtomicLong(0);
> static final String ORIGINAL_USER_TOKEN = "ORIGINAL_USER_TOKEN";
> @Override
> public Map<String, Header> getChallenges(HttpHost authhost, HttpResponse
> response, HttpContext context) throws MalformedChallengeException {
> String originalUserToken =
> (String)context.getAttribute(ORIGINAL_USER_TOKEN);
> if (originalUserToken == null) {
> originalUserToken =
> (String)context.getAttribute(HttpClientContext.USER_TOKEN);
> context.setAttribute(ORIGINAL_USER_TOKEN, originalUserToken);
> String temporaryName = "NON-REUSABLE-" + counter.incrementAndGet();
> context.setAttribute(HttpClientContext.USER_TOKEN, temporaryName);
> log.trace("OnAuth: Renaming connection from {} to {}",
> originalUserToken, temporaryName);
> }
> return super.getChallenges(authhost, response, context);
> }
> @Override
> public void authSucceeded(HttpHost authhost, AuthScheme authScheme,
> HttpContext context) {
> String originalUserToken =
> (String)context.getAttribute(ORIGINAL_USER_TOKEN);
> if (originalUserToken != null) {
> String tempUserToken =
> (String)context.getAttribute(HttpClientContext.USER_TOKEN);
> context.setAttribute(HttpClientContext.USER_TOKEN, originalUserToken);
> context.removeAttribute(ORIGINAL_USER_TOKEN);
> log.trace("OnAuthSucc: Renaming connection from {} to {}",
> tempUserToken, originalUserToken);
> }
> super.authSucceeded(authhost, authScheme, context);
> }
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]