]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: mux_h2: Handle others remaining read0 cases on partial frames
authorChristopher Faulet <cfaulet@haproxy.com>
Fri, 8 Oct 2021 06:56:00 +0000 (08:56 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Fri, 8 Oct 2021 07:17:27 +0000 (09:17 +0200)
We've found others places where the read0 is ignored because of an
incomplete frame parsing. This time, it happens during parsing of
CONTINUATION frames.

When frames are parsed, incomplete frames are properly handled and
H2_CF_DEM_SHORT_READ flag is set. It is also true for HEADERS
frames. However, for CONTINUATION frames, there is an exception. Besides
parsing the current frame, we try to peek header of the next one to merge
payload of both frames, the current one and the next one. Idea is to create
a sole HEADERS frame before parsing the payload. However, in this case, it
is possible to have an incomplete frame too, not the current one but the
next one. From the demux point of view, the current frame is complete. We
must go to the internal function h2c_decode_headers() to detect an
incomplete frame. And this case was not identified and fixed when
H2_CF_DEM_SHORT_READ flag was introduced in the commit b5f7b5296
("BUG/MEDIUM: mux-h2: Handle remaining read0 cases on partial frames")

This bug was reported in a comment of the issue #1362. The patch must be
backported as far as 2.0.

src/mux_h2.c

index ce56058b155dd242453fd7ef53b3e44d87692dfb..150a559067fc8eaba0fc79270ea7ab4a9fc10788 100644 (file)
@@ -2668,8 +2668,12 @@ static struct h2s *h2c_frt_handle_headers(struct h2c *h2c, struct h2s *h2s)
                        if (h2c->st0 >= H2_CS_ERROR)
                                goto out;
 
-                       if (error == 0)
+                       if (error == 0) {
+                               /* Demux not blocked because of the stream, it is an incomplete frame */
+                               if (!(h2c->flags &H2_CF_DEM_BLOCK_ANY))
+                                       h2c->flags |= H2_CF_DEM_SHORT_READ;
                                goto out; // missing data
+                       }
 
                        if (error < 0) {
                                /* Failed to decode this frame (e.g. too large request)
@@ -2706,8 +2710,12 @@ static struct h2s *h2c_frt_handle_headers(struct h2c *h2c, struct h2s *h2s)
                goto out;
 
        if (error <= 0) {
-               if (error == 0)
+               if (error == 0) {
+                       /* Demux not blocked because of the stream, it is an incomplete frame */
+                       if (!(h2c->flags &H2_CF_DEM_BLOCK_ANY))
+                               h2c->flags |= H2_CF_DEM_SHORT_READ;
                        goto out; // missing data
+               }
 
                /* Failed to decode this stream (e.g. too large request)
                 * but the HPACK decompressor is still synchronized.
@@ -2825,8 +2833,12 @@ static struct h2s *h2c_bck_handle_headers(struct h2c *h2c, struct h2s *h2s)
        }
 
        if (error <= 0) {
-               if (error == 0)
+               if (error == 0) {
+                       /* Demux not blocked because of the stream, it is an incomplete frame */
+                       if (!(h2c->flags &H2_CF_DEM_BLOCK_ANY))
+                               h2c->flags |= H2_CF_DEM_SHORT_READ;
                        goto fail; // missing data
+               }
 
                /* stream error : send RST_STREAM */
                TRACE_ERROR("couldn't decode response HEADERS", H2_EV_RX_FRAME|H2_EV_RX_HDR, h2c->conn, h2s);