]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: h2/mux-h2: Add flags to notify the response is known to have no body
authorChristopher Faulet <cfaulet@haproxy.com>
Wed, 2 Dec 2020 13:26:36 +0000 (14:26 +0100)
committerChristopher Faulet <cfaulet@haproxy.com>
Thu, 28 Jan 2021 15:37:14 +0000 (16:37 +0100)
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.

include/haproxy/h2.h
src/h2.c
src/mux_h2.c

index e4eaccafef49f2df040db173f4bfa402aff03742..45c3d8f10386bf07d4954a95e2d71bb1cf4d9d4f 100644 (file)
@@ -177,6 +177,8 @@ enum h2_err {
 #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)
index 3ff4b4d73c7db98367fc22c4cbae7422e49e26b2..a4279d32447464176d29b0d669e5c419589921b1 100644 (file)
--- a/src/h2.c
+++ b/src/h2.c
@@ -294,6 +294,8 @@ static struct htx_sl *h2_prepare_htx_reqline(uint32_t fields, struct ist *phdr,
                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 @@ static struct htx_sl *h2_prepare_htx_stsline(uint32_t fields, struct ist *phdr,
         * 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 @@ static struct htx_sl *h2_prepare_htx_stsline(uint32_t fields, struct ist *phdr,
                *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
index 31760c9725b5eac2ed14b54abe3ef75542b476ce..93fb99c3aec381dc41b46b836a182e3aeeebfbba 100644 (file)
@@ -179,7 +179,7 @@ enum h2_ss {
 
 /* 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 @@ next_frame:
                        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 @@ static size_t h2s_frt_make_resp_headers(struct h2s *h2s, struct htx *htx)
                        }
                        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 @@ static size_t h2s_bck_make_req_headers(struct h2s *h2s, struct htx *htx)
                        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;