]> git.kaiwu.me - haproxy.git/commitdiff
REGTESTS: filters: Exercise Lua filters across HTTP retries
authorChristopher Faulet <cfaulet@haproxy.com>
Fri, 2 Oct 2026 19:18:00 +0000 (21:18 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Fri, 9 Oct 2026 14:17:36 +0000 (16:17 +0200)
Retry a 503 response and redispatch to a second server. Check that both
servers receive the same request header order and instance identifiers,
without another attachment or duplicate request processing.

Verify that the failed response does not leak headers into the final
response, and that its filter order and instances still follow the
frontend/backend response sequences. Include a waiting frontend filter.

reg-tests/filters/lua-retry.vtc [new file with mode: 0644]

diff --git a/reg-tests/filters/lua-retry.vtc b/reg-tests/filters/lua-retry.vtc
new file mode 100644 (file)
index 0000000..afc5b6f
--- /dev/null
@@ -0,0 +1,74 @@
+varnishtest "HTTP retries reuse Lua filter instances and do not duplicate callbacks"
+
+feature cmd "$HAPROXY_PROGRAM -cc 'feature(LUA)'"
+feature ignore_unknown_macro
+
+barrier b_retry cond 2
+barrier b_drained cond 2
+
+server s1 {
+    rxreq
+    expect req.http.x-probe-order == "F.a;F.b;B.c;B.a;"
+    expect req.http.x-probe-instances == "F.a:2;F.b:1;B.c:1;B.a:2;"
+    expect req.http.x-probe-errors == <undef>
+    txresp -status 503 -hdr "X-Probe-Order: failed-response;" -body "retry me"
+    # Hold the first connection open until redispatch has completed too.
+    barrier b_retry sync
+} -start
+
+server s2 {
+    rxreq
+    expect req.http.x-probe-order == "F.a;F.b;B.c;B.a;"
+    expect req.http.x-probe-instances == "F.a:2;F.b:1;B.c:1;B.a:2;"
+    expect req.http.x-probe-errors == <undef>
+    barrier b_retry sync
+    txresp -body "successful retry"
+    # Do not mix retry assertions with the separate WAIT/backend-EOF race.
+    barrier b_drained sync
+} -start
+
+haproxy h1 -conf {
+    global
+        nbthread 1
+        tune.lua.bool-sample-conversion normal
+        lua-load "${testdir}/lua-probe.lua"
+    defaults
+        mode http
+        timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+        timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+        timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+    frontend fe
+        bind "fd@${fe}"
+        filter-config lua id probe-a enabled F a
+        filter-config lua id probe-b enabled F b wait
+        filter-sequence global lua/probe-b:before(lua/probe-a)
+        filter-sequence response lua/probe-b:before(lua/probe-a)
+        http-after-response set-header x-retries "%[txn.conn_retries]"
+        http-after-response set-header x-redispatched "%[txn.redispatched]"
+        default_backend be
+    backend be
+        balance first
+        retries 1
+        retry-on 503
+        option redispatch
+        filter-config lua id probe-a enabled B a
+        filter-config lua id probe-c enabled B c
+        filter-sequence global lua/probe-c:before(lua/probe-a)
+        filter-sequence request lua/probe-c:before(lua/probe-a)
+        filter-sequence response lua/probe-a:before(lua/probe-c)
+        server bad ${s1_addr}:${s1_port}
+        server good ${s2_addr}:${s2_port}
+} -start
+
+client c1 -connect ${h1_fe_sock} {
+    txreq
+    rxresp
+    expect resp.status == 200
+    expect resp.http.x-retries == "1"
+    expect resp.http.x-redispatched == "1"
+    expect resp.http.x-probe-order == "F.b;F.a;B.a;B.c;"
+    expect resp.http.x-probe-instances == "F.b:1;F.a:2;B.a:2;B.c:1;"
+    expect resp.http.x-probe-errors == <undef>
+    expect resp.body == "successful retry"
+    barrier b_drained sync
+} -run