From cf56b99d0f6790c5b3ae857f4a1975fb6e06a6d7 Mon Sep 17 00:00:00 2001 From: Christopher Faulet Date: Tue, 11 Dec 2018 16:12:31 +0100 Subject: [PATCH] BUG/MEDIUM: mux-h1: Fix loop if server closes its connection with unparsed data A first patch was pushed to fix this bug if it happens during the headers parsing. But it is also possible to hit the bug during the parsing of chunks. For instance, if the server sends only part of the trailers, some data remains unparsed. So it the server closes its connection without sending the end of the response, we fall back again into an infinite loop. The fix contains in 2 parts. First, we block the receive if a read0 or an error is detected on the connection, independently if the input buffer is empty or not. Then, the flags CS_FL_RCV_MORE and CL_FL_WANT_ROOM are always reset when input data are processed. We set them again only when necessary. --- src/mux_h1.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/mux_h1.c b/src/mux_h1.c index 5ca3c28a0..dfe9fd4b3 100644 --- a/src/mux_h1.c +++ b/src/mux_h1.c @@ -131,10 +131,10 @@ static void h1_shutw_conn(struct connection *conn); */ static inline int h1_recv_allowed(const struct h1c *h1c) { - if (b_data(&h1c->ibuf) == 0 && - (h1c->flags & (H1C_F_CS_ERROR|H1C_F_CS_SHUTW) || - h1c->conn->flags & CO_FL_ERROR || - conn_xprt_read0_pending(h1c->conn))) + if (b_data(&h1c->ibuf) == 0 && (h1c->flags & (H1C_F_CS_ERROR|H1C_F_CS_SHUTW))) + return 0; + + if (h1c->conn->flags & CO_FL_ERROR || conn_xprt_read0_pending(h1c->conn)) return 0; if (!(h1c->flags & (H1C_F_IN_ALLOC|H1C_F_IN_FULL|H1C_F_IN_BUSY))) @@ -1325,19 +1325,17 @@ static size_t h1_process_input(struct h1c *h1c, struct buffer *buf, int flags) tasklet_wakeup(h1c->wait_event.task); } - if (b_data(&h1c->ibuf)) { - if (!htx_is_empty(htx)) - h1s->cs->flags |= CS_FL_RCV_MORE | CS_FL_WANT_ROOM; - } - else { + h1s->cs->flags &= ~(CS_FL_RCV_MORE | CS_FL_WANT_ROOM); + + if (!b_data(&h1c->ibuf)) { h1_release_buf(h1c, &h1c->ibuf); h1_sync_messages(h1c); - h1s->cs->flags &= ~(CS_FL_RCV_MORE | CS_FL_WANT_ROOM); } + else if (!htx_is_empty(htx)) + h1s->cs->flags |= CS_FL_RCV_MORE | CS_FL_WANT_ROOM; if ((h1s->cs->flags & CS_FL_REOS) && (!b_data(&h1c->ibuf) || htx_is_empty(htx))) { h1s->cs->flags |= CS_FL_EOS; - h1s->cs->flags &= ~(CS_FL_RCV_MORE | CS_FL_WANT_ROOM); } return total; @@ -1673,10 +1671,12 @@ static int h1_recv(struct h1c *h1c) } } - if (h1_recv_allowed(h1c) && buf_room_for_htx_data(&h1c->ibuf)) - conn->xprt->subscribe(conn, SUB_CAN_RECV, &h1c->wait_event); - else + if (!h1_recv_allowed(h1c) || !buf_room_for_htx_data(&h1c->ibuf)) { rcvd = 1; + goto end; + } + + conn->xprt->subscribe(conn, SUB_CAN_RECV, &h1c->wait_event); end: if ((ret > 0 || (conn->flags & CO_FL_ERROR) ||