From: Willy Tarreau Date: Sat, 15 Jun 2019 07:55:50 +0000 (+0200) Subject: BUG/MEDIUM: mux-h2: fix early close with option abortonclose X-Git-Tag: v2.0.0~26 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=76c83826db63f8d613cdb74e32d2642eb05e2458;p=thirdparty%2Fhaproxy.git BUG/MEDIUM: mux-h2: fix early close with option abortonclose Olivier found that commit 99ad1b3e8 ("MINOR: mux-h2: stop relying on CS_FL_REOS") managed to break abortonclose again with H2. What happens is that while the CS_FL_REOS flag was set on some transitions to the HREM state, it's not set on all and is in fact only set when the low level connection is closed. So making the replacement condition match the HREM and ERROR states is not correct and causes completely correct requests to send advertise an early close of the connection layer while only the stream's input is closed. In order to avoid this, we now properly split the checks for the CLOSED state and for the closed connection. This way there is no risk to set the EOS flag too early on the connection. No backport is needed. --- diff --git a/src/mux_h2.c b/src/mux_h2.c index 20108bd7f8..790d5bb95d 100644 --- a/src/mux_h2.c +++ b/src/mux_h2.c @@ -157,7 +157,6 @@ enum h2_ss { #define H2_SS_HLOC_BIT (1UL << H2_SS_HLOC) #define H2_SS_ERROR_BIT (1UL << H2_SS_ERROR) #define H2_SS_CLOSED_BIT (1UL << H2_SS_CLOSED) -#define H2_SS_EOS_BITS (H2_SS_CLOSED_BIT|H2_SS_ERROR_BIT|H2_SS_HREM_BIT) /* HTTP/2 stream flags (32 bit), in h2s->flags */ #define H2_SF_NONE 0x00000000 @@ -2376,7 +2375,8 @@ static void h2_process_demux(struct h2c *h2c) if (tmp_h2s != h2s && h2s && h2s->cs && (b_data(&h2s->rxbuf) || - (H2_SS_MASK(h2s->st) & H2_SS_EOS_BITS) || + conn_xprt_read0_pending(h2c->conn) || + h2s->st == H2_SS_CLOSED || (h2s->flags & H2_SF_ES_RCVD) || (h2s->cs->flags & (CS_FL_ERROR|CS_FL_ERR_PENDING|CS_FL_EOS)))) { /* we may have to signal the upper layers */ @@ -2615,7 +2615,8 @@ static void h2_process_demux(struct h2c *h2c) /* we can go here on missing data, blocked response or error */ if (h2s && h2s->cs && (b_data(&h2s->rxbuf) || - (H2_SS_MASK(h2s->st) & H2_SS_EOS_BITS) || + conn_xprt_read0_pending(h2c->conn) || + h2s->st == H2_SS_CLOSED || (h2s->flags & H2_SF_ES_RCVD) || (h2s->cs->flags & (CS_FL_ERROR|CS_FL_ERR_PENDING|CS_FL_EOS)))) { /* we may have to signal the upper layers */ @@ -5411,7 +5412,7 @@ static size_t h2_rcv_buf(struct conn_stream *cs, struct buffer *buf, size_t coun cs->flags &= ~(CS_FL_RCV_MORE | CS_FL_WANT_ROOM); if (h2s->flags & H2_SF_ES_RCVD) cs->flags |= CS_FL_EOI; - if (H2_SS_MASK(h2s->st) & H2_SS_EOS_BITS) + if (conn_xprt_read0_pending(h2c->conn) || h2s->st == H2_SS_CLOSED) cs->flags |= CS_FL_EOS; if (cs->flags & CS_FL_ERR_PENDING) cs->flags |= CS_FL_ERROR;