[ 
https://issues.apache.org/jira/browse/HTTPCLIENT-2364?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Fabien Arrault updated HTTPCLIENT-2364:
---------------------------------------
    Description: 
We are using Apache HTTPClient 5.4.3 to connect in HTTPS to different remote 
servers through a corporate proxy (connecting in HTTP to the proxy)

Our application currently need to recreate the httpclient in some cases and 
before that : it closes the previous 
{{org.apache.hc.client5.http.impl.classic.CloseableHttpClient}} using the 
IMMEDIATE mode : {{{}httpClient.close(CloseMode.IMMEDIATE{}}}) :
however for some remote servers : the close is not immediate at all and take 2 
minutes.

I don't know which aspect of the remote servers configuration triggers that, 
but it occurs consistently on specific target servers.
It happens only when there is +recently used+ http connection in the connection 
pool (less than 2 minutes apparently)

 

Trying to figure out the problem :
 * When I enable TLS debug log : I can see that our app is blocked waiting for 
the response to a TLS close (see trace below)
 * However, from the code of 
{{{}org.apache.hc.core5.http.impl.io.BHttpConnectionBase#close(org.apache.hc.core5.io.CloseMode){}}},
 its seems that in IMMEDIATE mode, the SSL socket should be bypassed and that 
the physical socket should be directly close instead.

 

Debugging even further it appears that in my use case, the SocketHolder object 
on the connection does not hold two different sockets but only the ssl one :
 * socketHolder.getSSLSocket() is null
 * socketHolder.getBaseSocket() returns the SSL Socket

=> which explains why the Socket.close() is called on a SSLSocket and not the 
underlying physical one

 

It appears that this situation is linked to the use a proxy :
 * the initial connection toward the proxy is plain HTTP => so initially the 
socketHolder has only a baseSocket pointing to the physical socket
 * then after the CONNECT operation to the remote server through the proxy : 
the connection is upgraded to TLS in this method : 
{{org.apache.hc.client5.http.impl.io.DefaultHttpClientConnectionOperator#upgrade}}

This method seems to fail to attach both sockets to the connection retaining 
only the TLS one :          
{code:java}
SSLSocket upgradedSocket = tlsSocketStrategy.upgrade(socket, 
tlsName.getHostName(), tlsName.getPort(), attachment, context);

conn.bind(upgradedSocket);{code}
I would have expect this instead +(at least for my specific use case)+ :
{code:java}
SSLSocket upgradedSocket = tlsSocketStrategy.upgrade(socket, 
tlsName.getHostName(), tlsName.getPort(), attachment, context);

conn.bind(upgradedSocket, socket);{code}
 

 
----
Here the TLS log on close (with only one connection in the pool) : 

 
{noformat}
18:11:23.498 [main] DEBUG 
org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager - 
Shutdown connection pool IMMEDIATE
18:11:23.498 [main] DEBUG 
org.apache.hc.client5.http.impl.io.DefaultManagedHttpClientConnection - 
http-outgoing-0 close connection IMMEDIATE
javax.net.ssl|DEBUG|10|main|2025-03-28 18:11:23.498 
CET|SSLSocketImpl.java:577|duplex close of SSLSocket
javax.net.ssl|DEBUG|10|main|2025-03-28 18:11:23.500 
CET|SSLSocketOutputRecord.java:71|WRITE: TLSv1.2 alert(close_notify), length = 
10
javax.net.ssl|DEBUG|10|main|2025-03-28 18:11:23.500 
CET|SSLCipher.java:1773|Plaintext before ENCRYPTION (
  0000: 01 00                                              ..
)
javax.net.ssl|DEBUG|10|main|2025-03-28 18:11:23.501 
CET|SSLSocketOutputRecord.java:85|Raw write (
  0000: 15 03 03 00 1A 00 00 00   00 00 00 00 02 7B C3 9A  ................
  0010: 10 31 40 75 4D C5 AA 32   A9 C3 4A 3F 77 F1 80     .1@uM..2..J?w..
)
javax.net.ssl|DEBUG|10|main|2025-03-28 18:11:23.501 
CET|SSLSocketImpl.java:1759|close the underlying socket
javax.net.ssl|DEBUG|10|main|2025-03-28 18:11:23.502 
CET|SSLSocketImpl.java:1785|close the SSL connection (initiative)
javax.net.ssl|DEBUG|10|main|2025-03-28 18:11:23.502 
CET|SSLSocketImpl.java:1837|wait for close_notify or alert
javax.net.ssl|DEBUG|10|main|2025-03-28 18:13:23.530 
CET|SSLSocketInputRecord.java:487|Raw read: EOF
javax.net.ssl|DEBUG|10|main|2025-03-28 18:13:23.531 
CET|SSLSocketImpl.java:837|close inbound of SSLSocket
javax.net.ssl|ALL|10|main|2025-03-28 18:13:23.532 
CET|SSLSocketImpl.java:1847|discard plaintext while waiting for close (
contentType: 0/majorVersion: 0/minorVersion: 0/recordEpoch: -1/recordSN: 
0xffffffffffffffff/fragment: null
)
18:13:23.532 [main] DEBUG 
org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager - 
Connection pool shut down{noformat}
Those traces has been captured on Windows.
But the issue also occurs in linux-based production server.

 

  was:
We are using Apache HTTPClient 5.4.3 to connect in HTTPS to different remote 
servers through a corporate proxy (connecting in HTTP to the proxy)


Our application currently need to recreate the httpclient in some cases and 
before that : it closes the previous 
{{org.apache.hc.client5.http.impl.classic.CloseableHttpClient}} using the 
IMMEDIATE mode : {{{}httpClient.close(CloseMode.IMMEDIATE{}}}) :
however for some remote servers : the close is not immediate at all and take 2 
minutes.

I don't know which aspect of the remote servers configuration triggers that, 
but it occurs consistently on specific target servers.
It happens only when there is +recently used+ http connection in the connection 
pool (less than 2 minutes apparently)


Trying to figure out the problem :

When I enable TLS debug log : I can see that our app is blocked waiting for the 
response to a TLS close record (see trace below)

However, from the code of 
{{{}org.apache.hc.core5.http.impl.io.BHttpConnectionBase#close(org.apache.hc.core5.io.CloseMode){}}},
 its seems that in IMMEDIATE mode, the SSL socket should be bypassed and that 
the physical socket should be directly close instead.


Debuging even further it appears that in my use case, the SocketHolder object 
on the connection does not hold two different sockets but only the ssl one :
 * socketHolder.getSSLSocket() is null
 * socketHolder.getBaseSocket() returns the SSL Socket

=> which explains why the Socket.close() is called on a SSLSocket and not the 
underlying physical one


It appears that this situation is linked to the use a proxy :
 * the initial connection toward the proxy is plain HTTP => so initially the 
socketHolder has only a baseSocket pointing to the physical socket
 * then after the CONNECT operation to the remote server through the proxy : 
the connection is upgraded to TLS in this method : 
{{org.apache.hc.client5.http.impl.io.DefaultHttpClientConnectionOperator#upgrade}}

This method seems to fail to attach both sockets to the connection retaining 
only the TLS one :          
{code:java}
SSLSocket upgradedSocket = tlsSocketStrategy.upgrade(socket, 
tlsName.getHostName(), tlsName.getPort(), attachment, context);

conn.bind(upgradedSocket);{code}

I would have expect this instead +(at least for my specific use case)+ :
{code:java}
SSLSocket upgradedSocket = tlsSocketStrategy.upgrade(socket, 
tlsName.getHostName(), tlsName.getPort(), attachment, context);

conn.bind(upgradedSocket, socket);{code}
 

 

----


Here the TLS log on close (with only one connection in the pool) : 

 
{noformat}
18:11:23.498 [main] DEBUG 
org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager - 
Shutdown connection pool IMMEDIATE
18:11:23.498 [main] DEBUG 
org.apache.hc.client5.http.impl.io.DefaultManagedHttpClientConnection - 
http-outgoing-0 close connection IMMEDIATE
javax.net.ssl|DEBUG|10|main|2025-03-28 18:11:23.498 
CET|SSLSocketImpl.java:577|duplex close of SSLSocket
javax.net.ssl|DEBUG|10|main|2025-03-28 18:11:23.500 
CET|SSLSocketOutputRecord.java:71|WRITE: TLSv1.2 alert(close_notify), length = 
10
javax.net.ssl|DEBUG|10|main|2025-03-28 18:11:23.500 
CET|SSLCipher.java:1773|Plaintext before ENCRYPTION (
  0000: 01 00                                              ..
)
javax.net.ssl|DEBUG|10|main|2025-03-28 18:11:23.501 
CET|SSLSocketOutputRecord.java:85|Raw write (
  0000: 15 03 03 00 1A 00 00 00   00 00 00 00 02 7B C3 9A  ................
  0010: 10 31 40 75 4D C5 AA 32   A9 C3 4A 3F 77 F1 80     .1@uM..2..J?w..
)
javax.net.ssl|DEBUG|10|main|2025-03-28 18:11:23.501 
CET|SSLSocketImpl.java:1759|close the underlying socket
javax.net.ssl|DEBUG|10|main|2025-03-28 18:11:23.502 
CET|SSLSocketImpl.java:1785|close the SSL connection (initiative)
javax.net.ssl|DEBUG|10|main|2025-03-28 18:11:23.502 
CET|SSLSocketImpl.java:1837|wait for close_notify or alert
javax.net.ssl|DEBUG|10|main|2025-03-28 18:13:23.530 
CET|SSLSocketInputRecord.java:487|Raw read: EOF
javax.net.ssl|DEBUG|10|main|2025-03-28 18:13:23.531 
CET|SSLSocketImpl.java:837|close inbound of SSLSocket
javax.net.ssl|ALL|10|main|2025-03-28 18:13:23.532 
CET|SSLSocketImpl.java:1847|discard plaintext while waiting for close (
contentType: 0/majorVersion: 0/minorVersion: 0/recordEpoch: -1/recordSN: 
0xffffffffffffffff/fragment: null
)
18:13:23.532 [main] DEBUG 
org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager - 
Connection pool shut down{noformat}
Those traces has been captured on Windows.
But the issue also occurs in linux-based production server.

 


> Close IMMEDIATE does not work properly on HTTPS-upgraded connection through 
> proxy
> ---------------------------------------------------------------------------------
>
>                 Key: HTTPCLIENT-2364
>                 URL: https://issues.apache.org/jira/browse/HTTPCLIENT-2364
>             Project: HttpComponents HttpClient
>          Issue Type: Bug
>          Components: HttpClient (classic)
>    Affects Versions: 5.4.3
>            Reporter: Fabien Arrault
>            Priority: Minor
>
> We are using Apache HTTPClient 5.4.3 to connect in HTTPS to different remote 
> servers through a corporate proxy (connecting in HTTP to the proxy)
> Our application currently need to recreate the httpclient in some cases and 
> before that : it closes the previous 
> {{org.apache.hc.client5.http.impl.classic.CloseableHttpClient}} using the 
> IMMEDIATE mode : {{{}httpClient.close(CloseMode.IMMEDIATE{}}}) :
> however for some remote servers : the close is not immediate at all and take 
> 2 minutes.
> I don't know which aspect of the remote servers configuration triggers that, 
> but it occurs consistently on specific target servers.
> It happens only when there is +recently used+ http connection in the 
> connection pool (less than 2 minutes apparently)
>  
> Trying to figure out the problem :
>  * When I enable TLS debug log : I can see that our app is blocked waiting 
> for the response to a TLS close (see trace below)
>  * However, from the code of 
> {{{}org.apache.hc.core5.http.impl.io.BHttpConnectionBase#close(org.apache.hc.core5.io.CloseMode){}}},
>  its seems that in IMMEDIATE mode, the SSL socket should be bypassed and that 
> the physical socket should be directly close instead.
>  
> Debugging even further it appears that in my use case, the SocketHolder 
> object on the connection does not hold two different sockets but only the ssl 
> one :
>  * socketHolder.getSSLSocket() is null
>  * socketHolder.getBaseSocket() returns the SSL Socket
> => which explains why the Socket.close() is called on a SSLSocket and not the 
> underlying physical one
>  
> It appears that this situation is linked to the use a proxy :
>  * the initial connection toward the proxy is plain HTTP => so initially the 
> socketHolder has only a baseSocket pointing to the physical socket
>  * then after the CONNECT operation to the remote server through the proxy : 
> the connection is upgraded to TLS in this method : 
> {{org.apache.hc.client5.http.impl.io.DefaultHttpClientConnectionOperator#upgrade}}
> This method seems to fail to attach both sockets to the connection retaining 
> only the TLS one :          
> {code:java}
> SSLSocket upgradedSocket = tlsSocketStrategy.upgrade(socket, 
> tlsName.getHostName(), tlsName.getPort(), attachment, context);
> conn.bind(upgradedSocket);{code}
> I would have expect this instead +(at least for my specific use case)+ :
> {code:java}
> SSLSocket upgradedSocket = tlsSocketStrategy.upgrade(socket, 
> tlsName.getHostName(), tlsName.getPort(), attachment, context);
> conn.bind(upgradedSocket, socket);{code}
>  
>  
> ----
> Here the TLS log on close (with only one connection in the pool) : 
>  
> {noformat}
> 18:11:23.498 [main] DEBUG 
> org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager - 
> Shutdown connection pool IMMEDIATE
> 18:11:23.498 [main] DEBUG 
> org.apache.hc.client5.http.impl.io.DefaultManagedHttpClientConnection - 
> http-outgoing-0 close connection IMMEDIATE
> javax.net.ssl|DEBUG|10|main|2025-03-28 18:11:23.498 
> CET|SSLSocketImpl.java:577|duplex close of SSLSocket
> javax.net.ssl|DEBUG|10|main|2025-03-28 18:11:23.500 
> CET|SSLSocketOutputRecord.java:71|WRITE: TLSv1.2 alert(close_notify), length 
> = 10
> javax.net.ssl|DEBUG|10|main|2025-03-28 18:11:23.500 
> CET|SSLCipher.java:1773|Plaintext before ENCRYPTION (
>   0000: 01 00                                              ..
> )
> javax.net.ssl|DEBUG|10|main|2025-03-28 18:11:23.501 
> CET|SSLSocketOutputRecord.java:85|Raw write (
>   0000: 15 03 03 00 1A 00 00 00   00 00 00 00 02 7B C3 9A  ................
>   0010: 10 31 40 75 4D C5 AA 32   A9 C3 4A 3F 77 F1 80     .1@uM..2..J?w..
> )
> javax.net.ssl|DEBUG|10|main|2025-03-28 18:11:23.501 
> CET|SSLSocketImpl.java:1759|close the underlying socket
> javax.net.ssl|DEBUG|10|main|2025-03-28 18:11:23.502 
> CET|SSLSocketImpl.java:1785|close the SSL connection (initiative)
> javax.net.ssl|DEBUG|10|main|2025-03-28 18:11:23.502 
> CET|SSLSocketImpl.java:1837|wait for close_notify or alert
> javax.net.ssl|DEBUG|10|main|2025-03-28 18:13:23.530 
> CET|SSLSocketInputRecord.java:487|Raw read: EOF
> javax.net.ssl|DEBUG|10|main|2025-03-28 18:13:23.531 
> CET|SSLSocketImpl.java:837|close inbound of SSLSocket
> javax.net.ssl|ALL|10|main|2025-03-28 18:13:23.532 
> CET|SSLSocketImpl.java:1847|discard plaintext while waiting for close (
> contentType: 0/majorVersion: 0/minorVersion: 0/recordEpoch: -1/recordSN: 
> 0xffffffffffffffff/fragment: null
> )
> 18:13:23.532 [main] DEBUG 
> org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager - 
> Connection pool shut down{noformat}
> Those traces has been captured on Windows.
> But the issue also occurs in linux-based production server.
>  



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

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

Reply via email to