]> git.kaiwu.me - haproxy.git/commitdiff
REGTESTS: http-messaging: test the http-hardening checks on HTTP/2 headers
authorWilly Tarreau <w@1wt.eu>
Wed, 4 Nov 2026 17:08:51 +0000 (18:08 +0100)
committerWilly Tarreau <w@1wt.eu>
Wed, 4 Nov 2026 21:45:33 +0000 (22:45 +0100)
This is an LLM-generated reg-test covering HTTP/2 hardening checks.

This is the HTTP/2 counterpart of http_hardening_h1.vtc for the checks that
apply to HTTP/2 (folding and Transfer-Encoding cannot appear there). A
rejected request must cause a stream error, except for an invalid method
which results in a 400 like other method errors, and a rejected response a
502. It also checks that a Host header accompanying an identical :authority
is not considered as a duplicate Host header.

reg-tests/http-messaging/http_hardening_h2.vtc [new file with mode: 0644]

diff --git a/reg-tests/http-messaging/http_hardening_h2.vtc b/reg-tests/http-messaging/http_hardening_h2.vtc
new file mode 100644 (file)
index 0000000..b7a72f4
--- /dev/null
@@ -0,0 +1,869 @@
+varnishtest "HTTP hardening checks on HTTP/2 headers"
+
+# Note: vtest needs the pseudo-headers to be explicit on requests carrying
+# extra headers, otherwise it appends them after the regular ones.
+#
+# Same principle as http_hardening_h1.vtc, for the checks which apply to
+# HTTP/2: each check has its own profile, applied to a dedicated bind line for
+# requests, or to a dedicated server line for responses. The "off" profile has
+# everything disabled and serves as the reference. A rejected request causes
+# a stream error (or a 400 for an invalid method, like other method errors),
+# and a rejected response causes a 502.
+#
+# On the request side the frontend replies itself and reports the method, the
+# header names it saw and the hex-encoded value of header "foo".
+
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(3.5-dev10)'"
+feature ignore_unknown_macro
+
+server s_off_us {
+       rxpri
+       stream 0 {
+               txsettings
+               rxsettings
+               txsettings -ack
+       } -run
+
+       stream 1 {
+               rxreq
+               txresp -status 200 -hdr "x_a" "1" -hdr "x-b" "2"
+       } -run
+} -start
+
+server s_off_unreg {
+       rxpri
+       stream 0 {
+               txsettings
+               rxsettings
+               txsettings -ack
+       } -run
+
+       stream 1 {
+               rxreq
+               txresp -status 200 -hdr "x-foo" "1" -hdr "foo" "2"
+       } -run
+} -start
+
+server s_off_ctl {
+       rxpri
+       stream 0 {
+               txsettings
+               rxsettings
+               txsettings -ack
+       } -run
+
+       stream 1 {
+               rxreq
+               txresp -status 200 -hdr "foo" "a\x01b"
+       } -run
+} -start
+
+server s_off_cl0 {
+       rxpri
+       stream 0 {
+               txsettings
+               rxsettings
+               txsettings -ack
+       } -run
+
+       stream 1 {
+               rxreq
+               txresp -status 200 -hdr "content-length" "00"
+       } -run
+} -start
+
+server s_us_rej_ok {
+       rxpri
+       stream 0 {
+               txsettings
+               rxsettings
+               txsettings -ack
+       } -run
+
+       stream 1 {
+               rxreq
+               txresp -status 200 -hdr "x-b" "2"
+       } -run
+} -start
+
+server s_us_rej {
+       rxpri
+       stream 0 {
+               txsettings
+               rxsettings
+               txsettings -ack
+       } -run
+
+       stream 1 {
+               rxreq
+               txresp -status 200 -hdr "x_a" "1"
+       } -run
+} -start
+
+server s_us_del {
+       rxpri
+       stream 0 {
+               txsettings
+               rxsettings
+               txsettings -ack
+       } -run
+
+       stream 1 {
+               rxreq
+               txresp -status 200 -hdr "x_a" "1" -hdr "x-b" "2"
+       } -run
+} -start
+
+server s_us_both {
+       rxpri
+       stream 0 {
+               txsettings
+               rxsettings
+               txsettings -ack
+       } -run
+
+       stream 1 {
+               rxreq
+               txresp -status 200 -hdr "x_a" "1"
+       } -run
+} -start
+
+server s_unreg {
+       rxpri
+       stream 0 {
+               txsettings
+               rxsettings
+               txsettings -ack
+       } -run
+
+       stream 1 {
+               rxreq
+               txresp -status 200 -hdr "x-foo" "1" -hdr "foo" "2" -hdr "xa" "3"
+       } -run
+} -start
+
+server s_ctl_ok {
+       rxpri
+       stream 0 {
+               txsettings
+               rxsettings
+               txsettings -ack
+       } -run
+
+       stream 1 {
+               rxreq
+               txresp -status 200 -hdr "foo" "a\tb\xe9c"
+       } -run
+} -start
+
+server s_ctl1 {
+       rxpri
+       stream 0 {
+               txsettings
+               rxsettings
+               txsettings -ack
+       } -run
+
+       stream 1 {
+               rxreq
+               txresp -status 200 -hdr "foo" "a\x01b"
+       } -run
+} -start
+
+server s_ctl2 {
+       rxpri
+       stream 0 {
+               txsettings
+               rxsettings
+               txsettings -ack
+       } -run
+
+       stream 1 {
+               rxreq
+               txresp -status 200 -hdr "foo" "a\x7fb"
+       } -run
+} -start
+
+server s_ctl3 {
+       rxpri
+       stream 0 {
+               txsettings
+               rxsettings
+               txsettings -ack
+       } -run
+
+       stream 1 {
+               rxreq
+               txresp -status 200 -hdr "foo" "abcdefghijklmnopq\x1fb"
+       } -run
+} -start
+
+server s_cl0_ok {
+       rxpri
+       stream 0 {
+               txsettings
+               rxsettings
+               txsettings -ack
+       } -run
+
+       stream 1 {
+               rxreq
+               txresp -status 200 -hdr "content-length" "0"
+       } -run
+} -start
+
+server s_cl0 {
+       rxpri
+       stream 0 {
+               txsettings
+               rxsettings
+               txsettings -ack
+       } -run
+
+       stream 1 {
+               rxreq
+               txresp -status 200 -hdr "content-length" "00"
+       } -run
+} -start
+
+haproxy h1 -conf {
+    global
+    .if feature(THREAD)
+       thread-groups 1
+    .endif
+
+    http-hardening off
+       all off
+
+    http-hardening dup-host
+       reject-duplicate-host-header on
+
+    http-hardening lc-meth
+       reject-lowercase-method on
+
+    http-hardening us-rej
+       reject-underscore-in-header-name on
+
+    http-hardening us-del
+       delete-underscore-in-header-name on
+
+    http-hardening us-both
+       reject-underscore-in-header-name on
+       delete-underscore-in-header-name on
+
+    http-hardening unreg
+       delete-unregistered-header-fields on
+
+    http-hardening ctl
+       reject-ctl-in-header-trailer on
+
+    http-hardening cl0
+       reject-content-length-leading-zero on
+
+    defaults
+       mode http
+       http-reuse never
+       timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+       timeout client  "${HAPROXY_TEST_TIMEOUT-5s}"
+       timeout server  "${HAPROXY_TEST_TIMEOUT-5s}"
+
+    # request side: the frontend replies with what it parsed
+    frontend fe_req
+       bind "fd@${req_off}" proto h2 http-hardening off
+       bind "fd@${req_dup_host}" proto h2 http-hardening dup-host
+       bind "fd@${req_lc_meth}" proto h2 http-hardening lc-meth
+       bind "fd@${req_us_rej}" proto h2 http-hardening us-rej
+       bind "fd@${req_us_del}" proto h2 http-hardening us-del
+       bind "fd@${req_us_both}" proto h2 http-hardening us-both
+       bind "fd@${req_unreg}" proto h2 http-hardening unreg
+       bind "fd@${req_ctl}" proto h2 http-hardening ctl
+       bind "fd@${req_cl0}" proto h2 http-hardening cl0
+       http-request return status 200 hdr x-meth "%[method]" hdr x-hdrs "%[req.hdr_names]" hdr x-foo "%[req.hdr(foo),hex]"
+
+    # response side: one listener per server
+    listen s_off_us
+       bind "fd@${s_off_us}" proto h2 http-hardening off
+       server s ${s_off_us_addr}:${s_off_us_port} proto h2 http-hardening off
+
+    listen s_off_unreg
+       bind "fd@${s_off_unreg}" proto h2 http-hardening off
+       server s ${s_off_unreg_addr}:${s_off_unreg_port} proto h2 http-hardening off
+
+    listen s_off_ctl
+       bind "fd@${s_off_ctl}" proto h2 http-hardening off
+       server s ${s_off_ctl_addr}:${s_off_ctl_port} proto h2 http-hardening off
+
+    listen s_off_cl0
+       bind "fd@${s_off_cl0}" proto h2 http-hardening off
+       server s ${s_off_cl0_addr}:${s_off_cl0_port} proto h2 http-hardening off
+
+    listen s_us_rej_ok
+       bind "fd@${s_us_rej_ok}" proto h2 http-hardening off
+       server s ${s_us_rej_ok_addr}:${s_us_rej_ok_port} proto h2 http-hardening us-rej
+
+    listen s_us_rej
+       bind "fd@${s_us_rej}" proto h2 http-hardening off
+       server s ${s_us_rej_addr}:${s_us_rej_port} proto h2 http-hardening us-rej
+
+    listen s_us_del
+       bind "fd@${s_us_del}" proto h2 http-hardening off
+       server s ${s_us_del_addr}:${s_us_del_port} proto h2 http-hardening us-del
+
+    listen s_us_both
+       bind "fd@${s_us_both}" proto h2 http-hardening off
+       server s ${s_us_both_addr}:${s_us_both_port} proto h2 http-hardening us-both
+
+    listen s_unreg
+       bind "fd@${s_unreg}" proto h2 http-hardening off
+       server s ${s_unreg_addr}:${s_unreg_port} proto h2 http-hardening unreg
+
+    listen s_ctl_ok
+       bind "fd@${s_ctl_ok}" proto h2 http-hardening off
+       server s ${s_ctl_ok_addr}:${s_ctl_ok_port} proto h2 http-hardening ctl
+
+    listen s_ctl1
+       bind "fd@${s_ctl1}" proto h2 http-hardening off
+       server s ${s_ctl1_addr}:${s_ctl1_port} proto h2 http-hardening ctl
+
+    listen s_ctl2
+       bind "fd@${s_ctl2}" proto h2 http-hardening off
+       server s ${s_ctl2_addr}:${s_ctl2_port} proto h2 http-hardening ctl
+
+    listen s_ctl3
+       bind "fd@${s_ctl3}" proto h2 http-hardening off
+       server s ${s_ctl3_addr}:${s_ctl3_port} proto h2 http-hardening ctl
+
+    listen s_cl0_ok
+       bind "fd@${s_cl0_ok}" proto h2 http-hardening off
+       server s ${s_cl0_ok_addr}:${s_cl0_ok_port} proto h2 http-hardening cl0
+
+    listen s_cl0
+       bind "fd@${s_cl0}" proto h2 http-hardening off
+       server s ${s_cl0_addr}:${s_cl0_port} proto h2 http-hardening cl0
+
+} -start
+
+#
+# Requests
+#
+
+# reference: everything is accepted with all checks off
+client c_req_off -connect ${h1_req_off_sock} {
+       txpri
+       stream 0 {
+               txsettings
+               rxsettings
+               txsettings -ack
+               rxsettings
+               expect settings.ack == true
+       } -run
+
+       stream 1 {
+               txreq -req GET -url / -scheme http -hdr ":authority" "a" -hdr "host" "a"
+               rxresp
+               expect resp.status == 200
+               expect resp.http.x-hdrs == "host"
+       } -run
+       stream 3 {
+               txreq -req get -url / -scheme http -hdr ":authority" "a"
+               rxresp
+               expect resp.status == 200
+               expect resp.http.x-meth == "get"
+       } -run
+       stream 5 {
+               txreq -req GET -url / -scheme http -hdr ":authority" "a" -hdr "x_a" "1" -hdr "x-foo" "2"
+               rxresp
+               expect resp.status == 200
+               expect resp.http.x-hdrs == "host,x_a,x-foo"
+       } -run
+       stream 7 {
+               txreq -req GET -url / -scheme http -hdr ":authority" "a" -hdr "foo" "a\x01b"
+               rxresp
+               expect resp.status == 200
+               expect resp.http.x-foo == "610162"
+       } -run
+       stream 9 {
+               txreq -req GET -url / -scheme http -hdr ":authority" "a" -hdr "foo" "a\x7fb"
+               rxresp
+               expect resp.status == 200
+               expect resp.http.x-foo == "617F62"
+       } -run
+       stream 11 {
+               txreq -req POST -url / -scheme http -hdr ":authority" "a" -hdr "content-length" "00"
+               rxresp
+               expect resp.status == 200
+       } -run
+} -run
+
+# without :authority, Host is the only source of the authority
+client c_req_dup_host -connect ${h1_req_dup_host_sock} {
+       txpri
+       stream 0 {
+               txsettings
+               rxsettings
+               txsettings -ack
+               rxsettings
+               expect settings.ack == true
+       } -run
+
+
+       stream 1 {
+               txreq -req GET -url / -scheme http -hdr "host" "a"
+               rxresp
+               expect resp.status == 200
+               expect resp.http.x-hdrs == "host"
+       } -run
+       stream 3 {
+               txreq -req GET -url / -scheme http -hdr "host" "a" -hdr "host" "a"
+               rxrst
+               expect rst.err == PROTOCOL_ERROR
+       } -run
+} -run
+
+# :authority followed by an identical host header is legitimate (RFC9113
+# 8.3.1), it is not a duplicate Host header field.
+client c_req_dup_host2 -connect ${h1_req_dup_host_sock} {
+       txpri
+       stream 0 {
+               txsettings
+               rxsettings
+               txsettings -ack
+               rxsettings
+               expect settings.ack == true
+       } -run
+
+
+       stream 1 {
+               txreq -req GET -url / -scheme http -hdr ":authority" "a" -hdr "host" "a"
+               rxresp
+               expect resp.status == 200
+               expect resp.http.x-hdrs == "host"
+       } -run
+} -run
+
+client c_req_lc_meth -connect ${h1_req_lc_meth_sock} {
+       txpri
+       stream 0 {
+               txsettings
+               rxsettings
+               txsettings -ack
+               rxsettings
+               expect settings.ack == true
+       } -run
+
+       stream 1 {
+               txreq -req GET -url / -scheme http -hdr ":authority" "a"
+               rxresp
+               expect resp.status == 200
+               expect resp.http.x-meth == "GET"
+       } -run
+       stream 3 {
+               txreq -req MY-METH_1 -url / -scheme http -hdr ":authority" "a"
+               rxresp
+               expect resp.status == 200
+               expect resp.http.x-meth == "MY-METH_1"
+       } -run
+       stream 5 {
+               txreq -req gET -url / -scheme http -hdr ":authority" "a"
+               rxresp
+               expect resp.status == 400
+       } -run
+} -run
+
+client c_req_us_rej -connect ${h1_req_us_rej_sock} {
+       txpri
+       stream 0 {
+               txsettings
+               rxsettings
+               txsettings -ack
+               rxsettings
+               expect settings.ack == true
+       } -run
+
+       stream 1 {
+               txreq -req GET -url / -scheme http -hdr ":authority" "a" -hdr "x-a" "_"
+               rxresp
+               expect resp.status == 200
+               expect resp.http.x-hdrs == "host,x-a"
+       } -run
+       stream 3 {
+               txreq -req GET -url / -scheme http -hdr ":authority" "a" -hdr "x-a" "1" -hdr "x_b" "2"
+               rxrst
+               expect rst.err == PROTOCOL_ERROR
+       } -run
+} -run
+
+client c_req_us_del -connect ${h1_req_us_del_sock} {
+       txpri
+       stream 0 {
+               txsettings
+               rxsettings
+               txsettings -ack
+               rxsettings
+               expect settings.ack == true
+       } -run
+
+       stream 1 {
+               txreq -req GET -url / -scheme http -hdr ":authority" "a" -hdr "x_a" "1" -hdr "x-b" "2" -hdr "_c" "3" -hdr "d" "4"
+               rxresp
+               expect resp.status == 200
+               expect resp.http.x-hdrs == "host,x-b,d"
+       } -run
+} -run
+
+client c_req_us_both -connect ${h1_req_us_both_sock} {
+       txpri
+       stream 0 {
+               txsettings
+               rxsettings
+               txsettings -ack
+               rxsettings
+               expect settings.ack == true
+       } -run
+
+       stream 1 {
+               txreq -req GET -url / -scheme http -hdr ":authority" "a" -hdr "x_a" "1"
+               rxrst
+               expect rst.err == PROTOCOL_ERROR
+       } -run
+} -run
+
+client c_req_unreg -connect ${h1_req_unreg_sock} {
+       txpri
+       stream 0 {
+               txsettings
+               rxsettings
+               txsettings -ack
+               rxsettings
+               expect settings.ack == true
+       } -run
+
+       stream 1 {
+               txreq -req GET -url / -scheme http -hdr ":authority" "a" -hdr "x-foo" "1" -hdr "foo" "3" -hdr "xa" "4" -hdr "x" "5" -hdr "a-x-b" "6"
+               rxresp
+               expect resp.status == 200
+               expect resp.http.x-hdrs == "host,foo,xa,x,a-x-b"
+       } -run
+} -run
+
+client c_req_ctl -connect ${h1_req_ctl_sock} {
+       txpri
+       stream 0 {
+               txsettings
+               rxsettings
+               txsettings -ack
+               rxsettings
+               expect settings.ack == true
+       } -run
+
+       stream 1 {
+               txreq -req GET -url / -scheme http -hdr ":authority" "a" -hdr "foo" "a\tb c\xe9d"
+               rxresp
+               expect resp.status == 200
+               expect resp.http.x-foo == "6109622063E964"
+       } -run
+       stream 3 {
+               txreq -req GET -url / -scheme http -hdr ":authority" "a" -hdr "foo" "a\x01b"
+               rxrst
+               expect rst.err == PROTOCOL_ERROR
+       } -run
+       stream 5 {
+               txreq -req GET -url / -scheme http -hdr ":authority" "a" -hdr "foo" "a\x7fb"
+               rxrst
+               expect rst.err == PROTOCOL_ERROR
+       } -run
+       stream 7 {
+               txreq -req GET -url / -scheme http -hdr ":authority" "a" -hdr "foo" "abcdefghijklmnopq\x1fb"
+               rxrst
+               expect rst.err == PROTOCOL_ERROR
+       } -run
+} -run
+
+client c_req_cl0 -connect ${h1_req_cl0_sock} {
+       txpri
+       stream 0 {
+               txsettings
+               rxsettings
+               txsettings -ack
+               rxsettings
+               expect settings.ack == true
+       } -run
+
+       stream 1 {
+               txreq -req POST -url / -scheme http -hdr ":authority" "a" -hdr "content-length" "0"
+               rxresp
+               expect resp.status == 200
+       } -run
+       stream 3 {
+               txreq -req POST -url / -scheme http -hdr ":authority" "a" -hdr "content-length" "00"
+               rxrst
+               expect rst.err == PROTOCOL_ERROR
+       } -run
+} -run
+
+#
+# Responses
+#
+
+client c_s_off_us -connect ${h1_s_off_us_sock} {
+       txpri
+       stream 0 {
+               txsettings
+               rxsettings
+               txsettings -ack
+               rxsettings
+               expect settings.ack == true
+       } -run
+
+       stream 1 {
+               txreq -req GET -url / -scheme http -hdr ":authority" "a"
+               rxresp
+               expect resp.status == 200
+               expect resp.http.x_a == "1"
+       } -run
+} -run
+
+client c_s_off_unreg -connect ${h1_s_off_unreg_sock} {
+       txpri
+       stream 0 {
+               txsettings
+               rxsettings
+               txsettings -ack
+               rxsettings
+               expect settings.ack == true
+       } -run
+
+       stream 1 {
+               txreq -req GET -url / -scheme http -hdr ":authority" "a"
+               rxresp
+               expect resp.status == 200
+               expect resp.http.x-foo == "1"
+       } -run
+} -run
+
+client c_s_off_ctl -connect ${h1_s_off_ctl_sock} {
+       txpri
+       stream 0 {
+               txsettings
+               rxsettings
+               txsettings -ack
+               rxsettings
+               expect settings.ack == true
+       } -run
+
+       stream 1 {
+               txreq -req GET -url / -scheme http -hdr ":authority" "a"
+               rxresp
+               expect resp.status == 200
+       } -run
+} -run
+
+client c_s_off_cl0 -connect ${h1_s_off_cl0_sock} {
+       txpri
+       stream 0 {
+               txsettings
+               rxsettings
+               txsettings -ack
+               rxsettings
+               expect settings.ack == true
+       } -run
+
+       stream 1 {
+               txreq -req GET -url / -scheme http -hdr ":authority" "a"
+               rxresp
+               expect resp.status == 200
+       } -run
+} -run
+
+client c_s_us_rej_ok -connect ${h1_s_us_rej_ok_sock} {
+       txpri
+       stream 0 {
+               txsettings
+               rxsettings
+               txsettings -ack
+               rxsettings
+               expect settings.ack == true
+       } -run
+
+       stream 1 {
+               txreq -req GET -url / -scheme http -hdr ":authority" "a"
+               rxresp
+               expect resp.status == 200
+               expect resp.http.x-b == "2"
+       } -run
+} -run
+
+client c_s_us_rej -connect ${h1_s_us_rej_sock} {
+       txpri
+       stream 0 {
+               txsettings
+               rxsettings
+               txsettings -ack
+               rxsettings
+               expect settings.ack == true
+       } -run
+
+       stream 1 {
+               txreq -req GET -url / -scheme http -hdr ":authority" "a"
+               rxresp
+               expect resp.status == 502
+       } -run
+} -run
+
+client c_s_us_del -connect ${h1_s_us_del_sock} {
+       txpri
+       stream 0 {
+               txsettings
+               rxsettings
+               txsettings -ack
+               rxsettings
+               expect settings.ack == true
+       } -run
+
+       stream 1 {
+               txreq -req GET -url / -scheme http -hdr ":authority" "a"
+               rxresp
+               expect resp.status == 200
+               expect resp.http.x_a == <undef>
+               expect resp.http.x-b == "2"
+       } -run
+} -run
+
+client c_s_us_both -connect ${h1_s_us_both_sock} {
+       txpri
+       stream 0 {
+               txsettings
+               rxsettings
+               txsettings -ack
+               rxsettings
+               expect settings.ack == true
+       } -run
+
+       stream 1 {
+               txreq -req GET -url / -scheme http -hdr ":authority" "a"
+               rxresp
+               expect resp.status == 502
+       } -run
+} -run
+
+client c_s_unreg -connect ${h1_s_unreg_sock} {
+       txpri
+       stream 0 {
+               txsettings
+               rxsettings
+               txsettings -ack
+               rxsettings
+               expect settings.ack == true
+       } -run
+
+       stream 1 {
+               txreq -req GET -url / -scheme http -hdr ":authority" "a"
+               rxresp
+               expect resp.status == 200
+               expect resp.http.x-foo == <undef>
+               expect resp.http.foo == "2"
+               expect resp.http.xa == "3"
+       } -run
+} -run
+
+client c_s_ctl_ok -connect ${h1_s_ctl_ok_sock} {
+       txpri
+       stream 0 {
+               txsettings
+               rxsettings
+               txsettings -ack
+               rxsettings
+               expect settings.ack == true
+       } -run
+
+       stream 1 {
+               txreq -req GET -url / -scheme http -hdr ":authority" "a"
+               rxresp
+               expect resp.status == 200
+       } -run
+} -run
+
+client c_s_ctl1 -connect ${h1_s_ctl1_sock} {
+       txpri
+       stream 0 {
+               txsettings
+               rxsettings
+               txsettings -ack
+               rxsettings
+               expect settings.ack == true
+       } -run
+
+       stream 1 {
+               txreq -req GET -url / -scheme http -hdr ":authority" "a"
+               rxresp
+               expect resp.status == 502
+       } -run
+} -run
+
+client c_s_ctl2 -connect ${h1_s_ctl2_sock} {
+       txpri
+       stream 0 {
+               txsettings
+               rxsettings
+               txsettings -ack
+               rxsettings
+               expect settings.ack == true
+       } -run
+
+       stream 1 {
+               txreq -req GET -url / -scheme http -hdr ":authority" "a"
+               rxresp
+               expect resp.status == 502
+       } -run
+} -run
+
+client c_s_ctl3 -connect ${h1_s_ctl3_sock} {
+       txpri
+       stream 0 {
+               txsettings
+               rxsettings
+               txsettings -ack
+               rxsettings
+               expect settings.ack == true
+       } -run
+
+       stream 1 {
+               txreq -req GET -url / -scheme http -hdr ":authority" "a"
+               rxresp
+               expect resp.status == 502
+       } -run
+} -run
+
+client c_s_cl0_ok -connect ${h1_s_cl0_ok_sock} {
+       txpri
+       stream 0 {
+               txsettings
+               rxsettings
+               txsettings -ack
+               rxsettings
+               expect settings.ack == true
+       } -run
+
+       stream 1 {
+               txreq -req GET -url / -scheme http -hdr ":authority" "a"
+               rxresp
+               expect resp.status == 200
+       } -run
+} -run
+
+client c_s_cl0 -connect ${h1_s_cl0_sock} {
+       txpri
+       stream 0 {
+               txsettings
+               rxsettings
+               txsettings -ack
+               rxsettings
+               expect settings.ack == true
+       } -run
+
+       stream 1 {
+               txreq -req GET -url / -scheme http -hdr ":authority" "a"
+               rxresp
+               expect resp.status == 502
+       } -run
+} -run