Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Channel inactive not fired after SslCloseCompletionEvent(SUCCESS) causing connection still in pool hence io.netty.handler.ssl.SslClosedEngineException: SSLEngine closed already #2498

Closed
cyfax opened this issue Sep 21, 2022 · 14 comments · Fixed by #2518
Assignees
Labels
type/bug A general bug
Milestone

Comments

@cyfax
Copy link

cyfax commented Sep 21, 2022

From time to time a connection is still in pool but should not.

Expected Behavior

SslCloseCompletionEvent(SUCCESS) not correctly handled is causing connection still present in pool hence "io.netty.handler.ssl.SslClosedEngineException: SSLEngine closed already" thrown on next usage of the connection.
A Channel 'INACTIVE' shoud be fired after SslCloseCompletionEvent(SUCCESS)

Here is a fine example of a multi used (7 times) connection :
At the end, the connection is unregistered as soon as the sslCloseCompletion is fired :
image

Full logs : OK.log

Actual Behavior

In undetermined circumstances, SslCloseCompletionEvent is not followed by INACTIVE
In this example, the connection is reused 5min06 after SslCloseCompletionEvent
Contrary to what happened in "good" example above there is only one 'READ COMPLETE' event fired.
May be this is the reason why fireChannelInacctive is not triggered.
image

Full logs : NOK.log

Steps to Reproduce

Unfortunatly, I have no example to provide since this happen randomly.

Possible Solution

Bad idea, the SslReadHandler is not in the pipeline anymore when this happen.
In reactor.netty.tcp.SslProvider.SslReadHandler.userEventTriggered
image
add

                        if (evt instanceof SslCloseCompletionEvent) {
                            ctx.fireChannelInactive();
                        }

Your Environment

  • Reactor version(s) used: reactor-netty-http : 1.0.23
  • Other relevant libraries versions (eg. netty, ...): netty : 4.1.81.Final
  • JVM version (java -version): openjdk version "1.8.0_342"
  • OS and version (eg. uname -a): Linux 18.04.1-Ubuntu SMP Mon Aug 23 23:07:49 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
@cyfax cyfax added status/need-triage A new issue that still need to be evaluated as a whole type/bug A general bug labels Sep 21, 2022
@pderop pderop removed the status/need-triage A new issue that still need to be evaluated as a whole label Sep 21, 2022
@pderop pderop self-assigned this Sep 21, 2022
@pderop
Copy link
Member

pderop commented Sep 21, 2022

@cyfax ,

  • do you know what server is used ? is it tomcat ?
  • is the server using some kind of configured keep alive/idle timeout (a delay the server will wait for another HTTP request before closing the connection) ?
  • can you share how your are configuring your HttpClient, how are you configuring the connection pool ? for example, are you using a max idle time for your connection pool ?

thanks.

@pderop pderop added the for/user-attention This issue needs user attention (feedback, rework, etc...) label Sep 21, 2022
@pderop
Copy link
Member

pderop commented Sep 22, 2022

In addition, can you attach a tcpdump of the traffic when the exception happens ?
thanks.

@cyfax
Copy link
Author

cyfax commented Sep 23, 2022

Sorry, for the late response :

@cyfax ,

  • do you know what server is used ? is it tomcat ?

Apache Tomcat/9.0.39 wrapped in sring boot 2.4.0

  • is the server using some kind of configured keep alive/idle timeout (a delay the server will wait for another HTTP request before closing the connection) ?

Nothing is set up explicitly, all values are default ones configured by spring boot or from tomcat otherwise.

  • can you share how your are configuring your HttpClient, how are you configuring the connection pool ? for example, are you using a max idle time for your connection pool ?

Here is the configuration :

timeoutSeconds = 5
If a max idle time is used it is the default one.

    public void initWebClient() {

        final HttpClient httpClient = HttpClient.create()
                                                .wiretap(true)
                                                .responseTimeout(Duration.of(timeoutSeconds, ChronoUnit.SECONDS));

        final ClientHttpConnector connector = new ReactorClientHttpConnector(httpClient);

        final WebClient webClient = WebClient.builder().baseUrl(hostFsvUrl).defaultHeaders(httpheaders -> {
            httpheaders.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
            httpheaders.add(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
            httpheaders.add(API_KEY, hostFsvApiKey);
        }).clientConnector(connector).build();

        init(webClient);

    }

@cyfax
Copy link
Author

cyfax commented Sep 23, 2022

@pderop
Can you please tell me if the problem is that :

  1. the connection is still in pool despite SslCloseCompletionEvent(SUCCESS) is received
  2. the connection should be kept in the pool but a new SSL handshake should be run before sending http request.

@pderop pderop removed the for/user-attention This issue needs user attention (feedback, rework, etc...) label Sep 23, 2022
@cyfax
Copy link
Author

cyfax commented Sep 23, 2022

In addition, can you attach a tcpdump of the traffic when the exception happens ? thanks.

I am working on this.
Keep you in touch...

@pderop
Copy link
Member

pderop commented Sep 23, 2022

@cyfax , Hi,

I'm currently investigating, I prefer to be sure before responding ...will let you know asap.

@pderop
Copy link
Member

pderop commented Sep 23, 2022

@cyfax ,

What you suggested in 1/ seems correct: the connection is still in the pool while we are receiving a close_notify from the server.

When the server closes the connection (for whatever reasons), it first sends a close_notify, then after it closes the connection. So, if the application acquires the connection after the close_notify is received but before the socket is closed by the server, then it will get the SSLEngine closed already exception when the request is flushed.

I'm preparing a patch which handles the close_notify in order to close and invalidate the connection if it is in the pool.

@cyfax
Copy link
Author

cyfax commented Sep 26, 2022

In addition, can you attach a tcpdump of the traffic when the exception happens ? thanks.

I am working on this. Keep you in touch...

Here is a new failure @11:02:30 (SSL close not followed by inactive channel)
image

After 'Encrypted Alert' no FIN-ACK is sent/received.
image
After trying to use the SSL closed connection again an exception 'Outbound error happened' is thrown at 11:03:49.68 and FIN-ACK is sent by client at 11:03:49.701184.

When everything is fine, FIN - ACK is SENT by server after 'Encrypted Alert' :
image

and the connection is unregistered from the pool.
image

Full logs : NOK.1.log
Full tcpdump : tcpdump.txt

From my understanding the client is waiting for the server to close the connection (explaining why more than 5mn elapsed between SslCloseCompletionEvent & SslClosedEngineException in NOK.log).
Is it mandatory that client is waiting for server to close the connection or couldn't it close by itself provided SslCloseCompletionEvent is finely received by client ?

@pderop
Copy link
Member

pderop commented Sep 27, 2022

@cyfax,

some updates:

I'm still investigating, sorry for the bit of delay (please ignore my previous message for the moment, I'm still investigating).

So, based on the last NOK.1.log and from the tcpdump, let's focus on the 48702 port. so, indeed, it seems that the client waits for the server FIN, which is not sent by the server after the initial close_notify, and at some point in time, when the client acquires and writes to the connection, then it gets the "SSLEngine closed already" exception, and the client then closes the connection.

let's see this from your provided logs:

at 11:02:30.234595 from tcpdump: the server sends the close_notify to the client, which acknowledges it immediately:

   44 2022-09-26 11:02:30.234595  xx.xx.xx.xx → 11.0.0.110   TLSv1.2 97 Encrypted Alert
   45 2022-09-26 11:02:30.234632   11.0.0.110 → xx.xx.xx.xx  TCP 66 48702 → 443 [ACK] Seq=1955 Ack=6348 Win=56960 Len=0 TSval=3688553944 TSecr=2932835261
   46 2022-09-26 11:02:30.235310   11.0.0.110 → xx.xx.xx.xx  TLSv1.2 97 Encrypted Alert
   47 2022-09-26 11:02:30.276361  xx.xx.xx.xx → 11.0.0.110   TCP 66 443 → 48702 [ACK] Seq=6348 Ack=1986 Win=64128 Len=0 TSval=2932835303 TSecr=3688553945

From NOK.1.log, we see that the client has received the close_notify at 11:02:30.235

11:02:30.235 DEBUG 19934 --- [reactor-http-epoll-3] reactor.netty.http.client.HttpClient     : [ed8b90b8, L:/11.0.0.110:48702 - R:fake.server.com/xx.xx.xx.xx:443] USER_EVENT: SslCloseCompletionEvent(SUCCESS)

But after that, the server does not send a FIN to the client, even if this one has acknowledged the server close_notify with a client close_notify message (see at 11:02:30.235310)

And after 1,19 minute, at 11:03:49.680, the client then acquires the connection from the pool, writes to it, and is getting the "SslClosedEngineException: SSLEngine closed already":

2022-09-26 11:03:49.680 DEBUG 19934 --- [reactor-http-epoll-3] r.n.http.client.HttpClientOperations     : [ed8b90b8-5, L:/11.0.0.110:48702 - R:fake.server.com/xx.xx.xx.xx:443] Outbound error happened

io.netty.handler.ssl.SslClosedEngineException: SSLEngine closed already

then, at 11:03:49.696, the client closes the connection:

2022-09-26 11:03:49.695 TRACE 19934 --- [reactor-http-epoll-3] reactor.netty.channel.ChannelOperations  : [ed8b90b8, L:/11.0.0.110:48702 - R:fake.server.com/xx.xx.xx.xx:443] Disposing ChannelOperation from a channel
2022-09-26 11:03:49.696 DEBUG 19934 --- [reactor-http-epoll-3] r.n.r.DefaultPooledConnectionProvider    : [ed8b90b8, L:/11.0.0.110:48702 - R:fake.server.com/xx.xx.xx.xx:443] onStateChange(POST{uri=/card/event, connection=PooledConnection{channel=[id: 0xed8b90b8, L:/11.0.0.110:48702 - R:fake.server.com/xx.xx.xx.xx:443]}}, [response_completed])
2022-09-26 11:03:49.696 DEBUG 19934 --- [reactor-http-epoll-3] r.n.r.DefaultPooledConnectionProvider    : [ed8b90b8, L:/11.0.0.110:48702 - R:fake.server.com/xx.xx.xx.xx:443] onStateChange(POST{uri=/card/event, connection=PooledConnection{channel=[id: 0xed8b90b8, L:/11.0.0.110:48702 - R:fake.server.com/xx.xx.xx.xx:443]}}, [disconnecting])
2022-09-26 11:03:49.696 DEBUG 19934 --- [reactor-http-epoll-3] reactor.netty.http.client.HttpClient     : [ed8b90b8, L:/11.0.0.110:48702 - R:fake.server.com/xx.xx.xx.xx:443] CLOSE

and at 11:03:49.701184, from tcpdump, we then see that the FIN is sent from the client to the server:

   48 2022-09-26 11:03:49.701184   11.0.0.110 → xx.xx.xx.xx  TCP 66 48702 → 443 [FIN, ACK] Seq=1986 Ack=6348 Win=56960 Len=0 TSval=3688633411 TSecr=2932835303
   49 2022-09-26 11:03:49.744334  xx.xx.xx.xx → 11.0.0.110   TCP 66 443 → 48702 [ACK] Seq=6348 Ack=1987 Win=64128 Len=0 TSval=2932914771 TSecr=3688633411

so, first, it's strange that the server is not closing the connection after having received the close_notify ack sent by the client.

now, we are still investigating, and after discussion with the team, we do not desire the do a patch for the moment, because closing the connection when receiving the close-notify will only resolve your particular scenario, but won't avoid other scenarios where you have already acquired the connection: in this case, if the close_notify is received while you are writing to the acquired connection, then you will get a "Connection prematurely closed BEFORE response" even with the patch. Moreover, we are still investigating if something else could be done.

In the meantime:

Please consider to do what Violeta has suggested from this old issue, which seems to be the same problem: in the issue the problem was that the server was using a Keep-Alive timeout, and the server then sends a close_notify after some period of connection inactivity.

If you are using tomcat without any specific configuration, then Keep-Alive configuration is 60 sec if I'm correct (check #1318 (comment)). And indeed, from your tcpdump.txt, the server sends a close_notify after around 60 sec if inactivity:

   42 2022-09-26 11:01:29.755141  xx.xx.xx.xx → 11.0.0.110   TLSv1.2 100 Application Data
   43 2022-09-26 11:01:29.755149   11.0.0.110 → xx.xx.xx.xx  TCP 66 48702 → 443 [ACK] Seq=1955 Ack=6317 Win=56960 Len=0 TSval=3688493465 TSecr=2932774782
   44 2022-09-26 11:02:30.234595  xx.xx.xx.xx → 11.0.0.110   TLSv1.2 97 Encrypted Alert

So, please consider to use a maxIdleTime on the Reactor Netty's connection pool to be less than the value on the server (check #1318 (comment))

@pderop pderop added the for/user-attention This issue needs user attention (feedback, rework, etc...) label Sep 27, 2022
@cyfax
Copy link
Author

cyfax commented Sep 29, 2022

@pderop
Hi I configured my pool with maxIdleTime=20s
Here are the logs :
You can see maxIdleTime.
The trouble is that the connection is still closed after 60s.
start at 16:38:10
ends at 16:39:10

2022-09-29 16:34:14.242 DEBUG 2004 --- [taskExecutor-1] r.n.resources.PooledConnectionProvider   : Creating a new [custom] client pool [PoolFactory{evictionInterval=PT0S, leasingStrategy=fifo, maxConnections=500, maxIdleTime=20000, maxLifeTime=-1, metricsEnabled=false, pendingAcquireMaxCount=1000, pendingAcquireTimeout=45000}] for [fsv.demo.stellair.fr:443]

2022-09-29 16:38:10.249 DEBUG 2004 --- [reactor-http-epoll-4] r.n.resources.PooledConnectionProvider   : [68eabf93] Created a new pooled channel, now: 0 active connections, 0 inactive connections and 0 pending acquire requests.
2022-09-29 16:38:10.250 DEBUG 2004 --- [reactor-http-epoll-4] reactor.netty.tcp.SslProvider            : [68eabf93] SSL enabled using engine sun.security.ssl.SSLEngineImpl@3ef839e1 and SNI fake.server.com:443
2022-09-29 16:38:10.251 DEBUG 2004 --- [reactor-http-epoll-4] reactor.netty.transport.TransportConfig  : [68eabf93] Initialized pipeline DefaultChannelPipeline{(reactor.left.sslHandler = io.netty.handler.ssl.SslHandler), (reactor.left.loggingHandler = reactor.netty.transport.logging.ReactorNettyLoggingHandler), (reactor.left.sslReader = reactor.netty.tcp.SslProvider$SslReadHandler), (reactor.left.httpCodec = io.netty.handler.codec.http.HttpClientCodec), (reactor.right.reactiveBridge = reactor.netty.channel.ChannelOperationsHandler)}
2022-09-29 16:38:10.252 DEBUG 2004 --- [reactor-http-epoll-4] reactor.netty.http.client.HttpClient     : [68eabf93] REGISTERED
2022-09-29 16:38:10.270 DEBUG 2004 --- [reactor-http-epoll-4] r.netty.transport.TransportConnector     : [68eabf93] Connecting to [fake.server.com/xx.xx.xx.xx:443].
2022-09-29 16:38:10.271 DEBUG 2004 --- [reactor-http-epoll-4] reactor.netty.http.client.HttpClient     : [68eabf93] CONNECT: fake.server.com/xx.xx.xx.xx:443
2022-09-29 16:38:10.272 DEBUG 2004 --- [reactor-http-epoll-4] r.n.r.DefaultPooledConnectionProvider    : [68eabf93, L:/11.0.0.110:45018 - R:fake.server.com/xx.xx.xx.xx:443] Registering pool release on close event for channel
2022-09-29 16:38:10.272 DEBUG 2004 --- [reactor-http-epoll-4] r.n.resources.PooledConnectionProvider   : [68eabf93, L:/11.0.0.110:45018 - R:fake.server.com/xx.xx.xx.xx:443] Channel connected, now: 1 active connections, 0 inactive connections and 0 pending acquire requests.
2022-09-29 16:38:10.284 DEBUG 2004 --- [reactor-http-epoll-4] reactor.netty.http.client.HttpClient     : [68eabf93, L:/11.0.0.110:45018 - R:fake.server.com/xx.xx.xx.xx:443] ACTIVE
2022-09-29 16:38:10.288 DEBUG 2004 --- [reactor-http-epoll-4] reactor.netty.http.client.HttpClient     : [68eabf93, L:/11.0.0.110:45018 - R:fake.server.com/xx.xx.xx.xx:443] USER_EVENT: SslHandshakeCompletionEvent(SUCCESS)
2022-09-29 16:38:10.290 DEBUG 2004 --- [reactor-http-epoll-4] r.n.r.DefaultPooledConnectionProvider    : [68eabf93, L:/11.0.0.110:45018 - R:fake.server.com/xx.xx.xx.xx:443] onStateChange(PooledConnection{channel=[id: 0x68eabf93, L:/11.0.0.110:45018 - R:fake.server.com/xx.xx.xx.xx:443]}, [connected])
2022-09-29 16:38:10.290 DEBUG 2004 --- [reactor-http-epoll-4] r.n.r.DefaultPooledConnectionProvider    : [68eabf93-1, L:/11.0.0.110:45018 - R:fake.server.com/xx.xx.xx.xx:443] onStateChange(GET{uri=/, connection=PooledConnection{channel=[id: 0x68eabf93, L:/11.0.0.110:45018 - R:fake.server.com/xx.xx.xx.xx:443]}}, [configured])
2022-09-29 16:38:10.291 DEBUG 2004 --- [reactor-http-epoll-4] r.netty.http.client.HttpClientConnect    : [68eabf93-1, L:/11.0.0.110:45018 - R:fake.server.com/xx.xx.xx.xx:443] Handler is being applied: {uri=https://fake.server.com/card/event, method=POST}
2022-09-29 16:38:10.292 DEBUG 2004 --- [reactor-http-epoll-4] r.n.r.DefaultPooledConnectionProvider    : [68eabf93-1, L:/11.0.0.110:45018 - R:fake.server.com/xx.xx.xx.xx:443] onStateChange(POST{uri=/card/event, connection=PooledConnection{channel=[id: 0x68eabf93, L:/11.0.0.110:45018 - R:fake.server.com/xx.xx.xx.xx:443]}}, [request_prepared])
2022-09-29 16:38:10.297 DEBUG 2004 --- [reactor-http-epoll-4] reactor.netty.http.client.HttpClient     : [68eabf93-1, L:/11.0.0.110:45018 - R:fake.server.com/xx.xx.xx.xx:443] WRITE: 209B
2022-09-29 16:38:10.300 DEBUG 2004 --- [reactor-http-epoll-4] reactor.netty.http.client.HttpClient     : [68eabf93-1, L:/11.0.0.110:45018 - R:fake.server.com/xx.xx.xx.xx:443] WRITE: 170B
2022-09-29 16:38:10.301 DEBUG 2004 --- [reactor-http-epoll-4] reactor.netty.http.client.HttpClient     : [68eabf93-1, L:/11.0.0.110:45018 - R:fake.server.com/xx.xx.xx.xx:443] FLUSH
2022-09-29 16:38:10.302 DEBUG 2004 --- [reactor-http-epoll-4] r.n.r.DefaultPooledConnectionProvider    : [68eabf93-1, L:/11.0.0.110:45018 - R:fake.server.com/xx.xx.xx.xx:443] onStateChange(POST{uri=/card/event, connection=PooledConnection{channel=[id: 0x68eabf93, L:/11.0.0.110:45018 - R:fake.server.com/xx.xx.xx.xx:443]}}, [request_sent])
2022-09-29 16:38:10.302 DEBUG 2004 --- [reactor-http-epoll-4] reactor.netty.ReactorNetty               : [68eabf93-1, L:/11.0.0.110:45018 - R:fake.server.com/xx.xx.xx.xx:443] Added encoder [reactor.left.responseTimeoutHandler] at the beginning of the user pipeline, full pipeline: [reactor.left.sslHandler, reactor.left.loggingHandler, reactor.left.httpCodec, reactor.left.responseTimeoutHandler, reactor.right.reactiveBridge, DefaultChannelPipeline$TailContext#0]
2022-09-29 16:38:10.302 DEBUG 2004 --- [reactor-http-epoll-4] reactor.netty.http.client.HttpClient     : [68eabf93-1, L:/11.0.0.110:45018 - R:fake.server.com/xx.xx.xx.xx:443] READ COMPLETE
2022-09-29 16:38:10.313 DEBUG 2004 --- [reactor-http-epoll-4] reactor.netty.http.client.HttpClient     : [68eabf93-1, L:/11.0.0.110:45018 - R:fake.server.com/xx.xx.xx.xx:443] READ: 413B
2022-09-29 16:38:10.314 DEBUG 2004 --- [reactor-http-epoll-4] r.n.http.client.HttpClientOperations     : [68eabf93-1, L:/11.0.0.110:45018 - R:fake.server.com/xx.xx.xx.xx:443] Received response (auto-read:false) : [X-Content-Type-Options=nosniff, X-XSS-Protection=1; mode=block, Cache-Control=no-cache, no-store, max-age=0, must-revalidate, Pragma=no-cache, Expires=0, Strict-Transport-Security=max-age=31536000 ; includeSubDomains, X-Frame-Options=DENY, Content-Type=application/json;charset=UTF-8, Transfer-Encoding=chunked, Date=Thu, 29 Sep 2022 14:38:10 GMT]
2022-09-29 16:38:10.314 DEBUG 2004 --- [reactor-http-epoll-4] r.n.r.DefaultPooledConnectionProvider    : [68eabf93-1, L:/11.0.0.110:45018 - R:fake.server.com/xx.xx.xx.xx:443] onStateChange(POST{uri=/card/event, connection=PooledConnection{channel=[id: 0x68eabf93, L:/11.0.0.110:45018 - R:fake.server.com/xx.xx.xx.xx:443]}}, [response_received])
2022-09-29 16:38:10.314 DEBUG 2004 --- [reactor-http-epoll-4] reactor.netty.channel.FluxReceive        : [68eabf93-1, L:/11.0.0.110:45018 - R:fake.server.com/xx.xx.xx.xx:443] FluxReceive{pending=0, cancelled=false, inboundDone=false, inboundError=null}: subscribing inbound receiver
2022-09-29 16:38:10.315 DEBUG 2004 --- [reactor-http-epoll-4] reactor.netty.http.client.HttpClient     : [68eabf93-1, L:/11.0.0.110:45018 - R:fake.server.com/xx.xx.xx.xx:443] READ: 5B
2022-09-29 16:38:10.315 DEBUG 2004 --- [reactor-http-epoll-4] r.n.http.client.HttpClientOperations     : [68eabf93-1, L:/11.0.0.110:45018 - R:fake.server.com/xx.xx.xx.xx:443] Received last HTTP packet
2022-09-29 16:38:10.315 TRACE 2004 --- [reactor-http-epoll-4] reactor.netty.channel.ChannelOperations  : [68eabf93, L:/11.0.0.110:45018 - R:fake.server.com/xx.xx.xx.xx:443] Disposing ChannelOperation from a channel
2022-09-29 16:38:10.316 DEBUG 2004 --- [reactor-http-epoll-4] r.n.r.DefaultPooledConnectionProvider    : [68eabf93, L:/11.0.0.110:45018 - R:fake.server.com/xx.xx.xx.xx:443] onStateChange(POST{uri=/card/event, connection=PooledConnection{channel=[id: 0x68eabf93, L:/11.0.0.110:45018 - R:fake.server.com/xx.xx.xx.xx:443]}}, [response_completed])
2022-09-29 16:38:10.316 DEBUG 2004 --- [reactor-http-epoll-4] reactor.netty.ReactorNetty               : [68eabf93, L:/11.0.0.110:45018 - R:fake.server.com/xx.xx.xx.xx:443] Removed handler: reactor.left.responseTimeoutHandler, pipeline: DefaultChannelPipeline{(reactor.left.sslHandler = io.netty.handler.ssl.SslHandler), (reactor.left.loggingHandler = reactor.netty.transport.logging.ReactorNettyLoggingHandler), (reactor.left.httpCodec = io.netty.handler.codec.http.HttpClientCodec), (reactor.right.reactiveBridge = reactor.netty.channel.ChannelOperationsHandler)}
2022-09-29 16:38:10.316 DEBUG 2004 --- [reactor-http-epoll-4] r.n.r.DefaultPooledConnectionProvider    : [68eabf93, L:/11.0.0.110:45018 - R:fake.server.com/xx.xx.xx.xx:443] onStateChange(POST{uri=/card/event, connection=PooledConnection{channel=[id: 0x68eabf93, L:/11.0.0.110:45018 - R:fake.server.com/xx.xx.xx.xx:443]}}, [disconnecting])
2022-09-29 16:38:10.317 DEBUG 2004 --- [reactor-http-epoll-4] r.n.r.DefaultPooledConnectionProvider    : [68eabf93, L:/11.0.0.110:45018 - R:fake.server.com/xx.xx.xx.xx:443] Releasing channel
2022-09-29 16:38:10.317 DEBUG 2004 --- [reactor-http-epoll-4] r.n.resources.PooledConnectionProvider   : [68eabf93, L:/11.0.0.110:45018 - R:fake.server.com/xx.xx.xx.xx:443] Channel cleaned, now: 0 active connections, 1 inactive connections and 0 pending acquire requests.
2022-09-29 16:38:10.317 DEBUG 2004 --- [reactor-http-epoll-4] reactor.netty.http.client.HttpClient     : [68eabf93, L:/11.0.0.110:45018 - R:fake.server.com/xx.xx.xx.xx:443] READ COMPLETE
2022-09-29 16:39:10.370 DEBUG 2004 --- [reactor-http-epoll-4] reactor.netty.http.client.HttpClient     : [68eabf93, L:/11.0.0.110:45018 - R:fake.server.com/xx.xx.xx.xx:443] USER_EVENT: SslCloseCompletionEvent(SUCCESS)
2022-09-29 16:39:10.371 DEBUG 2004 --- [reactor-http-epoll-4] reactor.netty.http.client.HttpClient     : [68eabf93, L:/11.0.0.110:45018 - R:fake.server.com/xx.xx.xx.xx:443] READ COMPLETE
2022-09-29 16:39:10.372 DEBUG 2004 --- [reactor-http-epoll-4] reactor.netty.http.client.HttpClient     : [68eabf93, L:/11.0.0.110:45018 - R:fake.server.com/xx.xx.xx.xx:443] READ COMPLETE
2022-09-29 16:39:10.372 DEBUG 2004 --- [reactor-http-epoll-4] reactor.netty.http.client.HttpClient     : [68eabf93, L:/11.0.0.110:45018 ! R:fake.server.com/xx.xx.xx.xx:443] INACTIVE
2022-09-29 16:39:10.372 DEBUG 2004 --- [reactor-http-epoll-4] r.n.r.DefaultPooledConnectionProvider    : [68eabf93, L:/11.0.0.110:45018 ! R:fake.server.com/xx.xx.xx.xx:443] onStateChange(PooledConnection{channel=[id: 0x68eabf93, L:/11.0.0.110:45018 ! R:fake.server.com/xx.xx.xx.xx:443]}, [disconnecting])
2022-09-29 16:39:10.372 DEBUG 2004 --- [reactor-http-epoll-4] reactor.netty.http.client.HttpClient     : [68eabf93, L:/11.0.0.110:45018 ! R:fake.server.com/xx.xx.xx.xx:443] UNREGISTERED

related tcpdump :
the server emits [FIN-ACK]

 1 2022-09-29 16:38:10.271330   11.0.0.110 → xx.xx.xx.xx  TCP 74 45018 → 443 [SYN] Seq=0 Win=62727 Len=0 MSS=8961 SACK_PERM=1 TSval=3967893981 TSecr=0 WS=128
 2 2022-09-29 16:38:10.271881  xx.xx.xx.xx → 11.0.0.110   TCP 74 443 → 45018 [SYN, ACK] Seq=0 Ack=1 Win=65160 Len=0 MSS=1460 SACK_PERM=1 TSval=3212175299 TSecr=3967893981 WS=128
 3 2022-09-29 16:38:10.271904   11.0.0.110 → xx.xx.xx.xx  TCP 66 45018 → 443 [ACK] Seq=1 Ack=1 Win=62848 Len=0 TSval=3967893981 TSecr=3212175299
 4 2022-09-29 16:38:10.284237   11.0.0.110 → xx.xx.xx.xx  TLSv1.2 317 Client Hello
 5 2022-09-29 16:38:10.284675  xx.xx.xx.xx → 11.0.0.110   TCP 66 443 → 45018 [ACK] Seq=1 Ack=252 Win=65024 Len=0 TSval=3212175312 TSecr=3967893994
 6 2022-09-29 16:38:10.285659  xx.xx.xx.xx → 11.0.0.110   TLSv1.2 156 Server Hello
 7 2022-09-29 16:38:10.285676   11.0.0.110 → xx.xx.xx.xx  TCP 66 45018 → 443 [ACK] Seq=252 Ack=91 Win=62848 Len=0 TSval=3967893995 TSecr=3212175313
 8 2022-09-29 16:38:10.285724  xx.xx.xx.xx → 11.0.0.110   TLSv1.2 72 Change Cipher Spec
 9 2022-09-29 16:38:10.285730   11.0.0.110 → xx.xx.xx.xx  TCP 66 45018 → 443 [ACK] Seq=252 Ack=97 Win=62848 Len=0 TSval=3967893995 TSecr=3212175313
10 2022-09-29 16:38:10.285821  xx.xx.xx.xx → 11.0.0.110   TLSv1.2 111 Encrypted Handshake Message
11 2022-09-29 16:38:10.285826   11.0.0.110 → xx.xx.xx.xx  TCP 66 45018 → 443 [ACK] Seq=252 Ack=142 Win=62848 Len=0 TSval=3967893995 TSecr=3212175313
12 2022-09-29 16:38:10.301879   11.0.0.110 → xx.xx.xx.xx  TLSv1.2 525 Change Cipher Spec, Encrypted Handshake Message, Application Data
13 2022-09-29 16:38:10.302281  xx.xx.xx.xx → 11.0.0.110   TCP 66 443 → 45018 [ACK] Seq=142 Ack=711 Win=64640 Len=0 TSval=3212175330 TSecr=3967894011
14 2022-09-29 16:38:10.306840  xx.xx.xx.xx → 11.0.0.110   TLSv1.2 508 Application Data
15 2022-09-29 16:38:10.306850   11.0.0.110 → xx.xx.xx.xx  TCP 66 45018 → 443 [ACK] Seq=711 Ack=584 Win=62464 Len=0 TSval=3967894016 TSecr=3212175334
16 2022-09-29 16:38:10.307126  xx.xx.xx.xx → 11.0.0.110   TLSv1.2 100 Application Data
17 2022-09-29 16:38:10.307132   11.0.0.110 → xx.xx.xx.xx  TCP 66 45018 → 443 [ACK] Seq=711 Ack=618 Win=62464 Len=0 TSval=3967894017 TSecr=3212175335
18 2022-09-29 16:39:10.369849  xx.xx.xx.xx → 11.0.0.110   TLSv1.2 97 Encrypted Alert
19 2022-09-29 16:39:10.369849  xx.xx.xx.xx → 11.0.0.110   TCP 66 443 → 45018 [FIN, ACK] Seq=649 Ack=711 Win=64640 Len=0 TSval=3212235397 TSecr=3967894017
20 2022-09-29 16:39:10.369871   11.0.0.110 → xx.xx.xx.xx  TCP 66 45018 → 443 [ACK] Seq=711 Ack=649 Win=62464 Len=0 TSval=3967954079 TSecr=3212235397
21 2022-09-29 16:39:10.371653   11.0.0.110 → xx.xx.xx.xx  TLSv1.2 97 Encrypted Alert
22 2022-09-29 16:39:10.372041  xx.xx.xx.xx → 11.0.0.110   TCP 54 443 → 45018 [RST] Seq=650 Win=0 Len=0

I was expecting the WebClient to close the connection since the connection was idle for more than 20 seconds.

@pderop
Copy link
Member

pderop commented Sep 29, 2022

I see in the logs that the evictionInterval = 0 (evictionInterval=PT0S), can you check and configure the ConnectionProvider evictInBackground to a positive value, like 5 seconds ?

@pderop
Copy link
Member

pderop commented Sep 30, 2022

hi @cyfax ,

After checking with the Netty team, we changed our mind, and the PR #2518 will be merged soon, which closes the connection when receiving a close_notify, this should resolve in particular your issue in case the close_notify is received while the connection is idle in the connection pool.

But as described in the PR, some racy condition where the close_notify is received while a request is being written or when the request has been flushed but the response is waited for, then in this case you will get a PrematureCloseException, which we can't avoid in this case.

Now, as said before, for the moment the work around suggested here should also address the issue. In your last message, evictionInterval is set to 0, that's probably why the timer was not triggered, so maybe you need to double check why evictionInterval=PT0S and set it to a positive value like 5 seconds.

thanks.

pderop added a commit that referenced this issue Sep 30, 2022
#2518)

When a TLS close_notify is received and when the close_notify ack is replied, then the Netty SslHandler just does not close the channel. Instead of that, in that case it fires a SslCloseCompletionEvent.SUCCESS event down the pipeline, and the closing of the channel is left to other handlers.

And since the TLS RFC states that the party receiving a close_notify MUST respond with a close_notify alert of its own and close down the connection immediately, let's do this in Reactor-Netty.

This patch won't avoid AbortedExceptions or PrematureCloseException exceptions in case a close_notify is being received while a request is being written, or while a response is waited for, but it may address some of the pain highlighted by #2498, #2499, and #2509; and may avoid SslClosedEngineException: SSLEngine closed already " exceptions.
@cyfax
Copy link
Author

cyfax commented Sep 30, 2022

hi @pderop

I made new tests with maxIdleTime and it is fine :
At 14:30:57.916 post is finished but SSL connection is still open and present in pool.
I made a second call between [20s(maxIdleTime)-60s (keepAliveTimeout)].
In this case HttpClient explicity closes the connection and a new one is created

2022-09-30 14:30:57.005 DEBUG 7738 --- [taskExecutor-1] r.n.resources.PooledConnectionProvider   : Creating a new [custom] client pool [PoolFactory{evictionInterval=PT0S, leasingStrategy=fifo, maxConnections=500, maxIdleTime=20000, maxLifeTime=-1, metricsEnabled=false, pendingAcquireMaxCount=1000, pendingAcquireTimeout=45000}] for [fake.server.com:443]
2022-09-30 14:30:57.247 DEBUG 7738 --- [reactor-http-epoll-3] r.n.resources.PooledConnectionProvider   : [a884dc9e] Created a new pooled channel, now: 0 active connections, 0 inactive connections and 0 pending acquire requests.
2022-09-30 14:30:57.298 DEBUG 7738 --- [reactor-http-epoll-3] reactor.netty.tcp.SslProvider            : [a884dc9e] SSL enabled using engine sun.security.ssl.SSLEngineImpl@382399b1 and SNI fake.server.com:443
2022-09-30 14:30:57.352 DEBUG 7738 --- [reactor-http-epoll-3] reactor.netty.transport.TransportConfig  : [a884dc9e] Initialized pipeline DefaultChannelPipeline{(reactor.left.sslHandler = io.netty.handler.ssl.SslHandler), (reactor.left.loggingHandler = reactor.netty.transport.logging.ReactorNettyLoggingHandler), (reactor.left.sslReader = reactor.netty.tcp.SslProvider$SslReadHandler), (reactor.left.httpCodec = io.netty.handler.codec.http.HttpClientCodec), (reactor.right.reactiveBridge = reactor.netty.channel.ChannelOperationsHandler)}
2022-09-30 14:30:57.358 DEBUG 7738 --- [reactor-http-epoll-3] reactor.netty.http.client.HttpClient     : [a884dc9e] REGISTERED
2022-09-30 14:30:57.566 DEBUG 7738 --- [reactor-http-epoll-3] r.netty.transport.TransportConnector     : [a884dc9e] Connecting to [fake.server.com/xx.xx.xx.xx:443].
2022-09-30 14:30:57.567 DEBUG 7738 --- [reactor-http-epoll-3] reactor.netty.http.client.HttpClient     : [a884dc9e] CONNECT: fake.server.com/xx.xx.xx.xx:443
2022-09-30 14:30:57.577 DEBUG 7738 --- [reactor-http-epoll-3] r.n.r.DefaultPooledConnectionProvider    : [a884dc9e, L:/11.0.0.110:59772 - R:fake.server.com/xx.xx.xx.xx:443] Registering pool release on close event for channel
2022-09-30 14:30:57.577 DEBUG 7738 --- [reactor-http-epoll-3] r.n.resources.PooledConnectionProvider   : [a884dc9e, L:/11.0.0.110:59772 - R:fake.server.com/xx.xx.xx.xx:443] Channel connected, now: 1 active connections, 0 inactive connections and 0 pending acquire requests.
2022-09-30 14:30:57.599 DEBUG 7738 --- [reactor-http-epoll-3] reactor.netty.http.client.HttpClient     : [a884dc9e, L:/11.0.0.110:59772 - R:fake.server.com/xx.xx.xx.xx:443] ACTIVE
2022-09-30 14:30:57.605 DEBUG 7738 --- [reactor-http-epoll-3] reactor.netty.http.client.HttpClient     : [a884dc9e, L:/11.0.0.110:59772 - R:fake.server.com/xx.xx.xx.xx:443] READ COMPLETE
2022-09-30 14:30:57.676 DEBUG 7738 --- [reactor-http-epoll-3] reactor.netty.http.client.HttpClient     : [a884dc9e, L:/11.0.0.110:59772 - R:fake.server.com/xx.xx.xx.xx:443] READ COMPLETE
2022-09-30 14:30:57.682 DEBUG 7738 --- [reactor-http-epoll-3] reactor.netty.http.client.HttpClient     : [a884dc9e, L:/11.0.0.110:59772 - R:fake.server.com/xx.xx.xx.xx:443] USER_EVENT: SslHandshakeCompletionEvent(SUCCESS)
2022-09-30 14:30:57.683 DEBUG 7738 --- [reactor-http-epoll-3] r.n.r.DefaultPooledConnectionProvider    : [a884dc9e, L:/11.0.0.110:59772 - R:fake.server.com/xx.xx.xx.xx:443] onStateChange(PooledConnection{channel=[id: 0xa884dc9e, L:/11.0.0.110:59772 - R:fake.server.com/xx.xx.xx.xx:443]}, [connected])
2022-09-30 14:30:57.709 DEBUG 7738 --- [reactor-http-epoll-3] r.n.r.DefaultPooledConnectionProvider    : [a884dc9e-1, L:/11.0.0.110:59772 - R:fake.server.com/xx.xx.xx.xx:443] onStateChange(GET{uri=/, connection=PooledConnection{channel=[id: 0xa884dc9e, L:/11.0.0.110:59772 - R:fake.server.com/xx.xx.xx.xx:443]}}, [configured])
2022-09-30 14:30:57.716 DEBUG 7738 --- [reactor-http-epoll-3] r.netty.http.client.HttpClientConnect    : [a884dc9e-1, L:/11.0.0.110:59772 - R:fake.server.com/xx.xx.xx.xx:443] Handler is being applied: {uri=https://fake.server.com/card/event, method=POST}
2022-09-30 14:30:57.720 DEBUG 7738 --- [reactor-http-epoll-3] r.n.r.DefaultPooledConnectionProvider    : [a884dc9e-1, L:/11.0.0.110:59772 - R:fake.server.com/xx.xx.xx.xx:443] onStateChange(POST{uri=/card/event, connection=PooledConnection{channel=[id: 0xa884dc9e, L:/11.0.0.110:59772 - R:fake.server.com/xx.xx.xx.xx:443]}}, [request_prepared])
2022-09-30 14:30:57.802 DEBUG 7738 --- [reactor-http-epoll-3] reactor.netty.http.client.HttpClient     : [a884dc9e-1, L:/11.0.0.110:59772 - R:fake.server.com/xx.xx.xx.xx:443] WRITE: 209B
2022-09-30 14:30:57.804 DEBUG 7738 --- [reactor-http-epoll-3] reactor.netty.http.client.HttpClient     : [a884dc9e-1, L:/11.0.0.110:59772 - R:fake.server.com/xx.xx.xx.xx:443] WRITE: 170B
2022-09-30 14:30:57.808 DEBUG 7738 --- [reactor-http-epoll-3] reactor.netty.http.client.HttpClient     : [a884dc9e-1, L:/11.0.0.110:59772 - R:fake.server.com/xx.xx.xx.xx:443] FLUSH
2022-09-30 14:30:57.811 DEBUG 7738 --- [reactor-http-epoll-3] r.n.r.DefaultPooledConnectionProvider    : [a884dc9e-1, L:/11.0.0.110:59772 - R:fake.server.com/xx.xx.xx.xx:443] onStateChange(POST{uri=/card/event, connection=PooledConnection{channel=[id: 0xa884dc9e, L:/11.0.0.110:59772 - R:fake.server.com/xx.xx.xx.xx:443]}}, [request_sent])
2022-09-30 14:30:57.822 DEBUG 7738 --- [reactor-http-epoll-3] reactor.netty.ReactorNetty               : [a884dc9e-1, L:/11.0.0.110:59772 - R:fake.server.com/xx.xx.xx.xx:443] Added encoder [reactor.left.responseTimeoutHandler] at the beginning of the user pipeline, full pipeline: [reactor.left.sslHandler, reactor.left.loggingHandler, reactor.left.httpCodec, reactor.left.responseTimeoutHandler, reactor.right.reactiveBridge, DefaultChannelPipeline$TailContext#0]
2022-09-30 14:30:57.829 DEBUG 7738 --- [reactor-http-epoll-3] reactor.netty.http.client.HttpClient     : [a884dc9e-1, L:/11.0.0.110:59772 - R:fake.server.com/xx.xx.xx.xx:443] READ COMPLETE
2022-09-30 14:30:57.830 DEBUG 7738 --- [reactor-http-epoll-3] reactor.netty.http.client.HttpClient     : [a884dc9e-1, L:/11.0.0.110:59772 - R:fake.server.com/xx.xx.xx.xx:443] READ: 413B
2022-09-30 14:30:57.836 DEBUG 7738 --- [reactor-http-epoll-3] r.n.http.client.HttpClientOperations     : [a884dc9e-1, L:/11.0.0.110:59772 - R:fake.server.com/xx.xx.xx.xx:443] Received response (auto-read:false) : [X-Content-Type-Options=nosniff, X-XSS-Protection=1; mode=block, Cache-Control=no-cache, no-store, max-age=0, must-revalidate, Pragma=no-cache, Expires=0, Strict-Transport-Security=max-age=31536000 ; includeSubDomains, X-Frame-Options=DENY, Content-Type=application/json;charset=UTF-8, Transfer-Encoding=chunked, Date=Fri, 30 Sep 2022 12:30:57 GMT]
2022-09-30 14:30:57.840 DEBUG 7738 --- [reactor-http-epoll-3] r.n.r.DefaultPooledConnectionProvider    : [a884dc9e-1, L:/11.0.0.110:59772 - R:fake.server.com/xx.xx.xx.xx:443] onStateChange(POST{uri=/card/event, connection=PooledConnection{channel=[id: 0xa884dc9e, L:/11.0.0.110:59772 - R:fake.server.com/xx.xx.xx.xx:443]}}, [response_received])
2022-09-30 14:30:57.886 DEBUG 7738 --- [reactor-http-epoll-3] reactor.netty.channel.FluxReceive        : [a884dc9e-1, L:/11.0.0.110:59772 - R:fake.server.com/xx.xx.xx.xx:443] FluxReceive{pending=0, cancelled=false, inboundDone=false, inboundError=null}: subscribing inbound receiver
2022-09-30 14:30:57.895 DEBUG 7738 --- [reactor-http-epoll-3] reactor.netty.http.client.HttpClient     : [a884dc9e-1, L:/11.0.0.110:59772 - R:fake.server.com/xx.xx.xx.xx:443] READ: 5B
2022-09-30 14:30:57.895 DEBUG 7738 --- [reactor-http-epoll-3] r.n.http.client.HttpClientOperations     : [a884dc9e-1, L:/11.0.0.110:59772 - R:fake.server.com/xx.xx.xx.xx:443] Received last HTTP packet
2022-09-30 14:30:57.896 TRACE 7738 --- [reactor-http-epoll-3] reactor.netty.channel.ChannelOperations  : [a884dc9e, L:/11.0.0.110:59772 - R:fake.server.com/xx.xx.xx.xx:443] Disposing ChannelOperation from a channel
2022-09-30 14:30:57.907 DEBUG 7738 --- [reactor-http-epoll-3] r.n.r.DefaultPooledConnectionProvider    : [a884dc9e, L:/11.0.0.110:59772 - R:fake.server.com/xx.xx.xx.xx:443] onStateChange(POST{uri=/card/event, connection=PooledConnection{channel=[id: 0xa884dc9e, L:/11.0.0.110:59772 - R:fake.server.com/xx.xx.xx.xx:443]}}, [response_completed])
2022-09-30 14:30:57.913 DEBUG 7738 --- [reactor-http-epoll-3] reactor.netty.ReactorNetty               : [a884dc9e, L:/11.0.0.110:59772 - R:fake.server.com/xx.xx.xx.xx:443] Removed handler: reactor.left.responseTimeoutHandler, pipeline: DefaultChannelPipeline{(reactor.left.sslHandler = io.netty.handler.ssl.SslHandler), (reactor.left.loggingHandler = reactor.netty.transport.logging.ReactorNettyLoggingHandler), (reactor.left.httpCodec = io.netty.handler.codec.http.HttpClientCodec), (reactor.right.reactiveBridge = reactor.netty.channel.ChannelOperationsHandler)}
2022-09-30 14:30:57.913 DEBUG 7738 --- [reactor-http-epoll-3] r.n.r.DefaultPooledConnectionProvider    : [a884dc9e, L:/11.0.0.110:59772 - R:fake.server.com/xx.xx.xx.xx:443] onStateChange(POST{uri=/card/event, connection=PooledConnection{channel=[id: 0xa884dc9e, L:/11.0.0.110:59772 - R:fake.server.com/xx.xx.xx.xx:443]}}, [disconnecting])
2022-09-30 14:30:57.913 DEBUG 7738 --- [reactor-http-epoll-3] r.n.r.DefaultPooledConnectionProvider    : [a884dc9e, L:/11.0.0.110:59772 - R:fake.server.com/xx.xx.xx.xx:443] Releasing channel
2022-09-30 14:30:57.916 DEBUG 7738 --- [reactor-http-epoll-3] r.n.resources.PooledConnectionProvider   : [a884dc9e, L:/11.0.0.110:59772 - R:fake.server.com/xx.xx.xx.xx:443] Channel cleaned, now: 0 active connections, 1 inactive connections and 0 pending acquire requests.
2022-09-30 14:30:57.916 DEBUG 7738 --- [reactor-http-epoll-3] reactor.netty.http.client.HttpClient     : [a884dc9e, L:/11.0.0.110:59772 - R:fake.server.com/xx.xx.xx.xx:443] READ COMPLETE


2022-09-30 14:31:28.171 DEBUG 7738 --- [reactor-http-epoll-3] reactor.netty.http.client.HttpClient     : [a884dc9e, L:/11.0.0.110:59772 - R:fake.server.com/xx.xx.xx.xx:443] CLOSE
2022-09-30 14:31:28.176 DEBUG 7738 --- [reactor-http-epoll-3] reactor.netty.http.client.HttpClient     : [a884dc9e, L:/11.0.0.110:59772 ! R:fake.server.com/xx.xx.xx.xx:443] USER_EVENT: SslCloseCompletionEvent(java.nio.channels.ClosedChannelException)
2022-09-30 14:31:28.179 DEBUG 7738 --- [reactor-http-epoll-4] r.n.resources.PooledConnectionProvider   : [529f87c9] Created a new pooled channel, now: 0 active connections, 0 inactive connections and 0 pending acquire requests.
2022-09-30 14:31:28.181 DEBUG 7738 --- [reactor-http-epoll-4] reactor.netty.tcp.SslProvider            : [529f87c9] SSL enabled using engine sun.security.ssl.SSLEngineImpl@3e1877f8 and SNI fake.server.com:443
2022-09-30 14:31:28.182 DEBUG 7738 --- [reactor-http-epoll-4] reactor.netty.transport.TransportConfig  : [529f87c9] Initialized pipeline DefaultChannelPipeline{(reactor.left.sslHandler = io.netty.handler.ssl.SslHandler), (reactor.left.loggingHandler = reactor.netty.transport.logging.ReactorNettyLoggingHandler), (reactor.left.sslReader = reactor.netty.tcp.SslProvider$SslReadHandler), (reactor.left.httpCodec = io.netty.handler.codec.http.HttpClientCodec), (reactor.right.reactiveBridge = reactor.netty.channel.ChannelOperationsHandler)}
2022-09-30 14:31:28.182 DEBUG 7738 --- [reactor-http-epoll-4] reactor.netty.http.client.HttpClient     : [529f87c9] REGISTERED
2022-09-30 14:31:28.188 DEBUG 7738 --- [reactor-http-epoll-4] r.netty.transport.TransportConnector     : [529f87c9] Connecting to [fake.server.com/xx.xx.xx.xx:443].
2022-09-30 14:31:28.189 DEBUG 7738 --- [reactor-http-epoll-4] reactor.netty.http.client.HttpClient     : [529f87c9] CONNECT: fake.server.com/xx.xx.xx.xx:443
2022-09-30 14:31:28.189 DEBUG 7738 --- [reactor-http-epoll-3] reactor.netty.http.client.HttpClient     : [a884dc9e, L:/11.0.0.110:59772 ! R:fake.server.com/xx.xx.xx.xx:443] INACTIVE
2022-09-30 14:31:28.189 DEBUG 7738 --- [reactor-http-epoll-3] r.n.r.DefaultPooledConnectionProvider    : [a884dc9e, L:/11.0.0.110:59772 ! R:fake.server.com/xx.xx.xx.xx:443] onStateChange(PooledConnection{channel=[id: 0xa884dc9e, L:/11.0.0.110:59772 ! R:fake.server.com/xx.xx.xx.xx:443]}, [disconnecting])
2022-09-30 14:31:28.192 DEBUG 7738 --- [reactor-http-epoll-3] reactor.netty.http.client.HttpClient     : [a884dc9e, L:/11.0.0.110:59772 ! R:fake.server.com/xx.xx.xx.xx:443] UNREGISTERED
2022-09-30 14:31:28.190 DEBUG 7738 --- [reactor-http-epoll-4] r.n.r.DefaultPooledConnectionProvider    : [529f87c9, L:/11.0.0.110:59780 - R:fake.server.com/xx.xx.xx.xx:443] Registering pool release on close event for channel
2022-09-30 14:31:28.197 DEBUG 7738 --- [reactor-http-epoll-4] r.n.resources.PooledConnectionProvider   : [529f87c9, L:/11.0.0.110:59780 - R:fake.server.com/xx.xx.xx.xx:443] Channel connected, now: 1 active connections, 0 inactive connections and 0 pending acquire requests.
2022-09-30 14:31:28.204 DEBUG 7738 --- [reactor-http-epoll-4] reactor.netty.http.client.HttpClient     : [529f87c9, L:/11.0.0.110:59780 - R:fake.server.com/xx.xx.xx.xx:443] ACTIVE
2022-09-30 14:31:28.213 DEBUG 7738 --- [reactor-http-epoll-4] reactor.netty.http.client.HttpClient     : [529f87c9, L:/11.0.0.110:59780 - R:fake.server.com/xx.xx.xx.xx:443] USER_EVENT: SslHandshakeCompletionEvent(SUCCESS)
2022-09-30 14:31:28.213 DEBUG 7738 --- [reactor-http-epoll-4] r.n.r.DefaultPooledConnectionProvider    : [529f87c9, L:/11.0.0.110:59780 - R:fake.server.com/xx.xx.xx.xx:443] onStateChange(PooledConnection{channel=[id: 0x529f87c9, L:/11.0.0.110:59780 - R:fake.server.com/xx.xx.xx.xx:443]}, [connected])
2022-09-30 14:31:28.214 DEBUG 7738 --- [reactor-http-epoll-4] r.n.r.DefaultPooledConnectionProvider    : [529f87c9-1, L:/11.0.0.110:59780 - R:fake.server.com/xx.xx.xx.xx:443] onStateChange(GET{uri=/, connection=PooledConnection{channel=[id: 0x529f87c9, L:/11.0.0.110:59780 - R:fake.server.com/xx.xx.xx.xx:443]}}, [configured])
2022-09-30 14:31:28.215 DEBUG 7738 --- [reactor-http-epoll-4] r.netty.http.client.HttpClientConnect    : [529f87c9-1, L:/11.0.0.110:59780 - R:fake.server.com/xx.xx.xx.xx:443] Handler is being applied: {uri=https://fake.server.com/card/event, method=POST}
2022-09-30 14:31:28.216 DEBUG 7738 --- [reactor-http-epoll-4] r.n.r.DefaultPooledConnectionProvider    : [529f87c9-1, L:/11.0.0.110:59780 - R:fake.server.com/xx.xx.xx.xx:443] onStateChange(POST{uri=/card/event, connection=PooledConnection{channel=[id: 0x529f87c9, L:/11.0.0.110:59780 - R:fake.server.com/xx.xx.xx.xx:443]}}, [request_prepared])
2022-09-30 14:31:28.220 DEBUG 7738 --- [reactor-http-epoll-4] reactor.netty.http.client.HttpClient     : [529f87c9-1, L:/11.0.0.110:59780 - R:fake.server.com/xx.xx.xx.xx:443] WRITE: 209B
2022-09-30 14:31:28.222 DEBUG 7738 --- [reactor-http-epoll-4] reactor.netty.http.client.HttpClient     : [529f87c9-1, L:/11.0.0.110:59780 - R:fake.server.com/xx.xx.xx.xx:443] WRITE: 170B
2022-09-30 14:31:28.222 DEBUG 7738 --- [reactor-http-epoll-4] reactor.netty.http.client.HttpClient     : [529f87c9-1, L:/11.0.0.110:59780 - R:fake.server.com/xx.xx.xx.xx:443] FLUSH
2022-09-30 14:31:28.223 DEBUG 7738 --- [reactor-http-epoll-4] r.n.r.DefaultPooledConnectionProvider    : [529f87c9-1, L:/11.0.0.110:59780 - R:fake.server.com/xx.xx.xx.xx:443] onStateChange(POST{uri=/card/event, connection=PooledConnection{channel=[id: 0x529f87c9, L:/11.0.0.110:59780 - R:fake.server.com/xx.xx.xx.xx:443]}}, [request_sent])
2022-09-30 14:31:28.224 DEBUG 7738 --- [reactor-http-epoll-4] reactor.netty.ReactorNetty               : [529f87c9-1, L:/11.0.0.110:59780 - R:fake.server.com/xx.xx.xx.xx:443] Added encoder [reactor.left.responseTimeoutHandler] at the beginning of the user pipeline, full pipeline: [reactor.left.sslHandler, reactor.left.loggingHandler, reactor.left.httpCodec, reactor.left.responseTimeoutHandler, reactor.right.reactiveBridge, DefaultChannelPipeline$TailContext#0]
2022-09-30 14:31:28.227 DEBUG 7738 --- [reactor-http-epoll-4] reactor.netty.http.client.HttpClient     : [529f87c9-1, L:/11.0.0.110:59780 - R:fake.server.com/xx.xx.xx.xx:443] READ COMPLETE
2022-09-30 14:31:28.227 DEBUG 7738 --- [reactor-http-epoll-4] reactor.netty.http.client.HttpClient     : [529f87c9-1, L:/11.0.0.110:59780 - R:fake.server.com/xx.xx.xx.xx:443] READ: 413B
2022-09-30 14:31:28.228 DEBUG 7738 --- [reactor-http-epoll-4] r.n.http.client.HttpClientOperations     : [529f87c9-1, L:/11.0.0.110:59780 - R:fake.server.com/xx.xx.xx.xx:443] Received response (auto-read:false) : [X-Content-Type-Options=nosniff, X-XSS-Protection=1; mode=block, Cache-Control=no-cache, no-store, max-age=0, must-revalidate, Pragma=no-cache, Expires=0, Strict-Transport-Security=max-age=31536000 ; includeSubDomains, X-Frame-Options=DENY, Content-Type=application/json;charset=UTF-8, Transfer-Encoding=chunked, Date=Fri, 30 Sep 2022 12:31:28 GMT]
2022-09-30 14:31:28.230 DEBUG 7738 --- [reactor-http-epoll-4] r.n.r.DefaultPooledConnectionProvider    : [529f87c9-1, L:/11.0.0.110:59780 - R:fake.server.com/xx.xx.xx.xx:443] onStateChange(POST{uri=/card/event, connection=PooledConnection{channel=[id: 0x529f87c9, L:/11.0.0.110:59780 - R:fake.server.com/xx.xx.xx.xx:443]}}, [response_received])
2022-09-30 14:31:28.230 DEBUG 7738 --- [reactor-http-epoll-4] reactor.netty.channel.FluxReceive        : [529f87c9-1, L:/11.0.0.110:59780 - R:fake.server.com/xx.xx.xx.xx:443] FluxReceive{pending=0, cancelled=false, inboundDone=false, inboundError=null}: subscribing inbound receiver
2022-09-30 14:31:28.231 DEBUG 7738 --- [reactor-http-epoll-4] reactor.netty.http.client.HttpClient     : [529f87c9-1, L:/11.0.0.110:59780 - R:fake.server.com/xx.xx.xx.xx:443] READ: 5B
2022-09-30 14:31:28.231 DEBUG 7738 --- [reactor-http-epoll-4] r.n.http.client.HttpClientOperations     : [529f87c9-1, L:/11.0.0.110:59780 - R:fake.server.com/xx.xx.xx.xx:443] Received last HTTP packet
2022-09-30 14:31:28.235 TRACE 7738 --- [reactor-http-epoll-4] reactor.netty.channel.ChannelOperations  : [529f87c9, L:/11.0.0.110:59780 - R:fake.server.com/xx.xx.xx.xx:443] Disposing ChannelOperation from a channel
2022-09-30 14:31:28.241 DEBUG 7738 --- [reactor-http-epoll-4] r.n.r.DefaultPooledConnectionProvider    : [529f87c9, L:/11.0.0.110:59780 - R:fake.server.com/xx.xx.xx.xx:443] onStateChange(POST{uri=/card/event, connection=PooledConnection{channel=[id: 0x529f87c9, L:/11.0.0.110:59780 - R:fake.server.com/xx.xx.xx.xx:443]}}, [response_completed])
2022-09-30 14:31:28.241 DEBUG 7738 --- [reactor-http-epoll-4] reactor.netty.ReactorNetty               : [529f87c9, L:/11.0.0.110:59780 - R:fake.server.com/xx.xx.xx.xx:443] Removed handler: reactor.left.responseTimeoutHandler, pipeline: DefaultChannelPipeline{(reactor.left.sslHandler = io.netty.handler.ssl.SslHandler), (reactor.left.loggingHandler = reactor.netty.transport.logging.ReactorNettyLoggingHandler), (reactor.left.httpCodec = io.netty.handler.codec.http.HttpClientCodec), (reactor.right.reactiveBridge = reactor.netty.channel.ChannelOperationsHandler)}
2022-09-30 14:31:28.241 DEBUG 7738 --- [reactor-http-epoll-4] r.n.r.DefaultPooledConnectionProvider    : [529f87c9, L:/11.0.0.110:59780 - R:fake.server.com/xx.xx.xx.xx:443] onStateChange(POST{uri=/card/event, connection=PooledConnection{channel=[id: 0x529f87c9, L:/11.0.0.110:59780 - R:fake.server.com/xx.xx.xx.xx:443]}}, [disconnecting])
2022-09-30 14:31:28.241 DEBUG 7738 --- [reactor-http-epoll-4] r.n.r.DefaultPooledConnectionProvider    : [529f87c9, L:/11.0.0.110:59780 - R:fake.server.com/xx.xx.xx.xx:443] Releasing channel
2022-09-30 14:31:28.241 DEBUG 7738 --- [reactor-http-epoll-4] r.n.resources.PooledConnectionProvider   : [529f87c9, L:/11.0.0.110:59780 - R:fake.server.com/xx.xx.xx.xx:443] Channel cleaned, now: 0 active connections, 1 inactive connections and 0 pending acquire requests.
2022-09-30 14:31:28.241 DEBUG 7738 --- [reactor-http-epoll-4] reactor.netty.http.client.HttpClient     : [529f87c9, L:/11.0.0.110:59780 - R:fake.server.com/xx.xx.xx.xx:443] READ COMPLETE
2022-09-30 14:32:28.294 DEBUG 7738 --- [reactor-http-epoll-4] reactor.netty.http.client.HttpClient     : [529f87c9, L:/11.0.0.110:59780 - R:fake.server.com/xx.xx.xx.xx:443] USER_EVENT: SslCloseCompletionEvent(SUCCESS)
2022-09-30 14:32:28.296 DEBUG 7738 --- [reactor-http-epoll-4] reactor.netty.http.client.HttpClient     : [529f87c9, L:/11.0.0.110:59780 - R:fake.server.com/xx.xx.xx.xx:443] READ COMPLETE
2022-09-30 14:32:28.297 DEBUG 7738 --- [reactor-http-epoll-4] reactor.netty.http.client.HttpClient     : [529f87c9, L:/11.0.0.110:59780 - R:fake.server.com/xx.xx.xx.xx:443] READ COMPLETE
2022-09-30 14:32:28.298 DEBUG 7738 --- [reactor-http-epoll-4] reactor.netty.http.client.HttpClient     : [529f87c9, L:/11.0.0.110:59780 ! R:fake.server.com/xx.xx.xx.xx:443] INACTIVE
2022-09-30 14:32:28.298 DEBUG 7738 --- [reactor-http-epoll-4] r.n.r.DefaultPooledConnectionProvider    : [529f87c9, L:/11.0.0.110:59780 ! R:fake.server.com/xx.xx.xx.xx:443] onStateChange(PooledConnection{channel=[id: 0x529f87c9, L:/11.0.0.110:59780 ! R:fake.server.com/xx.xx.xx.xx:443]}, [disconnecting])
2022-09-30 14:32:28.299 DEBUG 7738 --- [reactor-http-epoll-4] reactor.netty.http.client.HttpClient     : [529f87c9, L:/11.0.0.110:59780 ! R:fake.server.com/xx.xx.xx.xx:443] UNREGISTERED

tcpdump :

 1 2022-09-30 14:30:57.567514   11.0.0.110 → xx.xx.xx.xx  TCP 74 59772 → 443 [SYN] Seq=0 Win=62727 Len=0 MSS=8961 SACK_PERM=1 TSval=4046661277 TSecr=0 WS=128
 2 2022-09-30 14:30:57.567999  xx.xx.xx.xx → 11.0.0.110   TCP 74 443 → 59772 [SYN, ACK] Seq=0 Ack=1 Win=65160 Len=0 MSS=1460 SACK_PERM=1 TSval=3290942595 TSecr=4046661277 WS=128
 3 2022-09-30 14:30:57.568019   11.0.0.110 → xx.xx.xx.xx  TCP 66 59772 → 443 [ACK] Seq=1 Ack=1 Win=62848 Len=0 TSval=4046661278 TSecr=3290942595
 4 2022-09-30 14:30:57.598830   11.0.0.110 → xx.xx.xx.xx  TLSv1.2 285 Client Hello
 5 2022-09-30 14:30:57.599319  xx.xx.xx.xx → 11.0.0.110   TCP 66 443 → 59772 [ACK] Seq=1 Ack=220 Win=65024 Len=0 TSval=3290942627 TSecr=4046661308
 6 2022-09-30 14:30:57.603997  xx.xx.xx.xx → 11.0.0.110   TLSv1.2 4427 Server Hello, Certificate, Server Key Exchange, Server Hello Done
 7 2022-09-30 14:30:57.604010   11.0.0.110 → xx.xx.xx.xx  TCP 66 59772 → 443 [ACK] Seq=220 Ack=4362 Win=58496 Len=0 TSval=4046661313 TSecr=3290942631
 8 2022-09-30 14:30:57.672758   11.0.0.110 → xx.xx.xx.xx  TLSv1.2 192 Client Key Exchange, Change Cipher Spec, Encrypted Handshake Message
 9 2022-09-30 14:30:57.673340  xx.xx.xx.xx → 11.0.0.110   TCP 66 443 → 59772 [ACK] Seq=4362 Ack=346 Win=65024 Len=0 TSval=3290942701 TSecr=4046661382
10 2022-09-30 14:30:57.676337  xx.xx.xx.xx → 11.0.0.110   TLSv1.2 72 Change Cipher Spec
11 2022-09-30 14:30:57.676346   11.0.0.110 → xx.xx.xx.xx  TCP 66 59772 → 443 [ACK] Seq=346 Ack=4368 Win=58496 Len=0 TSval=4046661386 TSecr=3290942704
12 2022-09-30 14:30:57.676399  xx.xx.xx.xx → 11.0.0.110   TLSv1.2 111 Encrypted Handshake Message
13 2022-09-30 14:30:57.676405   11.0.0.110 → xx.xx.xx.xx  TCP 66 59772 → 443 [ACK] Seq=346 Ack=4413 Win=58496 Len=0 TSval=4046661386 TSecr=3290942704
14 2022-09-30 14:30:57.810351   11.0.0.110 → xx.xx.xx.xx  TLSv1.2 474 Application Data
15 2022-09-30 14:30:57.810815  xx.xx.xx.xx → 11.0.0.110   TCP 66 443 → 59772 [ACK] Seq=4413 Ack=754 Win=64640 Len=0 TSval=3290942838 TSecr=4046661520
16 2022-09-30 14:30:57.818516  xx.xx.xx.xx → 11.0.0.110   TLSv1.2 508 Application Data
17 2022-09-30 14:30:57.818534   11.0.0.110 → xx.xx.xx.xx  TCP 66 59772 → 443 [ACK] Seq=754 Ack=4855 Win=58112 Len=0 TSval=4046661528 TSecr=3290942846
18 2022-09-30 14:30:57.818803  xx.xx.xx.xx → 11.0.0.110   TLSv1.2 100 Application Data
19 2022-09-30 14:30:57.818808   11.0.0.110 → xx.xx.xx.xx  TCP 66 59772 → 443 [ACK] Seq=754 Ack=4889 Win=58112 Len=0 TSval=4046661528 TSecr=3290942846

20 2022-09-30 14:31:28.173529   11.0.0.110 → xx.xx.xx.xx  TLSv1.2 97 Encrypted Alert
21 2022-09-30 14:31:28.174402  xx.xx.xx.xx → 11.0.0.110   TLSv1.2 97 Encrypted Alert
22 2022-09-30 14:31:28.174416   11.0.0.110 → xx.xx.xx.xx  TCP 66 59772 → 443 [ACK] Seq=785 Ack=4920 Win=58112 Len=0 TSval=4046691884 TSecr=3290973202
23 2022-09-30 14:31:28.174430  xx.xx.xx.xx → 11.0.0.110   TCP 66 443 → 59772 [FIN, ACK] Seq=4920 Ack=785 Win=64640 Len=0 TSval=3290973202 TSecr=4046691883
24 2022-09-30 14:31:28.175680   11.0.0.110 → xx.xx.xx.xx  TCP 66 59772 → 443 [RST, ACK] Seq=785 Ack=4921 Win=58112 Len=0 TSval=4046691885 TSecr=3290973202
25 2022-09-30 14:31:28.189406   11.0.0.110 → xx.xx.xx.xx  TCP 74 59780 → 443 [SYN] Seq=0 Win=62727 Len=0 MSS=8961 SACK_PERM=1 TSval=4046691899 TSecr=0 WS=128
26 2022-09-30 14:31:28.189810  xx.xx.xx.xx → 11.0.0.110   TCP 74 443 → 59780 [SYN, ACK] Seq=0 Ack=1 Win=65160 Len=0 MSS=1460 SACK_PERM=1 TSval=3290973217 TSecr=4046691899 WS=128
27 2022-09-30 14:31:28.189831   11.0.0.110 → xx.xx.xx.xx  TCP 66 59780 → 443 [ACK] Seq=1 Ack=1 Win=62848 Len=0 TSval=4046691899 TSecr=3290973217
28 2022-09-30 14:31:28.204131   11.0.0.110 → xx.xx.xx.xx  TLSv1.2 317 Client Hello
29 2022-09-30 14:31:28.204530  xx.xx.xx.xx → 11.0.0.110   TCP 66 443 → 59780 [ACK] Seq=1 Ack=252 Win=65024 Len=0 TSval=3290973232 TSecr=4046691914
30 2022-09-30 14:31:28.205431  xx.xx.xx.xx → 11.0.0.110   TLSv1.2 156 Server Hello
31 2022-09-30 14:31:28.205431  xx.xx.xx.xx → 11.0.0.110   TLSv1.2 72 Change Cipher Spec
32 2022-09-30 14:31:28.205446   11.0.0.110 → xx.xx.xx.xx  TCP 66 59780 → 443 [ACK] Seq=252 Ack=91 Win=62848 Len=0 TSval=4046691915 TSecr=3290973233
33 2022-09-30 14:31:28.205459   11.0.0.110 → xx.xx.xx.xx  TCP 66 59780 → 443 [ACK] Seq=252 Ack=97 Win=62848 Len=0 TSval=4046691915 TSecr=3290973233
34 2022-09-30 14:31:28.205545  xx.xx.xx.xx → 11.0.0.110   TLSv1.2 111 Encrypted Handshake Message
35 2022-09-30 14:31:28.205551   11.0.0.110 → xx.xx.xx.xx  TCP 66 59780 → 443 [ACK] Seq=252 Ack=142 Win=62848 Len=0 TSval=4046691915 TSecr=3290973233
36 2022-09-30 14:31:28.223376   11.0.0.110 → xx.xx.xx.xx  TLSv1.2 525 Change Cipher Spec, Encrypted Handshake Message, Application Data
37 2022-09-30 14:31:28.223869  xx.xx.xx.xx → 11.0.0.110   TCP 66 443 → 59780 [ACK] Seq=142 Ack=711 Win=64640 Len=0 TSval=3290973251 TSecr=4046691933
38 2022-09-30 14:31:28.226640  xx.xx.xx.xx → 11.0.0.110   TLSv1.2 508 Application Data
39 2022-09-30 14:31:28.226650   11.0.0.110 → xx.xx.xx.xx  TCP 66 59780 → 443 [ACK] Seq=711 Ack=584 Win=62464 Len=0 TSval=4046691936 TSecr=3290973254
40 2022-09-30 14:31:28.226912  xx.xx.xx.xx → 11.0.0.110   TLSv1.2 100 Application Data
41 2022-09-30 14:31:28.226918   11.0.0.110 → xx.xx.xx.xx  TCP 66 59780 → 443 [ACK] Seq=711 Ack=618 Win=62464 Len=0 TSval=4046691936 TSecr=3290973254

@cyfax
Copy link
Author

cyfax commented Sep 30, 2022

hi @cyfax ,

After checking with the Netty team, we changed our mind, and the PR #2518 will be merged soon, which closes the connection when receiving a close_notify, this should resolve in particular your issue in case the close_notify is received while the connection is idle in the connection pool.

But as described in the PR, some racy condition where the close_notify is received while a request is being written or when the request has been flushed but the response is waited for, then in this case you will get a PrematureCloseException, which we can't avoid in this case.

Now, as said before, for the moment the work around suggested here should also address the issue. In your last message, evictionInterval is set to 0, that's probably why the timer was not triggered, so maybe you need to double check why evictionInterval=PT0S and set it to a positive value like 5 seconds.

thanks.

Glad to know my suggestion and proposed fix was quite good :)

May I ask you when this fix is scheduled to be released ?
Do not bother I found it :
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type/bug A general bug
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants