]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MINOR: h2/mux-h2: Reject 101 responses with a PROTOCOL_ERROR h2s error
authorChristopher Faulet <cfaulet@haproxy.com>
Mon, 7 Dec 2020 17:24:43 +0000 (18:24 +0100)
committerChristopher Faulet <cfaulet@haproxy.com>
Thu, 28 Jan 2021 15:36:40 +0000 (16:36 +0100)
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.

src/h2.c
src/mux_h2.c

index 66846108653484823d013bda1a12692b2a48f538..a50c15c7fb797c98c18af51641cdbb13527025a7 100644 (file)
--- 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;
index 39d9016504fdae6179af888ef1234457c69d423e..ed42859f0a46e1b907a314c021d1cfa4cbcf215e 100644 (file)
@@ -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) {