]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: mux-h1: Add a BUSY mode to not loop on pipelinned requests
authorChristopher Faulet <cfaulet@haproxy.com>
Mon, 10 Dec 2018 10:56:47 +0000 (11:56 +0100)
committerWilly Tarreau <w@1wt.eu>
Mon, 10 Dec 2018 19:50:19 +0000 (20:50 +0100)
When a request is fully processed, no more data are parsed until the response is
totally processed and a new transaction starts. But during this time, the mux is
trying to read more data and subscribes to read. If requests are pipelined, we
start to receive the next requests which will stay in the input buffer, leading
to a loop consuming all the CPU. This loop ends when the transaction ends. To
avoid this loop, the flag H1C_F_IN_BUSY has been added. It is set when the
request is fully parsed and unset when the transaction ends. Once set on H1C, it
blocks the reads. So the mux never tries to receive more data in this state.

src/mux_h1.c

index e29e235c77ba59776a4e84075fecda88a9a810f1..f7026c9c56a527e38178d5371836cff4275eed8f 100644 (file)
@@ -38,6 +38,7 @@
 /* Flags indicating why reading input data are blocked. */
 #define H1C_F_IN_ALLOC       0x00000010 /* mux is blocked on lack of input buffer */
 #define H1C_F_IN_FULL        0x00000020 /* mux is blocked on input buffer full */
+#define H1C_F_IN_BUSY        0x00000040
 /* 0x00000040 - 0x00000800 unused */
 
 #define H1C_F_CS_ERROR       0x00001000 /* connection must be closed ASAP because an error occurred */
@@ -136,7 +137,7 @@ static inline int h1_recv_allowed(const struct h1c *h1c)
             conn_xprt_read0_pending(h1c->conn)))
                return 0;
 
-       if (!(h1c->flags & (H1C_F_IN_ALLOC|H1C_F_IN_FULL)))
+       if (!(h1c->flags & (H1C_F_IN_ALLOC|H1C_F_IN_FULL|H1C_F_IN_BUSY)))
                return 1;
 
        return 0;
@@ -319,6 +320,7 @@ static void h1s_destroy(struct h1s *h1s)
                if (h1s->send_wait != NULL)
                        h1s->send_wait->wait_reason &= ~SUB_CAN_SEND;
 
+               h1c->flags &= ~H1C_F_IN_BUSY;
                h1c->flags |= H1C_F_WAIT_NEXT_REQ;
                if (h1s->flags & (H1S_F_REQ_ERROR|H1S_F_RES_ERROR))
                        h1c->flags |= H1C_F_CS_ERROR;
@@ -1203,6 +1205,7 @@ static void h1_sync_messages(struct h1c *h1c)
                 */
                h1m_init_res(&h1s->res);
                h1s->res.flags |= H1_MF_NO_PHDR;
+               h1c->flags &= ~H1C_F_IN_BUSY;
        }
        else if (!b_data(&h1c->obuf) &&
                 h1s->req.state == H1_MSG_DONE && h1s->res.state == H1_MSG_DONE) {
@@ -1211,6 +1214,7 @@ static void h1_sync_messages(struct h1c *h1c)
                        h1m_init_res(&h1s->res);
                        h1s->req.state = H1_MSG_TUNNEL;
                        h1s->res.state = H1_MSG_TUNNEL;
+                       h1c->flags &= ~H1C_F_IN_BUSY;
                }
        }
 }
@@ -1262,8 +1266,10 @@ static size_t h1_process_input(struct h1c *h1c, struct buffer *buf, int flags)
                        if (!ret)
                                break;
                }
-               else if (h1m->state == H1_MSG_DONE)
+               else if (h1m->state == H1_MSG_DONE) {
+                       h1c->flags |= H1C_F_IN_BUSY;
                        break;
+               }
                else if (h1m->state == H1_MSG_TUNNEL) {
                        ret = h1_process_data(h1s, h1m, htx, &h1c->ibuf, &total, count, buf);
                        htx = htx_from_buf(buf);