openssl: improve ssl shutdown handling

- If SSL shutdown is not finished then make an additional call to
  SSL_read to gather additional tracing.

- Fix http2 and h2-proxy filters to forward do_close() calls to the next
  filter.

For example h2 and SSL shutdown before and after this change:

Before:

Curl_conn_close -> cf_hc_close -> Curl_conn_cf_discard_chain ->
ssl_cf_destroy

After:

Curl_conn_close -> cf_hc_close -> cf_h2_close -> cf_setup_close ->
ssl_cf_close

Note that currently the tracing does not show output on the connection
closure handle. Refer to discussion in #11878.

Ref: https://github.com/curl/curl/discussions/11878

Closes https://github.com/curl/curl/pull/11858
This commit is contained in:
Stefan Eissing 2023-09-15 09:12:52 +02:00 committed by Jay Satiro
parent 579f09343d
commit 34cdcb9b96
4 changed files with 40 additions and 5 deletions

View File

@ -1160,6 +1160,8 @@ static void cf_h2_proxy_close(struct Curl_cfilter *cf, struct Curl_easy *data)
cf_h2_proxy_ctx_clear(ctx);
CF_DATA_RESTORE(cf, save);
}
if(cf->next)
cf->next->cft->do_close(cf->next, data);
}
static void cf_h2_proxy_destroy(struct Curl_cfilter *cf,

View File

@ -2425,6 +2425,8 @@ static void cf_h2_close(struct Curl_cfilter *cf, struct Curl_easy *data)
cf_h2_ctx_clear(ctx);
CF_DATA_RESTORE(cf, save);
}
if(cf->next)
cf->next->cft->do_close(cf->next, data);
}
static void cf_h2_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)

View File

@ -1876,15 +1876,45 @@ static void ossl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
if(backend->handle) {
if(cf->next && cf->next->connected) {
char buf[32];
char buf[1024];
int nread, err;
long sslerr;
/* Maybe the server has already sent a close notify alert.
Read it to avoid an RST on the TCP connection. */
(void)SSL_read(backend->handle, buf, (int)sizeof(buf));
(void)SSL_shutdown(backend->handle);
ERR_clear_error();
if(SSL_shutdown(backend->handle) == 1) {
CURL_TRC_CF(data, cf, "SSL shutdown finished");
}
else {
nread = SSL_read(backend->handle, buf, (int)sizeof(buf));
err = SSL_get_error(backend->handle, nread);
switch(err) {
case SSL_ERROR_NONE: /* this is not an error */
case SSL_ERROR_ZERO_RETURN: /* no more data */
CURL_TRC_CF(data, cf, "SSL shutdown, EOF from server");
break;
case SSL_ERROR_WANT_READ:
/* SSL has send its notify and now wants to read the reply
* from the server. We are not really interested in that. */
CURL_TRC_CF(data, cf, "SSL shutdown sent");
break;
case SSL_ERROR_WANT_WRITE:
CURL_TRC_CF(data, cf, "SSL shutdown send blocked");
break;
default:
sslerr = ERR_get_error();
CURL_TRC_CF(data, cf, "SSL shutdown, error: '%s', errno %d",
(sslerr ?
ossl_strerror(sslerr, buf, sizeof(buf)) :
SSL_ERROR_to_str(err)),
SOCKERRNO);
break;
}
}
ERR_clear_error();
SSL_set_connect_state(backend->handle);
}

View File

@ -1494,7 +1494,8 @@ static void ssl_cf_close(struct Curl_cfilter *cf,
CF_DATA_SAVE(save, cf, data);
cf_close(cf, data);
cf->next->cft->do_close(cf->next, data);
if(cf->next)
cf->next->cft->do_close(cf->next, data);
CF_DATA_RESTORE(cf, save);
}