MINOR: h2/mux-h2: Add flags to notify the response is known to have no body
The H2 message flag H2_MSGF_BODYLESS_RSP is now used during the request or
the response parsing to notify the mux that, considering the parsed message,
the response is known to have no body. This happens during HEAD requests
parsing and during 204/304 responses parsing.
On the H2 multiplexer, the equivalent flag is set on H2 streams. Thus the
H2_SF_BODYLESS_RESP flag is set on a H2 stream if the H2_MSGF_BODYLESS_RSP
is found after a HEADERS frame parsing. Conversely, this flag is also set
when a HEADERS frame is emitted for HEAD requests and for 204/304 responses.
The H2_SF_BODYLESS_RESP flag will be used to ignore data payload from the
response but not the trailers.
diff --git a/include/haproxy/h2.h b/include/haproxy/h2.h
index e4eacca..45c3d8f 100644
--- a/include/haproxy/h2.h
+++ b/include/haproxy/h2.h
@@ -177,6 +177,8 @@
#define H2_MSGF_BODY_CL 0x0002 // content-length is present
#define H2_MSGF_BODY_TUNNEL 0x0004 // a tunnel is in use (CONNECT)
#define H2_MSGF_RSP_1XX 0x0010 // a 1xx ( != 101) HEADERS frame was received
+#define H2_MSGF_BODYLESS_RSP 0x0020 // response message is known to have no body
+ // (response to HEAD request or 204/304 response)
#define H2_MAX_STREAM_ID ((1U << 31) - 1)
#define H2_MAX_FRAME_LEN ((1U << 24) - 1)
diff --git a/src/h2.c b/src/h2.c
index 3ff4b4d..a4279d3 100644
--- a/src/h2.c
+++ b/src/h2.c
@@ -294,6 +294,8 @@
goto fail;
sl->info.req.meth = find_http_meth(phdr[H2_PHDR_IDX_METH].ptr, phdr[H2_PHDR_IDX_METH].len);
+ if (sl->info.req.meth == HTTP_METH_HEAD)
+ *msgf |= H2_MSGF_BODYLESS_RSP;
return sl;
fail:
return NULL;
@@ -547,6 +549,8 @@
* On 1xx responses there is no ES on the HEADERS frame but there is no
* body. So remove the flag H2_MSGF_BODY and add H2_MSGF_RSP_1XX to
* notify the decoder another HEADERS frame is expected.
+ * 204/304 resposne have no body by definition. So remove the flag
+ * H2_MSGF_BODY and set H2_MSGF_BODYLESS_RSP.
*/
if (status == 101)
goto fail;
@@ -554,6 +558,10 @@
*msgf |= H2_MSGF_RSP_1XX;
*msgf &= ~H2_MSGF_BODY;
}
+ else if (sl->info.res.status == 204 || sl->info.res.status == 304) {
+ *msgf &= ~H2_MSGF_BODY;
+ *msgf |= H2_MSGF_BODYLESS_RSP;
+ }
/* Set HTX start-line flags */
flags |= HTX_SL_F_VER_11; // V2 in fact
diff --git a/src/mux_h2.c b/src/mux_h2.c
index 31760c9..93fb99c 100644
--- a/src/mux_h2.c
+++ b/src/mux_h2.c
@@ -179,7 +179,7 @@
/* stream flags indicating how data is supposed to be sent */
#define H2_SF_DATA_CLEN 0x00000100 // data sent using content-length
-/* unused flags: 0x00000200 */
+#define H2_SF_BODYLESS_RESP 0x00000200 /* Bodyless response message */
#define H2_SF_BODY_TUNNEL 0x00000400 // Attempt to establish a Tunnelled stream (the result depends on the status code)
@@ -4701,6 +4701,8 @@
htx->extra = *body_len;
}
}
+ if (msgf & H2_MSGF_BODYLESS_RSP)
+ *flags |= H2_SF_BODYLESS_RESP;
if (msgf & H2_MSGF_BODY_TUNNEL)
*flags |= H2_SF_BODY_TUNNEL;
@@ -4942,6 +4944,8 @@
}
sl = htx_get_blk_ptr(htx, blk);
h2s->status = sl->info.res.status;
+ if (h2s->status == 204 || h2s->status == 304)
+ h2s->flags |= H2_SF_BODYLESS_RESP;
if (h2s->status < 100 || h2s->status > 999) {
TRACE_ERROR("will not encode an invalid status code", H2_EV_TX_FRAME|H2_EV_TX_HDR|H2_EV_H2S_ERR, h2c->conn, h2s);
goto fail;
@@ -5165,6 +5169,8 @@
sl = htx_get_blk_ptr(htx, blk);
meth = htx_sl_req_meth(sl);
uri = htx_sl_req_uri(sl);
+ if (sl->info.req.meth == HTTP_METH_HEAD)
+ h2s->flags |= H2_SF_BODYLESS_RESP;
if (unlikely(uri.len == 0)) {
TRACE_ERROR("no URI in HTX request", H2_EV_TX_FRAME|H2_EV_TX_HDR|H2_EV_H2S_ERR, h2c->conn, h2s);
goto fail;