From 714ca122443e64bdd91768e18a0676d7bac0591f Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 10 Jul 2025 12:16:40 +0200 Subject: [PATCH] connection: terminate after goaway When a multiplex connection (h2/h3) is shutdown by the server, the reported number of parallel transfers allowed drops to 0. Determine that when the last transfer is done and terminate the connection instead of keeping it in the cache. We detect the drop to 0 also when we try to reuse such a connection, but if we know this at the time the last transfer is done, we better terminate it right away. Have a consistent trace logging to this with the connections current hostname and port. Adjust test expectations to carry port numbers. --- lib/cfilters.c | 7 +++++-- lib/multi.c | 36 ++++++++++++++++++++---------------- tests/data/test1506 | 8 ++++---- tests/data/test1510 | 8 ++++---- tests/data/test1542 | 8 ++++---- tests/data/test2402 | 8 ++++---- tests/data/test2404 | 8 ++++---- tests/data/test2502 | 8 ++++---- 8 files changed, 49 insertions(+), 42 deletions(-) diff --git a/lib/cfilters.c b/lib/cfilters.c index 4c0f48606f..012039fce3 100644 --- a/lib/cfilters.c +++ b/lib/cfilters.c @@ -956,12 +956,15 @@ size_t Curl_conn_get_max_concurrent(struct Curl_easy *data, int sockindex) { CURLcode result; - int n = 0; + int n = -1; struct Curl_cfilter *cf = conn->cfilter[sockindex]; result = cf ? cf->cft->query(cf, data, CF_QUERY_MAX_CONCURRENT, &n, NULL) : CURLE_UNKNOWN_OPTION; - return (result || n <= 0) ? 1 : (size_t)n; + /* If no filter answered the query, the default is a non-multiplexed + * connection with limit 1. Otherwise, the the query may return 0 + * for connections that are in shutdown, e.g. server HTTP/2 GOAWAY. */ + return (result || n < 0) ? 1 : (size_t)n; } int Curl_conn_get_stream_error(struct Curl_easy *data, diff --git a/lib/multi.c b/lib/multi.c index fe2cca4039..51777b5cef 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -539,6 +539,13 @@ static void multi_done_locked(struct connectdata *conn, void *userdata) { struct multi_done_ctx *mdctx = userdata; +#ifndef CURL_DISABLE_VERBOSE_STRINGS + const char *host = NULL; + int port = 0; + + if(Curl_trc_is_verbose(data)) + Curl_conn_get_current_host(data, FIRSTSOCKET, &host, &port); +#endif Curl_detach_connection(data); @@ -584,30 +591,27 @@ static void multi_done_locked(struct connectdata *conn, #endif ) || conn->bits.close || (mdctx->premature && !Curl_conn_is_multiplex(conn, FIRSTSOCKET))) { - CURL_TRC_M(data, "multi_done, not reusing connection=%" - FMT_OFF_T ", forbid=%d" - ", close=%d, premature=%d, conn_multiplex=%d", - conn->connection_id, data->set.reuse_forbid, - conn->bits.close, mdctx->premature, - Curl_conn_is_multiplex(conn, FIRSTSOCKET)); + CURL_TRC_M(data, "multi_done, terminating conn #%" FMT_OFF_T " to %s:%d, " + "forbid=%d, close=%d, premature=%d, conn_multiplex=%d", + conn->connection_id, host, port, data->set.reuse_forbid, + conn->bits.close, mdctx->premature, + Curl_conn_is_multiplex(conn, FIRSTSOCKET)); connclose(conn, "disconnecting"); Curl_conn_terminate(data, conn, mdctx->premature); } + else if(!Curl_conn_get_max_concurrent(data, conn, FIRSTSOCKET)) { + CURL_TRC_M(data, "multi_done, conn #%" FMT_OFF_T " to %s:%d was shutdown" + " by server, not reusing", conn->connection_id, host, port); + connclose(conn, "server shutdown"); + Curl_conn_terminate(data, conn, mdctx->premature); + } else { /* the connection is no longer in use by any transfer */ if(Curl_cpool_conn_now_idle(data, conn)) { /* connection kept in the cpool */ - const char *host = -#ifndef CURL_DISABLE_PROXY - conn->bits.socksproxy ? - conn->socks_proxy.host.dispname : - conn->bits.httpproxy ? conn->http_proxy.host.dispname : -#endif - conn->bits.conn_to_host ? conn->conn_to_host.dispname : - conn->host.dispname; data->state.lastconnect_id = conn->connection_id; - infof(data, "Connection #%" FMT_OFF_T " to host %s left intact", - conn->connection_id, host); + infof(data, "Connection #%" FMT_OFF_T " to host %s:%d left intact", + conn->connection_id, host, port); } else { /* connection was removed from the cpool and destroyed. */ diff --git a/tests/data/test1506 b/tests/data/test1506 index 0a62c0c2a6..f1da087704 100644 --- a/tests/data/test1506 +++ b/tests/data/test1506 @@ -83,10 +83,10 @@ Accept: */* ^Host:.* -* Connection #0 to host server1.example.com left intact -* Connection #1 to host server2.example.com left intact -* Connection #2 to host server3.example.com left intact -* Connection #3 to host server4.example.com left intact +* Connection #0 to host server1.example.com:%HTTPPORT left intact +* Connection #1 to host server2.example.com:%HTTPPORT left intact +* Connection #2 to host server3.example.com:%HTTPPORT left intact +* Connection #3 to host server4.example.com:%HTTPPORT left intact $_ = '' if (($_ !~ /left intact/) && ($_ !~ /Closing connection/)) diff --git a/tests/data/test1510 b/tests/data/test1510 index d2316c0112..af8115efb4 100644 --- a/tests/data/test1510 +++ b/tests/data/test1510 @@ -83,10 +83,10 @@ Accept: */* ^Host:.* -* Connection #0 to host server1.example.com left intact -* Connection #1 to host server2.example.com left intact -* Connection #2 to host server3.example.com left intact -* Connection #3 to host server4.example.com left intact +* Connection #0 to host server1.example.com:%HTTPPORT left intact +* Connection #1 to host server2.example.com:%HTTPPORT left intact +* Connection #2 to host server3.example.com:%HTTPPORT left intact +* Connection #3 to host server4.example.com:%HTTPPORT left intact $_ = '' if (($_ !~ /left intact/) && ($_ !~ /Closing connection/)) diff --git a/tests/data/test1542 b/tests/data/test1542 index 0454d76dde..8f7e24b221 100644 --- a/tests/data/test1542 +++ b/tests/data/test1542 @@ -55,11 +55,11 @@ Accept: */* -== Info: Connection #0 to host %HOSTIP left intact -== Info: Connection #0 to host %HOSTIP left intact -== Info: Connection #0 to host %HOSTIP left intact +== Info: Connection #0 to host %HOSTIP:%HTTPPORT left intact +== Info: Connection #0 to host %HOSTIP:%HTTPPORT left intact +== Info: Connection #0 to host %HOSTIP:%HTTPPORT left intact == Info: shutting down connection #0 -== Info: Connection #1 to host %HOSTIP left intact +== Info: Connection #1 to host %HOSTIP:%HTTPPORT left intact $_ = '' if (($_ !~ /left intact/) && ($_ !~ /(closing|shutting down) connection #\d+/)) diff --git a/tests/data/test2402 b/tests/data/test2402 index 48a485624e..1f03e5f25d 100644 --- a/tests/data/test2402 +++ b/tests/data/test2402 @@ -96,10 +96,10 @@ Via: 2 nghttpx ^Host:.* -* Connection #0 to host localhost left intact -* Connection #0 to host localhost left intact -* Connection #0 to host localhost left intact -* Connection #0 to host localhost left intact +* Connection #0 to host localhost:%HTTP2TLSPORT left intact +* Connection #0 to host localhost:%HTTP2TLSPORT left intact +* Connection #0 to host localhost:%HTTP2TLSPORT left intact +* Connection #0 to host localhost:%HTTP2TLSPORT left intact $_ = '' if (($_ !~ /left intact/) && ($_ !~ /Closing connection/)) diff --git a/tests/data/test2404 b/tests/data/test2404 index 89461a4688..f20d152879 100644 --- a/tests/data/test2404 +++ b/tests/data/test2404 @@ -96,10 +96,10 @@ Via: 2 nghttpx ^Host:.* -* Connection #0 to host localhost left intact -* Connection #0 to host localhost left intact -* Connection #0 to host localhost left intact -* Connection #0 to host localhost left intact +* Connection #0 to host localhost:%HTTP2TLSPORT left intact +* Connection #0 to host localhost:%HTTP2TLSPORT left intact +* Connection #0 to host localhost:%HTTP2TLSPORT left intact +* Connection #0 to host localhost:%HTTP2TLSPORT left intact $_ = '' if (($_ !~ /left intact/) && ($_ !~ /Closing connection/)) diff --git a/tests/data/test2502 b/tests/data/test2502 index e53f880469..5dc503abf0 100644 --- a/tests/data/test2502 +++ b/tests/data/test2502 @@ -91,10 +91,10 @@ Via: 3 nghttpx ^Host:.* -== Info: Connection #0 to host localhost left intact -== Info: Connection #0 to host localhost left intact -== Info: Connection #0 to host localhost left intact -== Info: Connection #0 to host localhost left intact +== Info: Connection #0 to host localhost:%HTTP3PORT left intact +== Info: Connection #0 to host localhost:%HTTP3PORT left intact +== Info: Connection #0 to host localhost:%HTTP3PORT left intact +== Info: Connection #0 to host localhost:%HTTP3PORT left intact $_ = '' if (($_ !~ /left intact/) && ($_ !~ /Closing connection/))