Fabien Arrault created HTTPCLIENT-2364:
------------------------------------------
Summary: 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
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 [email protected]?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: [email protected]
For additional commands, e-mail: [email protected]