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.
txresp \
-status 200
} -run
-} -repeat 4 -start
+} -repeat 2 -start
# http2 server without support for RFC8441
server srv_h2_no_ws {
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
} -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
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
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
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
/* 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 */