This is an automated email from the ASF dual-hosted git repository.
bneradt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/master by this push:
new d366ab0fed Fix bg fill teardown crash in update_size_and_time_stats
(#13114)
d366ab0fed is described below
commit d366ab0feda439399bc32d8d3d2551492347fcb1
Author: Brian Neradt <[email protected]>
AuthorDate: Tue May 12 11:07:09 2026 -0500
Fix bg fill teardown crash in update_size_and_time_stats (#13114)
Production crash logs show ink_assert(0) firing in
HttpTransact::update_size_and_time_stats when an HTTP/2 stream close
re-enters HttpSM after the user-agent side was detached for background
fill. The server-to-cache tunnel should continue, but the stale
user-agent event misses the VC table and falls through to the default
tunnel handler, which tears down the SM with background_fill still
STARTED.
This ignores stale user-agent VIO and close events while a background
fill tunnel is active, so tunnel_handler_server remains responsible for
driving the fill to COMPLETED or ABORTED. This also keeps an
unconditional kill_this cleanup as a last-resort guard to balance
background_fill_current_count if any unexpected path still tears down
mid-fill.
---
src/proxy/http/HttpSM.cc | 46 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
diff --git a/src/proxy/http/HttpSM.cc b/src/proxy/http/HttpSM.cc
index c75f69ec9d..12af2570b2 100644
--- a/src/proxy/http/HttpSM.cc
+++ b/src/proxy/http/HttpSM.cc
@@ -2762,11 +2762,47 @@ HttpSM::main_handler(int event, void *data)
}
}
+ // Is there an active background-fill tunnel?
+ // Background fill detaches the user-agent VC and lets the server/cache side
+ // finish the response body. An Http2Stream can still deliver a scheduled UA
+ // close/error callback after that detach, but the UA VIO no longer has a VC
+ // table entry. This predicate recognizes only those detached UA-side events
+ // so they do not fall through to the default tunnel handler and tear down
the
+ // HttpSM before the active background-fill tunnel completes.
+ auto is_stale_bg_fill_ua_event = [&]() -> bool {
+ if (background_fill != BackgroundFill_t::STARTED ||
!tunnel.is_tunnel_alive() || _ua.get_txn() == nullptr) {
+ return false;
+ }
+
+ switch (event) {
+ case VC_EVENT_EOS:
+ case VC_EVENT_ERROR:
+ case VC_EVENT_INACTIVITY_TIMEOUT:
+ case VC_EVENT_ACTIVE_TIMEOUT:
+ case VC_EVENT_WRITE_READY:
+ case VC_EVENT_WRITE_COMPLETE:
+ case VC_EVENT_READ_READY:
+ case VC_EVENT_READ_COMPLETE:
+ break;
+ default:
+ return false;
+ }
+
+ if (data == nullptr) {
+ return true;
+ }
+
+ return static_cast<VIO *>(data)->vc_server == _ua.get_txn();
+ };
+
if (vc_entry) {
jump_point = (static_cast<VIO *>(data) == vc_entry->read_vio) ?
vc_entry->vc_read_handler : vc_entry->vc_write_handler;
ink_assert(jump_point != (HttpSMHandler) nullptr);
ink_assert(vc_entry->vc != (VConnection *)nullptr);
(this->*jump_point)(event, data);
+ } else if (is_stale_bg_fill_ua_event()) {
+ SMDbg(dbg_ctl_http, "ignoring stale %s event for closed user agent while
background fill is active",
+ HttpDebugNames::get_event_name(event));
} else {
ink_assert(default_handler != (HttpSMHandler) nullptr);
(this->*default_handler)(event, data);
@@ -7714,6 +7750,16 @@ HttpSM::kill_this()
// we must check it again
if (kill_this_async_done == true) {
pending_action = nullptr;
+
+ // This should only be a last-resort cleanup path. A background fill is
+ // normally driven to COMPLETED or ABORTED by tunnel_handler_server, but
+ // any unexpected teardown must still balance the active fill gauge before
+ // optional stats/logging run.
+ if (background_fill == BackgroundFill_t::STARTED) {
+ background_fill = BackgroundFill_t::ABORTED;
+ Metrics::Gauge::decrement(http_rsb.background_fill_current_count);
+ }
+
if (t_state.http_config_param->enable_http_stats) {
update_stats();
}