[ 
https://issues.apache.org/jira/browse/HTTPCLIENT-2386?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18032369#comment-18032369
 ] 

Jens Popp edited comment on HTTPCLIENT-2386 at 10/24/25 9:26 AM:
-----------------------------------------------------------------

This issue caused a change in behavior in a minor build that was difficult to 
detect. Basically I have connectTimout and requestTimeout. I want to have a 
fast fail if the connection including tls handshake cannot be established, but 
the request can take very long. In 5.5 this worked with some settings as 
described below. The commit and 5.5.1 cause a change in behavior that the tls 
handshake failure is no longer covered and the request timeout is used in 5.5.1
Old code worked in 5.5:

 
{code:java}
            final TlsSocketStrategy tlsSocketStrategey = sslContext != null
                    ? new DefaultClientTlsStrategy(sslContext, verifier)
                    : null;
            final PoolingHttpClientConnectionManagerBuilder 
connectionManagerBuilder = PoolingHttpClientConnectionManagerBuilder
                    
.create().setPoolConcurrencyPolicy(PoolConcurrencyPolicy.STRICT)
                    
.setConnPoolPolicy(PoolReusePolicy.LIFO).setTlsSocketStrategy(tlsSocketStrategey);
            final ConnectionConfig.Builder connConfig = 
ConnectionConfig.custom();
            if (connectTimeout != null) {
                connectionManagerBuilder
                        .setDefaultConnectionConfig(
                                
ConnectionConfig.custom().setConnectTimeout(Timeout.of(connectTimeout))
                                    
.setSocketTimeout(Timeout.of(connectTimeout)).build())
                        
.setDefaultSocketConfig(SocketConfig.custom().setSoTimeout(Timeout.of(connectTimeout)).build())
                        .build();
            }
            // Request Timeout is set in interceptor
            
...  {code}
New code required from 5.5.1
{code:java}
            final TlsSocketStrategy tlsSocketStrategey = sslContext != null
                    ? new DefaultClientTlsStrategy(sslContext, verifier)
                    : null;            
            // New fix due to changes in 5.5.1 ;
            TlsConfig tlsConfig = sslContext != null
                    ? 
TlsConfig.custom().setHandshakeTimeout(Timeout.of(connectTimeout)) // TLS 
handshake specific
                            .build()
                    : null;
            final PoolingHttpClientConnectionManagerBuilder 
connectionManagerBuilder = PoolingHttpClientConnectionManagerBuilder
                    
.create().setPoolConcurrencyPolicy(PoolConcurrencyPolicy.STRICT)
                    
.setConnPoolPolicy(PoolReusePolicy.LIFO).setTlsSocketStrategy(tlsSocketStrategey)
                    .setDefaultTlsConfig(tlsConfig);
... same as above{code}
 

 

 

 


was (Author: JIRAUSER311288):
This issue caused a change in behavior in a minor build that was difficult to 
detect. Basically I have connectTimout and requestTimeout. I want to have a 
fast fail if the connection including tls handshake cannot be established, but 
the request can take very long. In 5.5 this worked with some settings as 
described below. The commit and 5.5.1 cause a change in behavior that the tls 
handshake failure is no longer covered and the request timeout is used in 5.5.1
Old code worked in 5.5:

 
{code:java}
            final TlsSocketStrategy tlsSocketStrategey = sslContext != null
                    ? new DefaultClientTlsStrategy(sslContext, verifier)
                    : null;
            final PoolingHttpClientConnectionManagerBuilder 
connectionManagerBuilder = PoolingHttpClientConnectionManagerBuilder
                    
.create().setPoolConcurrencyPolicy(PoolConcurrencyPolicy.STRICT)
                    
.setConnPoolPolicy(PoolReusePolicy.LIFO).setTlsSocketStrategy(tlsSocketStrategey);
            final ConnectionConfig.Builder connConfig = 
ConnectionConfig.custom();
            if (connectTimeout != null) {
                connectionManagerBuilder
                        .setDefaultConnectionConfig(
                                
ConnectionConfig.custom().setConnectTimeout(Timeout.of(connectTimeout))
                                    
.setSocketTimeout(Timeout.of(connectTimeout)).build())
                        
.setDefaultSocketConfig(SocketConfig.custom().setSoTimeout(Timeout.of(connectTimeout)).build())
                        .build();
            }
            // Request Timeout is set in interceptor
            
connectionManagerBuilder.setDefaultConnectionConfig(connConfig.build());
            final HttpClientBuilder builder = HttpClients.custom()
                    .setConnectionManager(connectionManagerBuilder.build());
...  {code}
New code required from 5.5.1
{code:java}
            final TlsSocketStrategy tlsSocketStrategey = sslContext != null
                    ? new DefaultClientTlsStrategy(sslContext, verifier)
                    : null;            
            // New fix due to changes in 5.5.1 ;
            TlsConfig tlsConfig = sslContext != null
                    ? 
TlsConfig.custom().setHandshakeTimeout(Timeout.of(connectTimeout)) // TLS 
handshake specific
                            .build()
                    : null;
            final PoolingHttpClientConnectionManagerBuilder 
connectionManagerBuilder = PoolingHttpClientConnectionManagerBuilder
                    
.create().setPoolConcurrencyPolicy(PoolConcurrencyPolicy.STRICT)
                    
.setConnPoolPolicy(PoolReusePolicy.LIFO).setTlsSocketStrategy(tlsSocketStrategey)
                    .setDefaultTlsConfig(tlsConfig);
... same as above{code}
 

 

 

 

> httpClient5 socketTimeoutException in dataChannel with connectTimeout value
> ---------------------------------------------------------------------------
>
>                 Key: HTTPCLIENT-2386
>                 URL: https://issues.apache.org/jira/browse/HTTPCLIENT-2386
>             Project: HttpComponents HttpClient
>          Issue Type: Improvement
>          Components: HttpClient (async)
>    Affects Versions: 5.4.4
>         Environment: httpclient5 version: 5.4.4
> httpCore5 version: 5.3.4
> Java version: 17 (21 since recently)
>            Reporter: Cenk Pekyaman
>            Priority: Minor
>             Fix For: 5.5.1, 5.6-alpha1
>
>          Time Spent: 5h
>  Remaining Estimate: 0h
>
> We are using http-client-5 under our api-client layer with async + TLS. Once 
> in a while, we get a timeout exception like this: 
> "{*}java.net.SocketTimeoutException: 2 SECONDS{*}" in some requests. and from 
> the stack trace, we see that the exception is coming from 
> "InternalDataChannel.onTimeout". but the value we see is actually the 
> {*}connectTimeout{*}, not the readTimeout({*}socketTimeout{*}) we set for the 
> request.
> we specify our *connectTimeout* as *2 seconds* in 
> *PoolingAsyncClientConnectionManagerBuilder* during client creation. we 
> specify our *socketTimeout* as *10 seconds* in *RequestConfig* of 
> *HttpClientContext* during request execution. 
>  
> this is how we make the call (a bit simplified):
> {{// the last parameter is our class implementing FutureCallback}}
> {{Future<Message<HttpResponse, RES>> clientFuture = 
> asyncHttpClient.execute(asyncRequestProducer, responseConsumer, null, 
> httpClientContext, this);}}
> {{// callTimeout is essentially connectTimeout + socketTimeout by default.}}
> {{return clientFuture.get(callTimeout, TimeUnit.MILLISECONDS);}}
>  
> We suspect that the client completes the initial connect step with 
> "InternalConnectChannel" and then the socket is handed over to 
> "InternalDataChannel" to do the TLS handshake in "{*}startTls{*}", which 
> either takes too long to complete, or hangs. Since we don't specify 
> handshakeTimeout in our tlsconfig, *DefaultAsyncClientConnectionOperator* 
> seems to be using *connectTimeout* for this stage (in the callback called 
> after connection is established ?).
>  
> Code flow is essentially correct but getting a generic socketTimeoutException 
> with the value of connectTimeout seems a bit confusing, as we normally expect 
> some ConnectTimeoutException if we really have a connection timeout, or the 
> other way around.
>  
> This is an example stack trace for such a case:
> {{ at org.apache.hc.core5.concurrent.BasicFuture.failed(BasicFuture.java:166) 
> [httpcore5-5.3.4.jar:5.3.4] at 
> org.apache.hc.core5.concurrent.ComplexFuture.failed(ComplexFuture.java:79) 
> [httpcore5-5.3.4.jar:5.3.4] at 
> org.apache.hc.client5.http.impl.async.InternalAbstractHttpAsyncClient$2.failed(InternalAbstractHttpAsyncClient.java:364)
>  [httpclient5-5.4.4.jar:5.4.4] at 
> org.apache.hc.client5.http.impl.async.AsyncRedirectExec$1.failed(AsyncRedirectExec.java:246)
>  [httpclient5-5.4.4.jar:5.4.4] at 
> org.apache.hc.client5.http.impl.async.AsyncProtocolExec$1.failed(AsyncProtocolExec.java:295)
>  [httpclient5-5.4.4.jar:5.4.4] at 
> org.apache.hc.client5.http.impl.async.AsyncConnectExec$2.failed(AsyncConnectExec.java:233)
>  [httpclient5-5.4.4.jar:5.4.4] at 
> org.apache.hc.core5.concurrent.CallbackContribution.failed(CallbackContribution.java:52)
>  [httpcore5-5.3.4.jar:5.3.4] at 
> org.apache.hc.core5.concurrent.BasicFuture.failed(BasicFuture.java:166) 
> [httpcore5-5.3.4.jar:5.3.4] at 
> org.apache.hc.core5.concurrent.ComplexFuture.failed(ComplexFuture.java:79) 
> [httpcore5-5.3.4.jar:5.3.4] at 
> org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager$4.failed(PoolingAsyncClientConnectionManager.java:482)
>  [httpclient5-5.4.4.jar:5.4.4] at 
> org.apache.hc.core5.concurrent.BasicFuture.failed(BasicFuture.java:166) 
> [httpcore5-5.3.4.jar:5.3.4] at 
> org.apache.hc.core5.concurrent.ComplexFuture.failed(ComplexFuture.java:79) 
> [httpcore5-5.3.4.jar:5.3.4] at 
> org.apache.hc.core5.concurrent.FutureContribution.failed(FutureContribution.java:52)
>  [httpcore5-5.3.4.jar:5.3.4] at 
> org.apache.hc.core5.concurrent.CallbackContribution.failed(CallbackContribution.java:52)
>  [httpcore5-5.3.4.jar:5.3.4] at 
> org.apache.hc.core5.reactor.ssl.SSLIOSession$1.exception(SSLIOSession.java:233)
>  [httpcore5-5.3.4.jar:5.3.4] at 
> org.apache.hc.core5.reactor.ssl.SSLIOSession$1.timeout(SSLIOSession.java:223) 
> [httpcore5-5.3.4.jar:5.3.4] at 
> org.apache.hc.core5.reactor.InternalDataChannel.onTimeout(InternalDataChannel.java:170)
>  [httpcore5-5.3.4.jar:5.3.4] at 
> org.apache.hc.core5.reactor.InternalChannel.checkTimeout(InternalChannel.java:67)
>  [httpcore5-5.3.4.jar:5.3.4] at 
> org.apache.hc.core5.reactor.SingleCoreIOReactor.checkTimeout(SingleCoreIOReactor.java:239)
>  [httpcore5-5.3.4.jar:5.3.4] at 
> org.apache.hc.core5.reactor.SingleCoreIOReactor.validateActiveChannels(SingleCoreIOReactor.java:166)
>  [httpcore5-5.3.4.jar:5.3.4] at 
> org.apache.hc.core5.reactor.SingleCoreIOReactor.doExecute(SingleCoreIOReactor.java:128)
>  [httpcore5-5.3.4.jar:5.3.4] at 
> org.apache.hc.core5.reactor.AbstractSingleCoreIOReactor.execute(AbstractSingleCoreIOReactor.java:92)
>  [httpcore5-5.3.4.jar:5.3.4] at 
> org.apache.hc.core5.reactor.IOReactorWorker.run(IOReactorWorker.java:44) 
> [httpcore5-5.3.4.jar:5.3.4] at java.lang.Thread.run(Thread.java:840) [?:?] 
> Caused by: java.net.SocketTimeoutException: 2 SECONDS at 
> org.apache.hc.core5.io.SocketTimeoutExceptionFactory.create(SocketTimeoutExceptionFactory.java:50)
>  ~[httpcore5-5.3.4.jar:5.3.4]}}



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to