hc-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Fae Hutter (JIRA)" <j...@apache.org>
Subject [jira] [Commented] (HTTPASYNC-103) Connections reuse does not work when using TLS client certs
Date Thu, 03 Mar 2016 11:06:18 GMT

    [ https://issues.apache.org/jira/browse/HTTPASYNC-103?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15177673#comment-15177673

Fae Hutter commented on HTTPASYNC-103:

Hi, thanks for the quick reply.  I think I understand the concept.
The client cert is configured as part of the {{SSLContext}}, which is part of the {{SSLIOSessionStrategy}}
for all {{https}} connections in the {{PoolingNHttpClientConnectionManager}}.
Since it is configured before the connection is requested from the pool, why is {{state}}
null when the connection is requested from the pool and not the {{X500Principal}}?
Or is it the intended default behaviour that a connection should never be reused when using
a client cert?

I have now found {{org.apache.http.impl.nio.client.HttpAsyncClientBuilder.disableConnectionState()}}
which seems to cause connections to be reused.  Its JavaDoc of "Disables connection state
tracking." is not particularly helpful.

While trying to debug this, at first I thought that {{this.leased.remove(entry)}} would fail,
and so the connection would never actually be able to be reused.  But on closer inspection
I realised that {{org.apache.http.impl.nio.conn.CPoolEntry.class}} does not override {{equals()}}
and its always the same instance, so changing its fields does not alter its equality.  To
me this is kinda confusing and unexpected.

> 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()}}
> {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
> {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
>  * 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,
>     }
>     @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

To unsubscribe, e-mail: dev-unsubscribe@hc.apache.org
For additional commands, e-mail: dev-help@hc.apache.org

View raw message