From 7f35412881436c56b4efc6d503cd2ffe940457e2 Mon Sep 17 00:00:00 2001 From: Brian Neradt Date: Fri, 6 Feb 2026 23:10:42 +0000 Subject: [PATCH] Fix failed assertion in build_response for 1xx races This failed assertion was seen sometimes when running the cache-tests. When a 1xx informational response (such as 103 Early Hints) is forwarded to the client, its headers are copied into client_response and sent via an asynchronous tunnel. The tunnel completion handler (tunnel_handler_100_continue) destroys client_response when the tunnel finishes. However, if the final server response arrives and build_response is called before the tunnel completes, client_response is still valid, triggering the assertion `!new_hdr->valid()` in copy_header_fields. This patch addresses this by defensively destroying outgoing_response in build_response if it is already valid before calling copy_header_fields. The header data from the 1xx has already been serialized into the tunnel buffer and is no longer needed, so this should be safe. --- src/proxy/http/HttpTransact.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/proxy/http/HttpTransact.cc b/src/proxy/http/HttpTransact.cc index 0f5e689222d..dc76af18812 100644 --- a/src/proxy/http/HttpTransact.cc +++ b/src/proxy/http/HttpTransact.cc @@ -7881,6 +7881,12 @@ HttpTransact::build_response(State *s, HTTPHdr *base_response, HTTPHdr *outgoing HttpTransactHeaders::build_base_response(outgoing_response, status_code, reason_phrase, strlen(reason_phrase), s->current.now); } else { if ((status_code == HTTPStatus::NONE) || (status_code == base_response->status_get())) { + // Preemptively clean up the response in case a prior 1xx informational + // response was forwarded to the client. Otherwise, copy_header_fields + // will fail an assertion that the new header is not yet valid. + if (outgoing_response->valid()) { + outgoing_response->destroy(); + } HttpTransactHeaders::copy_header_fields(base_response, outgoing_response, s->txn_conf->fwd_proxy_auth_to_parent); if (s->txn_conf->insert_age_in_response) {