[jira] [Comment Edited] (HTTPCLIENT-2386) httpClient5 socketTimeoutException in dataChannel with connectTimeout value

2025-10-24 Thread Jens Popp (Jira)


[ 
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 10:20 AM:
--

{*}Update{*}:

I found a bug in my code, that explains the behavior. So the TlsConfig is not 
necessary when connectionTimout in ConnectionConfig is set correctly! However 
the change still affected the default behavior, if the connectionTimout is 
default but the soTimeout is set in the SocketConfig.



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):
{*}Update{*}:

I found a bug in my code, that explains the behavior. So the TlsConfig is not 
necessary when connectionTimout in ConnectionConfig is set correctly! However 
the change still affected the default behavior, if the connectionTimout is 
default but the soTimeout is set in the SocketConfig.

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())
                        
.

[jira] [Comment Edited] (HTTPCLIENT-2386) httpClient5 socketTimeoutException in dataChannel with connectTimeout value

2025-10-24 Thread Jens Popp (Jira)


[ 
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 10:19 AM:
--

{*}Update{*}:

I found a bug in my code, that explains the behavior. So the TlsConfig is not 
necessary when connectionTimout in ConnectionConfig is set correctly! However 
the change still affected the default behavior, if the connectionTimout is 
default but the soTimeout is set in the SocketConfig.

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
            
...  {code}
New code required from 5.5.1
{code:java}
            final TlsSocketStrategy tlsSocketStr

[jira] [Comment Edited] (HTTPCLIENT-2386) httpClient5 socketTimeoutException in dataChannel with connectTimeout value

2025-10-24 Thread Jens Popp (Jira)


[ 
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

[jira] [Comment Edited] (HTTPCLIENT-2386) httpClient5 socketTimeoutException in dataChannel with connectTimeout value

2025-08-04 Thread Cenk Pekyaman (Jira)


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

Cenk Pekyaman edited comment on HTTPCLIENT-2386 at 8/4/25 12:16 PM:


[~abernal], even though the core issue seems to be inconsistency between 
classic and async, which is solved by pull-request#694, 
[https://github.com/apache/httpcomponents-core/pull/541] can still be useful in 
general, I think.

most people assume they couldn't even connect when they see a 
`connectTimeoutException`, and assume they could connect but couldn't receive a 
response in time if they see a `socketTimeoutException`.

it seems initial tls handshake is somewhat in the middle, and distinguishing it 
via a different message or exception can prove useful in diagnosing failures 
more easily.

it can also help with some retry behaviour as a generic 
`socketTimeoutException` is not necessarily safe to retry if you don't have an 
idemponent request, but the other type of timeouts can be.

 

but I don't know if this ticket is the correct place to fix / improve that part.


was (Author: JIRAUSER310612):
[~abernal], even though the core issue seems to be inconsistency between 
classic and async, which is solved by pull-request#694, 
[https://github.com/apache/httpcomponents-core/pull/541] can still be useful in 
general, I think.

most people assume they couldn't even connect when they see a 
`connectTimeoutException`, and assume they could connect but couldn't receive a 
response in time if they see a `socketTimeoutException`.

it seems initial tls handshake is somewhat in the middle, and distinguishing it 
via a different message or exception can prove useful in diagnosing failures 
more easily.

it can also help with some retry behaviour as a generic 
`socketTimeoutException` is not necessarily safe to retry if you don't have an 
idemponent request, but the other type of timeouts can be.

> 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
>  Time Spent: 1h 40m
>  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> 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.c