diff --git a/include/haproxy/h2.h b/include/haproxy/h2.h index e4eaccafe..45c3d8f10 100644 --- a/include/haproxy/h2.h +++ b/include/haproxy/h2.h @@ -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) diff --git a/src/h2.c b/src/h2.c index 3ff4b4d73..a4279d324 100644 --- 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 diff --git a/src/mux_h2.c b/src/mux_h2.c index 31760c972..93fb99c3a 100644 --- a/src/mux_h2.c +++ b/src/mux_h2.c @@ -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;