From: Stefan Eissing Date: Thu, 17 Oct 2024 11:53:06 +0000 (+0200) Subject: openssl: improve retries on shutdown X-Git-Tag: curl-8_11_0~126 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=b42eb27c1f6f235249ee6c001fc5c28d28d3a064;p=thirdparty%2Fcurl.git openssl: improve retries on shutdown Once SSL_shutdown() has been called, OpenSSL does not really seem to like it when it is called again and the other side has some finally data to deliver. Instead SSL_read() needs to be used solely, once the close notify has been sent from curl's side. Closes #15321 --- diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 43c478eca2..43dcce06b2 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -1935,8 +1935,9 @@ static CURLcode ossl_shutdown(struct Curl_cfilter *cf, /* SSL should now have started the shutdown from our side. Since it * was not complete, we are lacking the close notify from the server. */ - if(send_shutdown) { + if(send_shutdown && !(SSL_get_shutdown(octx->ssl) & SSL_SENT_SHUTDOWN)) { ERR_clear_error(); + CURL_TRC_CF(data, cf, "send SSL close notify"); if(SSL_shutdown(octx->ssl) == 1) { CURL_TRC_CF(data, cf, "SSL shutdown finished"); *done = TRUE; @@ -1961,7 +1962,10 @@ static CURLcode ossl_shutdown(struct Curl_cfilter *cf, err = SSL_get_error(octx->ssl, nread); switch(err) { case SSL_ERROR_ZERO_RETURN: /* no more data */ - CURL_TRC_CF(data, cf, "SSL shutdown not received, but closed"); + if(SSL_shutdown(octx->ssl) == 1) + CURL_TRC_CF(data, cf, "SSL shutdown finished"); + else + CURL_TRC_CF(data, cf, "SSL shutdown not received, but closed"); *done = TRUE; break; case SSL_ERROR_NONE: /* just did not get anything */ diff --git a/tests/http/test_19_shutdown.py b/tests/http/test_19_shutdown.py index 5e82121ee2..bbb67d360e 100644 --- a/tests/http/test_19_shutdown.py +++ b/tests/http/test_19_shutdown.py @@ -73,7 +73,7 @@ class TestShutdown: pytest.skip('only works for curl debug builds') curl = CurlClient(env=env, run_env={ 'CURL_GRACEFUL_SHUTDOWN': '2000', - 'CURL_DEBUG': 'ssl' + 'CURL_DEBUG': 'ssl,tcp' }) url = f'https://{env.authority_for(env.domain1, proto)}/data.json?[0-1]' r = curl.http_download(urls=[url], alpn_proto=proto, with_tcpdump=True, extra_args=[