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.
This commit is contained in:
Christopher Faulet 2020-12-02 14:26:36 +01:00
parent f3e7619041
commit 7d247f0771
3 changed files with 17 additions and 1 deletions

View 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)

View File

@ -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

View 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;