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.

Closes #17884
This commit is contained in:
Stefan Eissing 2025-07-10 12:16:40 +02:00 committed by Daniel Stenberg
parent 2ec54556d4
commit b453a447ce
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
8 changed files with 58 additions and 42 deletions

View File

@ -972,12 +972,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,

View File

@ -535,6 +535,22 @@ static void multi_done_locked(struct connectdata *conn,
void *userdata)
{
struct multi_done_ctx *mdctx = userdata;
#ifndef CURL_DISABLE_VERBOSE_STRINGS
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;
int port =
#ifndef CURL_DISABLE_PROXY
conn->bits.httpproxy ? conn->http_proxy.port :
#endif
conn->bits.conn_to_port ? conn->conn_to_port :
conn->remote_port;
#endif
Curl_detach_connection(data);
@ -580,30 +596,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. */

View File

@ -83,10 +83,10 @@ Accept: */*
^Host:.*
</strip>
<file name="%LOGDIR/stderr%TESTNUMBER" mode="text">
* 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
</file>
<stripfile>
$_ = '' if(($_ !~ /left intact/) && ($_ !~ /Closing connection/))

View File

@ -83,10 +83,10 @@ Accept: */*
^Host:.*
</strip>
<file name="%LOGDIR/stderr%TESTNUMBER" mode="text">
* 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
</file>
<stripfile>
$_ = '' if(($_ !~ /left intact/) && ($_ !~ /Closing connection/))

View File

@ -55,11 +55,11 @@ Accept: */*
</protocol>
<file name="%LOGDIR/stderr%TESTNUMBER" mode="text">
== 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
</file>
<stripfile>
$_ = '' if(($_ !~ /left intact/) && ($_ !~ /(closing|shutting down) connection #\d+/))

View File

@ -96,10 +96,10 @@ Via: 2 nghttpx
^Host:.*
</strip>
<file name="%LOGDIR/stderr%TESTNUMBER" mode="text">
* 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
</file>
<stripfile>
$_ = '' if(($_ !~ /left intact/) && ($_ !~ /Closing connection/))

View File

@ -96,10 +96,10 @@ Via: 2 nghttpx
^Host:.*
</strip>
<file name="%LOGDIR/stderr%TESTNUMBER" mode="text">
* 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
</file>
<stripfile>
$_ = '' if(($_ !~ /left intact/) && ($_ !~ /Closing connection/))

View File

@ -91,10 +91,10 @@ Via: 3 nghttpx
^Host:.*
</strip>
<file name="%LOGDIR/stderr%TESTNUMBER" mode="text">
== 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
</file>
<stripfile>
$_ = '' if(($_ !~ /left intact/) && ($_ !~ /Closing connection/))