mirror of
https://github.com/curl/curl.git
synced 2026-08-26 19:23:32 +03:00
cfilter: unlink and discard
Rewrite the code that removes a filter from the connection and discards it. Always look at the connection, otherwise it will not work of the filter is at the top of the chain. Change QUIC filter setup code to always tear down the chain in construction when an error occured. HTTP proxy, do not remove the h1/h2 sub filter on close. Leave it to be discarded with the connection. Avoids keeping an additional pointer that might become dangling. Triggered by a reported on a code bug in discard method. Reported-by: Joshua Rogers Closes #18596
This commit is contained in:
parent
ca034e839c
commit
0f08211330
7 changed files with 54 additions and 85 deletions
|
|
@ -383,29 +383,26 @@ void Curl_conn_cf_insert_after(struct Curl_cfilter *cf_at,
|
||||||
*pnext = tail;
|
*pnext = tail;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Curl_conn_cf_discard_sub(struct Curl_cfilter *cf,
|
bool Curl_conn_cf_discard(struct Curl_cfilter **pcf,
|
||||||
struct Curl_cfilter *discard,
|
struct Curl_easy *data)
|
||||||
struct Curl_easy *data,
|
|
||||||
bool destroy_always)
|
|
||||||
{
|
{
|
||||||
struct Curl_cfilter **pprev = &cf->next;
|
struct Curl_cfilter *cf = pcf ? *pcf : NULL;
|
||||||
bool found = FALSE;
|
bool found = FALSE;
|
||||||
|
if(cf) {
|
||||||
/* remove from sub-chain and destroy */
|
if(cf->conn) {
|
||||||
DEBUGASSERT(cf);
|
/* unlink if present in connection filter chain */
|
||||||
while(*pprev) {
|
struct Curl_cfilter **pprev = &cf->conn->cfilter[cf->sockindex];
|
||||||
if(*pprev == cf) {
|
while(*pprev) {
|
||||||
*pprev = discard->next;
|
if(*pprev == *pcf) {
|
||||||
discard->next = NULL;
|
*pprev = (*pcf)->next;
|
||||||
found = TRUE;
|
cf->next = NULL;
|
||||||
break;
|
found = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pprev = &((*pprev)->next);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pprev = &((*pprev)->next);
|
Curl_conn_cf_discard_chain(pcf, data);
|
||||||
}
|
|
||||||
if(found || destroy_always) {
|
|
||||||
discard->next = NULL;
|
|
||||||
discard->cft->destroy(discard, data);
|
|
||||||
free(discard);
|
|
||||||
}
|
}
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -297,16 +297,12 @@ void Curl_conn_cf_insert_after(struct Curl_cfilter *cf_at,
|
||||||
struct Curl_cfilter *cf_new);
|
struct Curl_cfilter *cf_new);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Discard, e.g. remove and destroy `discard` iff
|
* Extract filter `*pcf` from its connection filter chain.
|
||||||
* it still is in the filter chain below `cf`. If `discard`
|
* Destroy `*pcf`, even if it was not part of the chain and NULL it.
|
||||||
* is no longer found beneath `cf` return FALSE.
|
* Returns TRUE of cf has been part of chain.
|
||||||
* if `destroy_always` is TRUE, will call `discard`s destroy
|
|
||||||
* function and free it even if not found in the subchain.
|
|
||||||
*/
|
*/
|
||||||
bool Curl_conn_cf_discard_sub(struct Curl_cfilter *cf,
|
bool Curl_conn_cf_discard(struct Curl_cfilter **pcf,
|
||||||
struct Curl_cfilter *discard,
|
struct Curl_easy *data);
|
||||||
struct Curl_easy *data,
|
|
||||||
bool destroy_always);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Discard all cfilters starting with `*pcf` and clearing it afterwards.
|
* Discard all cfilters starting with `*pcf` and clearing it afterwards.
|
||||||
|
|
|
||||||
|
|
@ -215,9 +215,8 @@ CURLcode Curl_http_proxy_get_destination(struct Curl_cfilter *cf,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cf_proxy_ctx {
|
struct cf_proxy_ctx {
|
||||||
/* the protocol specific sub-filter we install during connect */
|
|
||||||
struct Curl_cfilter *cf_protocol;
|
|
||||||
int httpversion; /* HTTP version used to CONNECT */
|
int httpversion; /* HTTP version used to CONNECT */
|
||||||
|
BIT(sub_filter_installed);
|
||||||
};
|
};
|
||||||
|
|
||||||
CURLcode Curl_http_proxy_create_CONNECT(struct httpreq **preq,
|
CURLcode Curl_http_proxy_create_CONNECT(struct httpreq **preq,
|
||||||
|
|
@ -317,8 +316,7 @@ connect_sub:
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
*done = FALSE;
|
*done = FALSE;
|
||||||
if(!ctx->cf_protocol) {
|
if(!ctx->sub_filter_installed) {
|
||||||
struct Curl_cfilter *cf_protocol = NULL;
|
|
||||||
int httpversion = 0;
|
int httpversion = 0;
|
||||||
const char *alpn = Curl_conn_cf_get_alpn_negotiated(cf->next, data);
|
const char *alpn = Curl_conn_cf_get_alpn_negotiated(cf->next, data);
|
||||||
|
|
||||||
|
|
@ -332,7 +330,6 @@ connect_sub:
|
||||||
result = Curl_cf_h1_proxy_insert_after(cf, data);
|
result = Curl_cf_h1_proxy_insert_after(cf, data);
|
||||||
if(result)
|
if(result)
|
||||||
goto out;
|
goto out;
|
||||||
cf_protocol = cf->next;
|
|
||||||
httpversion = 10;
|
httpversion = 10;
|
||||||
}
|
}
|
||||||
else if(!alpn || !strcmp(alpn, "http/1.1")) {
|
else if(!alpn || !strcmp(alpn, "http/1.1")) {
|
||||||
|
|
@ -340,7 +337,6 @@ connect_sub:
|
||||||
result = Curl_cf_h1_proxy_insert_after(cf, data);
|
result = Curl_cf_h1_proxy_insert_after(cf, data);
|
||||||
if(result)
|
if(result)
|
||||||
goto out;
|
goto out;
|
||||||
cf_protocol = cf->next;
|
|
||||||
/* Assume that without an ALPN, we are talking to an ancient one */
|
/* Assume that without an ALPN, we are talking to an ancient one */
|
||||||
httpversion = 11;
|
httpversion = 11;
|
||||||
}
|
}
|
||||||
|
|
@ -350,7 +346,6 @@ connect_sub:
|
||||||
result = Curl_cf_h2_proxy_insert_after(cf, data);
|
result = Curl_cf_h2_proxy_insert_after(cf, data);
|
||||||
if(result)
|
if(result)
|
||||||
goto out;
|
goto out;
|
||||||
cf_protocol = cf->next;
|
|
||||||
httpversion = 20;
|
httpversion = 20;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -360,7 +355,7 @@ connect_sub:
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->cf_protocol = cf_protocol;
|
ctx->sub_filter_installed = TRUE;
|
||||||
ctx->httpversion = httpversion;
|
ctx->httpversion = httpversion;
|
||||||
/* after we installed the filter "below" us, we call connect
|
/* after we installed the filter "below" us, we call connect
|
||||||
* on out sub-chain again.
|
* on out sub-chain again.
|
||||||
|
|
@ -371,7 +366,7 @@ connect_sub:
|
||||||
/* subchain connected and we had already installed the protocol filter.
|
/* subchain connected and we had already installed the protocol filter.
|
||||||
* This means the protocol tunnel is established, we are done.
|
* This means the protocol tunnel is established, we are done.
|
||||||
*/
|
*/
|
||||||
DEBUGASSERT(ctx->cf_protocol);
|
DEBUGASSERT(ctx->sub_filter_installed);
|
||||||
result = CURLE_OK;
|
result = CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -419,23 +414,8 @@ static void http_proxy_cf_destroy(struct Curl_cfilter *cf,
|
||||||
static void http_proxy_cf_close(struct Curl_cfilter *cf,
|
static void http_proxy_cf_close(struct Curl_cfilter *cf,
|
||||||
struct Curl_easy *data)
|
struct Curl_easy *data)
|
||||||
{
|
{
|
||||||
struct cf_proxy_ctx *ctx = cf->ctx;
|
|
||||||
|
|
||||||
CURL_TRC_CF(data, cf, "close");
|
CURL_TRC_CF(data, cf, "close");
|
||||||
cf->connected = FALSE;
|
cf->connected = FALSE;
|
||||||
if(ctx->cf_protocol) {
|
|
||||||
struct Curl_cfilter *f;
|
|
||||||
/* if someone already removed it, we assume he also
|
|
||||||
* took care of destroying it. */
|
|
||||||
for(f = cf->next; f; f = f->next) {
|
|
||||||
if(f == ctx->cf_protocol) {
|
|
||||||
/* still in our sub-chain */
|
|
||||||
Curl_conn_cf_discard_sub(cf, ctx->cf_protocol, data, FALSE);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ctx->cf_protocol = NULL;
|
|
||||||
}
|
|
||||||
if(cf->next)
|
if(cf->next)
|
||||||
cf->next->cft->do_close(cf->next, data);
|
cf->next->cft->do_close(cf->next, data);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2767,7 +2767,7 @@ CURLcode Curl_cf_ngtcp2_create(struct Curl_cfilter **pcf,
|
||||||
const struct Curl_addrinfo *ai)
|
const struct Curl_addrinfo *ai)
|
||||||
{
|
{
|
||||||
struct cf_ngtcp2_ctx *ctx = NULL;
|
struct cf_ngtcp2_ctx *ctx = NULL;
|
||||||
struct Curl_cfilter *cf = NULL, *udp_cf = NULL;
|
struct Curl_cfilter *cf = NULL;
|
||||||
CURLcode result;
|
CURLcode result;
|
||||||
|
|
||||||
(void)data;
|
(void)data;
|
||||||
|
|
@ -2781,23 +2781,21 @@ CURLcode Curl_cf_ngtcp2_create(struct Curl_cfilter **pcf,
|
||||||
result = Curl_cf_create(&cf, &Curl_cft_http3, ctx);
|
result = Curl_cf_create(&cf, &Curl_cft_http3, ctx);
|
||||||
if(result)
|
if(result)
|
||||||
goto out;
|
goto out;
|
||||||
|
cf->conn = conn;
|
||||||
|
|
||||||
result = Curl_cf_udp_create(&udp_cf, data, conn, ai, TRNSPRT_QUIC);
|
result = Curl_cf_udp_create(&cf->next, data, conn, ai, TRNSPRT_QUIC);
|
||||||
if(result)
|
if(result)
|
||||||
goto out;
|
goto out;
|
||||||
|
cf->next->conn = cf->conn;
|
||||||
cf->conn = conn;
|
cf->next->sockindex = cf->sockindex;
|
||||||
udp_cf->conn = cf->conn;
|
|
||||||
udp_cf->sockindex = cf->sockindex;
|
|
||||||
cf->next = udp_cf;
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
*pcf = (!result) ? cf : NULL;
|
*pcf = (!result) ? cf : NULL;
|
||||||
if(result) {
|
if(result) {
|
||||||
if(udp_cf)
|
if(cf)
|
||||||
Curl_conn_cf_discard_sub(cf, udp_cf, data, TRUE);
|
Curl_conn_cf_discard_chain(&cf, data);
|
||||||
Curl_safefree(cf);
|
else if(ctx)
|
||||||
cf_ngtcp2_ctx_free(ctx);
|
cf_ngtcp2_ctx_free(ctx);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2398,7 +2398,7 @@ CURLcode Curl_cf_osslq_create(struct Curl_cfilter **pcf,
|
||||||
const struct Curl_addrinfo *ai)
|
const struct Curl_addrinfo *ai)
|
||||||
{
|
{
|
||||||
struct cf_osslq_ctx *ctx = NULL;
|
struct cf_osslq_ctx *ctx = NULL;
|
||||||
struct Curl_cfilter *cf = NULL, *udp_cf = NULL;
|
struct Curl_cfilter *cf = NULL;
|
||||||
CURLcode result;
|
CURLcode result;
|
||||||
|
|
||||||
(void)data;
|
(void)data;
|
||||||
|
|
@ -2412,23 +2412,22 @@ CURLcode Curl_cf_osslq_create(struct Curl_cfilter **pcf,
|
||||||
result = Curl_cf_create(&cf, &Curl_cft_http3, ctx);
|
result = Curl_cf_create(&cf, &Curl_cft_http3, ctx);
|
||||||
if(result)
|
if(result)
|
||||||
goto out;
|
goto out;
|
||||||
|
cf->conn = conn;
|
||||||
|
|
||||||
result = Curl_cf_udp_create(&udp_cf, data, conn, ai, TRNSPRT_QUIC);
|
result = Curl_cf_udp_create(&cf->next, data, conn, ai, TRNSPRT_QUIC);
|
||||||
if(result)
|
if(result)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
cf->conn = conn;
|
cf->next->conn = cf->conn;
|
||||||
udp_cf->conn = cf->conn;
|
cf->next->sockindex = cf->sockindex;
|
||||||
udp_cf->sockindex = cf->sockindex;
|
|
||||||
cf->next = udp_cf;
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
*pcf = (!result) ? cf : NULL;
|
*pcf = (!result) ? cf : NULL;
|
||||||
if(result) {
|
if(result) {
|
||||||
if(udp_cf)
|
if(cf)
|
||||||
Curl_conn_cf_discard_sub(cf, udp_cf, data, TRUE);
|
Curl_conn_cf_discard_chain(&cf, data);
|
||||||
Curl_safefree(cf);
|
else if(ctx)
|
||||||
cf_osslq_ctx_free(ctx);
|
cf_osslq_ctx_free(ctx);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1636,7 +1636,7 @@ CURLcode Curl_cf_quiche_create(struct Curl_cfilter **pcf,
|
||||||
const struct Curl_addrinfo *ai)
|
const struct Curl_addrinfo *ai)
|
||||||
{
|
{
|
||||||
struct cf_quiche_ctx *ctx = NULL;
|
struct cf_quiche_ctx *ctx = NULL;
|
||||||
struct Curl_cfilter *cf = NULL, *udp_cf = NULL;
|
struct Curl_cfilter *cf = NULL;
|
||||||
CURLcode result;
|
CURLcode result;
|
||||||
|
|
||||||
(void)data;
|
(void)data;
|
||||||
|
|
@ -1651,22 +1651,21 @@ CURLcode Curl_cf_quiche_create(struct Curl_cfilter **pcf,
|
||||||
result = Curl_cf_create(&cf, &Curl_cft_http3, ctx);
|
result = Curl_cf_create(&cf, &Curl_cft_http3, ctx);
|
||||||
if(result)
|
if(result)
|
||||||
goto out;
|
goto out;
|
||||||
|
cf->conn = conn;
|
||||||
|
|
||||||
result = Curl_cf_udp_create(&udp_cf, data, conn, ai, TRNSPRT_QUIC);
|
result = Curl_cf_udp_create(&cf->next, data, conn, ai, TRNSPRT_QUIC);
|
||||||
if(result)
|
if(result)
|
||||||
goto out;
|
goto out;
|
||||||
|
cf->next->conn = cf->conn;
|
||||||
udp_cf->conn = cf->conn;
|
cf->next->sockindex = cf->sockindex;
|
||||||
udp_cf->sockindex = cf->sockindex;
|
|
||||||
cf->next = udp_cf;
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
*pcf = (!result) ? cf : NULL;
|
*pcf = (!result) ? cf : NULL;
|
||||||
if(result) {
|
if(result) {
|
||||||
if(udp_cf)
|
if(cf)
|
||||||
Curl_conn_cf_discard_sub(cf, udp_cf, data, TRUE);
|
Curl_conn_cf_discard_chain(&cf, data);
|
||||||
Curl_safefree(cf);
|
else if(ctx)
|
||||||
cf_quiche_ctx_free(ctx);
|
cf_quiche_ctx_free(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
|
||||||
|
|
@ -1862,7 +1862,7 @@ CURLcode Curl_ssl_cfilter_remove(struct Curl_easy *data,
|
||||||
Curl_shutdown_clear(data, sockindex);
|
Curl_shutdown_clear(data, sockindex);
|
||||||
if(!result && !done) /* blocking failed? */
|
if(!result && !done) /* blocking failed? */
|
||||||
result = CURLE_SSL_SHUTDOWN_FAILED;
|
result = CURLE_SSL_SHUTDOWN_FAILED;
|
||||||
Curl_conn_cf_discard_sub(head, cf, data, FALSE);
|
Curl_conn_cf_discard(&cf, data);
|
||||||
CURL_TRC_CF(data, cf, "shutdown and remove SSL, done -> %d", result);
|
CURL_TRC_CF(data, cf, "shutdown and remove SSL, done -> %d", result);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue