]> git.kaiwu.me - haproxy.git/commitdiff
BUG/MEDIUM: filters: Don't propagate a close while a filter waits on a channel
authorChristopher Faulet <cfaulet@haproxy.com>
Fri, 23 Oct 2026 16:33:29 +0000 (18:33 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Fri, 23 Oct 2026 17:43:38 +0000 (19:43 +0200)
When a filter asks to wait during the analysis of a channel, with
filter.WAIT, all the data it holds are kept in the buffer, waiting to be
processed when it is called back. But a close could be propagated to the
other side in the meantime: when a shutdown or an abort was received on
the channel, the close was forwarded to the peer side, for instance a
backend EOF was immediately forwarded to the client. The stream could
then terminate before the filter resumed, and the held data were lost,
typically a complete response held by lua filters waiting for their
wake-up, delivered with no framing and delimited by the backend close.

So now, when a filter asks to wait, the close is no longer propagated:
like the connection on the request side, the channel keeps the
CF_AUTO_CLOSE flag cleared while a filter waits on it. The flag is
restored by the analyzers on each pass, so the close is simply deferred
until the filter resumes, and nothing changes for the streams without
filters waiting.

The "lua-eof" reg-test, introduced to record this race and marked broken
until it was fixed, now passes and is un-broken. It exercises both the
legacy filter chains and the filter instance mode, with a keep-alive
connection reuse.

This patch should be backported to all supported version after a perido of
observation.

reg-tests/filters/lua-eof.vtc
src/filters.c

index 751d042e0ad2d79870eb1a2aa9e2ebd119015930..a97f182546dc8ff80f95a30a2b976f644d437904 100644 (file)
@@ -1,14 +1,15 @@
 varnishtest "Waiting Lua filters drain a complete response followed by backend EOF"
 
-#REGTEST_TYPE=broken
+#REGTEST_TYPE=devel
 
 feature cmd "$HAPROXY_PROGRAM -cc 'feature(LUA)'"
 feature ignore_unknown_macro
 
-# A backend closing after a complete chunked response can make the stream
-# close before waiting Lua callbacks resume. This also occurs with legacy
-# filters before the instance refactoring. Keep the reproducer separate
-# from the passing resumption test, which holds the backend open with a barrier.
+# A backend closing after a complete chunked response while lua filters
+# wait must not lose the held response: the close is now deferred until
+# the filters resume, and the complete response is delivered to the
+# client. This also exercises keep-alive reuse and both the legacy
+# "filter" chains and the filter instance mode.
 server s1 {
     rxreq
     txresp -body "first response"
index 698ddfafdbd48f3c89b5f2a1a19758c4c02ca234..0ef8c625e22120c90c34dc1677cd8dba944ff5d6 100644 (file)
@@ -1878,6 +1878,7 @@ handle_analyzer_result(struct stream *s, struct channel *chn,
  wait:
        if (!(chn->flags & CF_ISRESP))
                channel_dont_connect(chn);
+       channel_dont_close(chn);
        DBG_TRACE_DEVEL("wairing for more data", STRM_EV_FLT_ANA, s);
        return 0;
 }