Summary
When Traffic Server is proxying a request to an upstream server and the client aborts the request before the upstream server has responded at all, Traffic Server appears to still try and complete the request, rather than cancelling the request and relaying this cancellation to the upstream server.
Under Traffic Server 9.2 and 10.0, this behavior can seemingly be controlled by proxy.config.http.allow_half_open, but in Traffic Server 10.1.4 and 10.2.0-rc1, I can't find any way to have Traffic Server abort these canceled client requests.
In situations where the upstream server is very slow to respond and clients cancel many requests, Traffic Server still holds open the connections for any cancelled requests to the upstream server. In a worst-case scenario, this may eventually cause Traffic Server to hit its own proxy.config.net.max_requests_in or proxy.config.net.connections_throttle limits if it's completely occupied trying to fulfill all of the canceled requests. I realize there are some situations where you'd maybe want to try and let the upstream requests complete, but I'm trying to figure out why changing that allow_half_open setting doesn't seem to affect 10.1 and 10.2 in the same way as before.
Based on the docs, I was also wondering if proxy.config.http.background_fill_active_timeout or proxy.config.http.background_fill_completed_threshold could play a role, but regardless of settings, I can't get these requests canceled by the client to stop processing in Traffic Server 10.1 or 10.2.
So, am I missing some other setting to control this, or is this a bug in 10.1 and 10.2?
Possibly related PRs
I'm proxying over HTTP 1.1, if that's relevant. I dug up several semi-recent PRs that seem to be touching this code, but they all seem maybe more related to HTTP 2 behavior, so I'm wondering if maybe this is no longer working properly for HTTP 1.1 proxied requests (but I haven't verified things with anything besides HTTP 1.1):
Logs and related code
Debug logging indicates that when the client cancels the request, Traffic Server is hitting the state_watch_for_client_abort handler with a VC_EVENT_EOS event:
[ET_NET 0] DIAG: <HttpSM.cc:2795 (main_handler)> (http) [2] VC_EVENT_EOS/TS_EVENT_VCONN_EOS, 104
[ET_NET 0] DIAG: <HttpSM.cc:896 (state_watch_for_client_abort)> (http) [2] [state_watch_for_client_abort, VC_EVENT_EOS/TS_EVENT_VCONN_EOS]
With allow_half_open disabled, then in 10.1.4 or 10.2.0-rc1, it's landing in this else if block:
|
} else if (t_state.txn_conf->cache_http && |
|
(server_entry != nullptr && server_entry->vc_read_handler == &HttpSM::state_read_server_response_header)) { |
|
// if HttpSM is waiting response header from origin server, keep it for a while to run background fetch |
|
_ua.get_txn()->do_io_shutdown(IO_SHUTDOWN_READWRITE); |
However, if I remove that else if block entirely (so it falls into the else logic), then the request is canceled as I was originally expecting. It seems like that else if block was intentionally added by #12529 to fix a very similar sounding issue, though. I'm not familiar enough with the codebase or what that PR was originally fixing to know what the proper solution is here, but it seems like some of these more recent changes to state_watch_for_client_abort could be playing a role.
Reproduction
Here's a little repo (client-abort branch) showing how the cancellation behavior doesn't seem to be working as I'd expect in Traffic Server 10.1 and 10.2: https://github.com/GUI/trafficserver-debugging/tree/client-aborts
This reproduction essentially consists of an nginx upstream server that sleeps for 10 seconds and then responds. Traffic Server is proxying to this upstream with the allow_half_open option disabled.
With Traffic Server 9.2, 10.0, or nginx itself proxying, you can see the upstream connection is aborted after the client cancels the request. However, in Traffic Server 10.1.4 or 10.2.0-rc1, the upstream connection continues until it is complete (which is not what I want with allow_half_open disabled).
Direct upstream request with timeout
curl -w 'time_total: %{time_total}s\n' --max-time 2 'http://localhost:8081/'
# curl: (28) Operation timed out after 2005 milliseconds with 0 bytes received
# time_total: 2.004165s
Server logs show nginx upstream canceling request immediately after client hangs up (after 2 seconds):
nginx-1 | 192.168.65.1 - - [14/Aug/2026:04:07:06 +0000] "GET / HTTP/1.1" 499 0 "-" "curl/8.7.1" request_time=2.004 msec=1786680426.901
Traffic Server 9.2/10.0 cancellation
curl -w 'time_total: %{time_total}s\n' --max-time 2 'http://localhost:10100/'
# curl: (28) Operation timed out after 2006 milliseconds with 0 bytes received
# time_total: 2.006394s
Server logs show both nginx upstream and Traffic Server closing connection after the 2 second client timeout.
nginx-1 | 192.168.224.2 - - [14/Aug/2026:04:08:50 +0000] "GET / HTTP/1.1" 499 0 "-" "curl/8.7.1" request_time=1.998 msec=1786680530.387
ts-10-0-1 | 192.168.65.1 - - [14/Aug/2026:04:08:48 -0000] "GET http://nginx:8081/ http/1.1" 000 0 000 0 0 0 90 0 226 17 2 EMPTY INTR FIN ERR_CLIENT_ABORT ttms=2009 stms=-1
BUG SCENARIO: Traffic Server 10.1.4/10.2.0-rc1 not aborting
curl -w 'time_total: %{time_total}s\n' --max-time 2 'http://localhost:10102/'
# curl: (28) Operation timed out after 2002 milliseconds with 0 bytes received
# time_total: 2.002365s
Despite the client hanging up after 2 seconds, server logs show that both Traffic Server and the nginx upstream kept the connection open for the full 10 seconds it took for the upstream to respond (see request_time and ttms in log output):
nginx-1 | 192.168.224.4 - - [14/Aug/2026:04:11:18 +0000] "GET / HTTP/1.1" 200 29 "-" "curl/8.7.1" request_time=10.001 msec=1786680678.975
ts-10-2-1 | 192.168.65.1 - - [14/Aug/2026:04:11:08 -0000] "GET http://nginx:8081/ http/1.1" 200 0 200 0 0 0 90 177 226 148 10 DIRECT INTR FIN ERR_CLIENT_READ_ERROR ttms=10020 stms=10007
nginx proxy cancellation
Just for comparison, there's also an nginx proxy in front of the nginx upstream:
curl -w 'time_total: %{time_total}s\n' --max-time 2 'http://localhost:10092/'
curl: (28) Operation timed out after 2003 milliseconds with 0 bytes received
time_total: 2.003557s
You can see this nginx proxy behaves the same as Traffic Server 9.2 or 10.0, with both requests being canceled after the 2 second client timeout:
nginx-1 | 192.168.65.1 - - [14/Aug/2026:04:13:02 +0000] "GET / HTTP/1.1" 499 0 "-" "curl/8.7.1" request_time=2.007 msec=1786680782.467
nginx-1 | 127.0.0.1 - - [14/Aug/2026:04:13:02 +0000] "GET / HTTP/1.1" 499 0 "-" "curl/8.7.1" request_time=2.005 msec=1786680782.467
Summary
When Traffic Server is proxying a request to an upstream server and the client aborts the request before the upstream server has responded at all, Traffic Server appears to still try and complete the request, rather than cancelling the request and relaying this cancellation to the upstream server.
Under Traffic Server 9.2 and 10.0, this behavior can seemingly be controlled by
proxy.config.http.allow_half_open, but in Traffic Server 10.1.4 and 10.2.0-rc1, I can't find any way to have Traffic Server abort these canceled client requests.In situations where the upstream server is very slow to respond and clients cancel many requests, Traffic Server still holds open the connections for any cancelled requests to the upstream server. In a worst-case scenario, this may eventually cause Traffic Server to hit its own
proxy.config.net.max_requests_inorproxy.config.net.connections_throttlelimits if it's completely occupied trying to fulfill all of the canceled requests. I realize there are some situations where you'd maybe want to try and let the upstream requests complete, but I'm trying to figure out why changing thatallow_half_opensetting doesn't seem to affect 10.1 and 10.2 in the same way as before.Based on the docs, I was also wondering if
proxy.config.http.background_fill_active_timeoutorproxy.config.http.background_fill_completed_thresholdcould play a role, but regardless of settings, I can't get these requests canceled by the client to stop processing in Traffic Server 10.1 or 10.2.So, am I missing some other setting to control this, or is this a bug in 10.1 and 10.2?
Possibly related PRs
I'm proxying over HTTP 1.1, if that's relevant. I dug up several semi-recent PRs that seem to be touching this code, but they all seem maybe more related to HTTP 2 behavior, so I'm wondering if maybe this is no longer working properly for HTTP 1.1 proxied requests (but I haven't verified things with anything besides HTTP 1.1):
Logs and related code
Debug logging indicates that when the client cancels the request, Traffic Server is hitting the
state_watch_for_client_aborthandler with aVC_EVENT_EOSevent:With
allow_half_opendisabled, then in 10.1.4 or 10.2.0-rc1, it's landing in thiselse ifblock:trafficserver/src/proxy/http/HttpSM.cc
Lines 924 to 927 in b1df733
However, if I remove that
else ifblock entirely (so it falls into theelselogic), then the request is canceled as I was originally expecting. It seems like thatelse ifblock was intentionally added by #12529 to fix a very similar sounding issue, though. I'm not familiar enough with the codebase or what that PR was originally fixing to know what the proper solution is here, but it seems like some of these more recent changes tostate_watch_for_client_abortcould be playing a role.Reproduction
Here's a little repo (
client-abortbranch) showing how the cancellation behavior doesn't seem to be working as I'd expect in Traffic Server 10.1 and 10.2: https://github.com/GUI/trafficserver-debugging/tree/client-abortsThis reproduction essentially consists of an nginx upstream server that sleeps for 10 seconds and then responds. Traffic Server is proxying to this upstream with the
allow_half_openoption disabled.With Traffic Server 9.2, 10.0, or nginx itself proxying, you can see the upstream connection is aborted after the client cancels the request. However, in Traffic Server 10.1.4 or 10.2.0-rc1, the upstream connection continues until it is complete (which is not what I want with
allow_half_opendisabled).Direct upstream request with timeout
Server logs show nginx upstream canceling request immediately after client hangs up (after 2 seconds):
Traffic Server 9.2/10.0 cancellation
Server logs show both nginx upstream and Traffic Server closing connection after the 2 second client timeout.
BUG SCENARIO: Traffic Server 10.1.4/10.2.0-rc1 not aborting
Despite the client hanging up after 2 seconds, server logs show that both Traffic Server and the nginx upstream kept the connection open for the full 10 seconds it took for the upstream to respond (see
request_timeandttmsin log output):nginx proxy cancellation
Just for comparison, there's also an nginx proxy in front of the nginx upstream:
You can see this nginx proxy behaves the same as Traffic Server 9.2 or 10.0, with both requests being canceled after the 2 second client timeout: