]> git.kaiwu.me - haproxy.git/commitdiff
BUG/MEDIUM: mux-h2: fix the detection of the ext connect support
authorWilly Tarreau <w@1wt.eu>
Thu, 7 May 2026 15:15:06 +0000 (17:15 +0200)
committerWilly Tarreau <w@1wt.eu>
Thu, 7 May 2026 15:34:39 +0000 (17:34 +0200)
As reported by Huangbin Zhan (@zhanhb) in github issue #3355, latest
commit 96f7ff4fdd ("MINOR: mux-h2: add a new message flag to indicate
ext connect support") was not correct and can break RFC8441-compliant
clients, as it did for them with a variant of Chrome 142.

The problem is that while RFC9113 says that new pseudo-headers are only
permitted with *negotiated* extensions, and RFC8441 doesn't indicate
whether or not SETTINGS_ENABLE_CONNECT_PROTOCOL is needed from clients,
it only says that clients know that servers support the extension when
seeing it in their settings and can use it, which seems to imply that
they don't need to send it to indicate their willingness to use it.
This also means that the server cannot know if a client is expected to
use it or not by default. It only know that a client is not allowed to
use it if the server didn't emit support mentioning it, which haproxy
can do using h2-workaround-bogus-websocket-clients.

Thus the fix proposed by @zhanhb is right, when presetting the flag for
the parser to indicate whether or not we're willing to accept RFC8441's
:protocol pseudo-header, we should:
  - consider the received setting on the backend side (though the
    pseudo-header is neither used nor supported there, but at least
    we pass the info regarding the support of the extension)
  - consider the configuration for the frontend (since it's the only
    place where we can decide on support or not)

This patch does just that and reverts the accompanying changes to the
regtests that made them want to see the client's setting. It must be
backported to 2.6.

In the mean time, placing this option in the global section will force
the clients to downgrade to h1:

    h2-workaround-bogus-websocket-clients

Many thanks again to @zhanbb this feedback and proposing a tested fix.

reg-tests/http-messaging/protocol_upgrade.vtc
reg-tests/http-messaging/websocket.vtc
src/mux_h2.c

index 3cd0f4cb0b78a6b47cf9a6acc21a5244903f42f6..2fe65e7173e777fe0b7a7b4de8e7791bf8dc57d8 100644 (file)
@@ -72,7 +72,7 @@ server srv_h2 {
                txresp \
                  -status 200
        } -run
-} -repeat 4 -start
+} -repeat 2 -start
 
 # http2 server without support for RFC8441
 server srv_h2_no_ws {
@@ -219,8 +219,7 @@ client c1_h1_h2 -connect ${hap_frt_h1_h2_sock} {
 client c2_h2 -connect ${hap_frt_h2_sock} {
        txpri
        stream 0 {
-               # manually send RFC8441 SETTINGS_ENABLE_CONNECT_PROTOCOL
-               sendhex "00 00 06 04   00    00 00 00 00    00 08   00 00 00 01"
+               txsettings
                rxsettings
                txsettings -ack
                rxsettings
@@ -242,62 +241,11 @@ client c2_h2 -connect ${hap_frt_h2_sock} {
        } -run
 } -run
 
-# connect to h2 server frontend without extension: must fail
-client c2_h2_rej1 -connect ${hap_frt_h2_sock} {
-       txpri
-       stream 0 {
-               # no extension sent
-               txsettings
-               rxsettings
-               txsettings -ack
-               rxsettings
-               expect settings.ack == true
-       } -run
-
-       stream 1 {
-               txreq \
-                 -req "CONNECT" \
-                 -scheme "http" \
-                 -url "/" \
-                 -hdr ":authority" "127.0.0.1" \
-                 -hdr ":protocol" "custom_protocol" \
-                 -nostrend
-
-               rxrst
-       } -run
-} -run
-
-# connect to h2 server with ext but :proto with bad method: must fail
-client c2_h2_rej2 -connect ${hap_frt_h2_sock} {
-       txpri
-       stream 0 {
-               # manually send RFC8441 SETTINGS_ENABLE_CONNECT_PROTOCOL
-               sendhex "00 00 06 04   00    00 00 00 00    00 08   00 00 00 01"
-               rxsettings
-               txsettings -ack
-               rxsettings
-               expect settings.ack == true
-       } -run
-
-       stream 1 {
-               txreq \
-                 -req "GET" \
-                 -scheme "http" \
-                 -url "/" \
-                 -hdr ":authority" "127.0.0.1" \
-                 -hdr ":protocol" "custom_protocol" \
-                 -nostrend
-
-               rxrst
-       } -run
-} -run
-
 # connect to h2 translation frontend
 client c3_h2_h1 -connect ${hap_frt_h2_h1_sock} {
        txpri
        stream 0 {
-               # manually send RFC8441 SETTINGS_ENABLE_CONNECT_PROTOCOL
-               sendhex "00 00 06 04   00    00 00 00 00    00 08   00 00 00 01"
+               txsettings
                rxsettings
                txsettings -ack
                rxsettings
@@ -391,8 +339,7 @@ client c8_h2c -connect ${hap_frt_h1_h2c_sock} {
 client c9_h2c -connect ${hap_frt_h2_h1_sock} {
        txpri
        stream 0 {
-               # manually send RFC8441 SETTINGS_ENABLE_CONNECT_PROTOCOL
-               sendhex "00 00 06 04   00    00 00 00 00    00 08   00 00 00 01"
+               txsettings
                rxsettings
                txsettings -ack
                rxsettings
index b82f5a3185fa9c994435b16e8ee7b1c0c02717c3..9567ea577de6478a3665c640f107baa901946fa6 100644 (file)
@@ -177,8 +177,7 @@ client c3 -connect ${hap_fe2_sock} {
 client c4 -connect ${hap_fe3_sock} {
        txpri
        stream 0 {
-               # manually send RFC8441 SETTINGS_ENABLE_CONNECT_PROTOCOL
-               sendhex "00 00 06 04   00    00 00 00 00    00 08   00 00 00 01"
+               txsettings
                rxsettings
                txsettings -ack
                rxsettings
@@ -206,8 +205,7 @@ client c4 -connect ${hap_fe3_sock} {
 client c5 -connect ${hap_fe4_sock} {
        txpri
        stream 0 {
-               # manually send RFC8441 SETTINGS_ENABLE_CONNECT_PROTOCOL
-               sendhex "00 00 06 04   00    00 00 00 00    00 08   00 00 00 01"
+               txsettings
                rxsettings
                txsettings -ack
                rxsettings
index a04fa8f90459e531963028c9fe8a9e8068759deb..9720ae99c1302bc76119dcf2bd4bb7573745f463 100644 (file)
@@ -6286,8 +6286,16 @@ next_frame:
        /* If an Extended CONNECT has been sent on this stream, set message flag
         * to convert 200 response to 101 htx response. We only support this if
         * the connection supports RFC8441.
+        * On the backend, that means the origin server advertised the setting.
+        * On the frontend, RFC 8441 ยง3 only requires the server (us) to
+        * advertise it; clients are not required to echo it back. Use whether
+        * we ourselves advertised it as the gate.
         */
-       msgf |= (h2c->flags & H2_CF_RCVD_RFC8441) ? H2_MSGF_EXT_CONN_OK : 0;
+       if (h2c->flags & H2_CF_IS_BACK)
+               msgf |= (h2c->flags & H2_CF_RCVD_RFC8441) ? H2_MSGF_EXT_CONN_OK : 0;
+       else if (!(global.tune.options & GTUNE_DISABLE_H2_WEBSOCKET))
+               msgf |= H2_MSGF_EXT_CONN_OK;
+
        msgf |= (*flags & H2_SF_EXT_CONNECT_SENT) ? H2_MSGF_EXT_CONNECT: 0;
 
        /* when dealing with trailers, we need to check the content-length */