From b3d30f44e5cca977c958c85a7a818cdf4cf5fb91 Mon Sep 17 00:00:00 2001 From: MrObvious Date: Wed, 29 Jul 2026 16:19:33 -0500 Subject: [PATCH] https_client: trigger connection reset timer on HTTP/2 and send/recv errors, not just timeouts We saw recurring "curl request failed with 16: Error" (CURLE_HTTP2) and "curl request failed with 55: Error / Send failure: Broken pipe" (CURLE_SEND_ERROR) on a production OpenWrt router running two https-dns-proxy instances, even after tuning max_idle_time down to 30s. These are classic symptoms of curl reusing a stale/half-closed HTTP/2 connection - the same class of problem the existing reset_timer/https_client_reset mechanism was built to recover from, but that mechanism is currently only armed on CURLE_OPERATION_TIMEDOUT. HTTP/2 stream errors and send/recv errors on a reused connection never reach it, so the proxy keeps trying to reuse a bad connection indefinitely instead of forcing a fresh one. This extends the existing case in https_fetch_ctx_process_response() to also arm the reset timer for CURLE_HTTP2, CURLE_HTTP2_STREAM, CURLE_GOT_NOTHING, and CURLE_SEND_ERROR - all indicators of a broken/stale connection rather than a one-off content error. No new mechanism is introduced; this only widens the set of error codes that trigger the recovery path that already exists. Tested on a production OpenWrt router (two instances, Cloudflare + Quad9 backends) - confirmed the reset timer now arms and fires (full client reset) in response to these errors, where previously they were silently ignored. --- src/https_client.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/https_client.c b/src/https_client.c index 01605a1..baa7d5a 100644 --- a/src/https_client.c +++ b/src/https_client.c @@ -357,6 +357,12 @@ static int https_fetch_ctx_process_response(https_client_t *client, WLOG_REQ("curl request failed with write error (probably response content was too large)"); break; case CURLE_OPERATION_TIMEDOUT: + case CURLE_HTTP2: + case CURLE_HTTP2_STREAM: + case CURLE_GOT_NOTHING: + case CURLE_SEND_ERROR: + // These all indicate a stale/broken (often reused HTTP/2) connection, + // not a one-off content error - same recovery path as a timeout. if (!ev_is_active(&client->reset_timer)) { ILOG_REQ("Client reset timer started"); ev_timer_start(client->loop, &client->reset_timer);