From 8af09879faadbce77aa8f6bfa7e171cd37e5b284 Mon Sep 17 00:00:00 2001 From: bneradt Date: Wed, 18 Mar 2026 21:24:07 -0500 Subject: [PATCH] Cancel pending origin connect on client abort The http2_rst_stream AuTest exposed a race on multiplexed origin connects. If the client aborted while ATS was still queued on a shared HTTP/2 origin handshake, HttpSM marked the transaction aborted but stayed in the ConnectingEntry queue until later cleanup. A handshake that finished in that window could still dispatch CONNECT_EVENT_TXN back into the dead transaction, forwarding the request upstream and producing an unexpected origin-side RST_STREAM. Cancel the pending shared origin connect as soon as state_watch_for_client_abort() records the client abort. That removes the HttpSM from the ConnectingEntry queue before the handshake callback can revive it, making the abort path deterministic and keeping the aborted request from reaching origin. --- src/proxy/http/HttpSM.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/proxy/http/HttpSM.cc b/src/proxy/http/HttpSM.cc index 1f312ad1e23..73f0846e317 100644 --- a/src/proxy/http/HttpSM.cc +++ b/src/proxy/http/HttpSM.cc @@ -922,6 +922,10 @@ HttpSM::state_watch_for_client_abort(int event, void *data) vc_table.cleanup_entry(_ua.get_entry()); _ua.set_entry(nullptr); tunnel.kill_tunnel(); + // Drop any queued multiplexed origin connect immediately so a + // completed handshake cannot revive this transaction after the + // client has already aborted. + this->cancel_pending_server_connection(); terminate_sm = true; // Just die already, the requester is gone set_ua_abort(HttpTransact::ABORTED, event); } @@ -955,6 +959,7 @@ HttpSM::state_watch_for_client_abort(int event, void *data) ATS_PROBE1(milestone_ua_close, sm_id); milestones[TS_MILESTONE_UA_CLOSE] = ink_get_hrtime(); set_ua_abort(HttpTransact::ABORTED, event); + this->cancel_pending_server_connection(); terminate_sm = true; break;