Fae Hutter created HTTPASYNC-103:
------------------------------------
Summary: Connections reuse does not work when using TLS client
certs
Key: HTTPASYNC-103
URL: https://issues.apache.org/jira/browse/HTTPASYNC-103
Project: HttpComponents HttpAsyncClient
Issue Type: Bug
Affects Versions: 4.1.1
Reporter: Fae Hutter
When using TLS client certs,
{{PoolingNHttpClientConnectionManager.requestConnection()}} is called with
{{state=null}} but {{PoolingNHttpClientConnectionManager.releaseConnection()}}
is called with {{state=X500Principal}}.
What I think it happening...
{{org.apache.http.impl.nio.client.AbstractClientExchangeHandler.requestConnection()}}
has:
{code:java}
final Object userToken = this.localContext.getUserToken();
this.connmgr.requestConnection( ... userToken, ...
{code}
At this point the user token has not been set.
Then {{org.apache.http.impl.nio.client.MainClientExec.responseCompleted()}} has
this which sets the user token:
{code:java}
Object userToken = localContext.getUserToken();
if (userToken == null) {
userToken = this.userTokenHandler.getUserToken(localContext);
localContext.setAttribute(HttpClientContext.USER_TOKEN, userToken);
}
{code}
And
{{org.apache.http.impl.nio.client.AbstractClientExchangeHandler.releaseConnection()}}
then with:
{code:java}
final Object userToken = this.localContext.getUserToken();
this.connmgr.releaseConnection(localConn, userToken, validDuration,
TimeUnit.MILLISECONDS);
{code}
And because the state does not match, the call to {{releaseConnection()}} has
no effect.
There is an assertion for this at
{{org.apache.http.nio.pool.RouteSpecificPool.free()}}, but the assertion is
never called because {{org.apache.http.nio.pool.AbstractNIOConnPool.release()}}
first checks the response of:
{code:java}
if (this.leased.remove(entry)) { ...
{code}
And there is no else statement.
In case this is useful for anyone else, for now I have worked around the issue
using this:
{code:java}
/**
* This is a hackaround for connections not being release (and thus not reused)
when using TLS client certs.
* The problem is that the connection is requested with state==null but
released with state==javax.security.auth.x500.X500Principal.
* Since our use case does not require the state value to be none null, enforce
that assumption and override it when releasing connections.
*/
private static class MyPoolingNHttpClientConnectionManager extends
PoolingNHttpClientConnectionManager {
public MyPoolingNHttpClientConnectionManager(final ConnectingIOReactor
ioreactor, final NHttpConnectionFactory<ManagedNHttpClientConnection>
connFactory,
final Registry<SchemeIOSessionStrategy> iosessionFactoryRegistry,
final DnsResolver dnsResolver) {
super(ioreactor, connFactory, iosessionFactoryRegistry, dnsResolver);
}
@Override
public Future<NHttpClientConnection> requestConnection(final HttpRoute
route, final Object state, final long connectTimeout, final long leaseTimeout,
final TimeUnit tunit,
final FutureCallback<NHttpClientConnection> callback) {
if (state != null) throw new UnsupportedOperationException("Requesting
connections with state!=null is not supported by this work around.");
new Exception().printStackTrace();
return super.requestConnection(route, state, connectTimeout,
leaseTimeout, tunit, callback);
}
@Override
public void releaseConnection(final NHttpClientConnection managedConn,
final Object state, final long keepalive, final TimeUnit tunit) {
new Exception().printStackTrace();
super.releaseConnection(managedConn, null, keepalive, tunit); // XXX
Deliberately replace state with null.
}
}
{code}
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]