From: Christopher Faulet Date: Mon, 7 Dec 2020 17:24:43 +0000 (+0100) Subject: BUG/MINOR: h2/mux-h2: Reject 101 responses with a PROTOCOL_ERROR h2s error X-Git-Tag: v2.4-dev7~106 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=8989942cfc642a728233e575f9c6b1bf0890b411;p=thirdparty%2Fhaproxy.git BUG/MINOR: h2/mux-h2: Reject 101 responses with a PROTOCOL_ERROR h2s error As stated in the RFC7540, section 8.1.1, the HTTP/2 removes support for the 101 informational status code. Thus a PROTOCOL_ERROR is now returned to the server if a 101-switching-protocols response is received. Thus, the server connection is aborted. This patch may be backported as far as 2.0. --- diff --git a/src/h2.c b/src/h2.c index 6684610865..a50c15c7fb 100644 --- a/src/h2.c +++ b/src/h2.c @@ -517,7 +517,7 @@ int h2_make_htx_request(struct http_hdr *list, struct htx *htx, unsigned int *ms */ static struct htx_sl *h2_prepare_htx_stsline(uint32_t fields, struct ist *phdr, struct htx *htx, unsigned int *msgf) { - unsigned int flags = HTX_SL_F_NONE; + unsigned int status, flags = HTX_SL_F_NONE; struct htx_sl *sl; unsigned char h, t, u; @@ -528,33 +528,33 @@ static struct htx_sl *h2_prepare_htx_stsline(uint32_t fields, struct ist *phdr, if (phdr[H2_PHDR_IDX_STAT].len != 3) goto fail; - /* Set HTX start-line flags */ - flags |= HTX_SL_F_VER_11; // V2 in fact - flags |= HTX_SL_F_XFER_LEN; // xfer len always known with H2 - - sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, ist("HTTP/2.0"), phdr[H2_PHDR_IDX_STAT], ist("")); - if (!sl) - goto fail; - h = phdr[H2_PHDR_IDX_STAT].ptr[0] - '0'; t = phdr[H2_PHDR_IDX_STAT].ptr[1] - '0'; u = phdr[H2_PHDR_IDX_STAT].ptr[2] - '0'; if (h > 9 || t > 9 || u > 9) goto fail; + status = h * 100 + t * 10 + u; - sl->info.res.status = h * 100 + t * 10 + u; - - /* On 1xx responses (except 101) 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. + /* 101 responses are not supported in H2, so return a error. + * 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. */ - if (sl->info.res.status < 200 && - (sl->info.res.status == 100 || sl->info.res.status >= 102)) { + if (status == 101) + goto fail; + else if (status < 200) { *msgf |= H2_MSGF_RSP_1XX; *msgf &= ~H2_MSGF_BODY; } + /* Set HTX start-line flags */ + flags |= HTX_SL_F_VER_11; // V2 in fact + flags |= HTX_SL_F_XFER_LEN; // xfer len always known with H2 + + sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, ist("HTTP/2.0"), phdr[H2_PHDR_IDX_STAT], ist("")); + if (!sl) + goto fail; + sl->info.res.status = status; return sl; fail: return NULL; diff --git a/src/mux_h2.c b/src/mux_h2.c index 39d9016504..ed42859f0a 100644 --- a/src/mux_h2.c +++ b/src/mux_h2.c @@ -4892,6 +4892,11 @@ static size_t h2s_frt_make_resp_headers(struct h2s *h2s, struct htx *htx) 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; } + else if (h2s->status == 101) { + /* 101 responses are not supported in H2, so return a error (RFC7540#8.1.1) */ + 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; + } /* and the rest of the headers, that we dump starting at header 0 */ hdr = 0; @@ -5000,8 +5005,7 @@ static size_t h2s_frt_make_resp_headers(struct h2s *h2s, struct htx *htx) * FIXME: we should also set it when we know for sure that the * content-length is zero as well as on 204/304 */ - if (blk_end && htx_get_blk_type(blk_end) == HTX_BLK_EOM && - (h2s->status >= 200 || h2s->status == 101)) + if (blk_end && htx_get_blk_type(blk_end) == HTX_BLK_EOM && h2s->status >= 200) es_now = 1; if (!h2s->cs || h2s->cs->flags & CS_FL_SHW) @@ -5017,7 +5021,7 @@ static size_t h2s_frt_make_resp_headers(struct h2s *h2s, struct htx *htx) /* indicates the HEADERS frame was sent, except for 1xx responses. For * 1xx responses, another HEADERS frame is expected. */ - if (h2s->status >= 200 || h2s->status == 101) + if (h2s->status >= 200) h2s->flags |= H2_SF_HEADERS_SENT; if (es_now) {