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.
This commit is contained in:
Christopher Faulet 2018-12-11 16:12:31 +01:00 committed by Willy Tarreau
parent 9a86fcbd47
commit cf56b99d0f

View File

@ -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) ||