MINOR: mux-h2: clear up H2_CF_DEM_DFULL and H2_CF_DEM_SHORT_READ ambiguity

Since commit 485da0b05 ("BUG/MEDIUM: mux_h2: Handle others remaining
read0 cases on partial frames"), H2_CF_DEM_SHORT_READ is set when there
is no blocking flags. However, it checks H2_CF_DEM_BLOCK_ANY which does
not include H2_CF_DEM_DFULL. This results in many cases where both
H2_CF_DEM_DFULL and H2_CF_DEM_SHORT_READ are set together, which makes
no sense, since one says the demux buffer is full while the other one
says an incomplete read was done. This doesn't permit to properly
decide whether to restart reading or processing.

Let's make sure to clear DFULL in h2_process_demux() whenever we
consume incoming data from the dbuf, and check for DFULL before
setting SHORT_READ.

This could probably be considered as a bug fix but it's hard to say if
it has any impact on the current code, probably at worst it might cause
a few useless wakeups, so until there's any proof that it needs to be
backported, better not do it.
This commit is contained in:
Willy Tarreau 2024-10-09 20:00:07 +02:00
parent b74bedf157
commit 6279cbc9e9

View File

@ -3114,8 +3114,10 @@ static struct h2s *h2c_frt_handle_headers(struct h2c *h2c, struct h2s *h2s)
}
if (error == 0) {
/* Demux not blocked because of the stream, it is an incomplete frame */
if (!(h2c->flags &H2_CF_DEM_BLOCK_ANY))
/* Demux not blocked because of the stream, it is an incomplete frame,
* or the rxbuf is not empty (e.g. for trailers).
*/
if (!(h2c->flags & (H2_CF_DEM_BLOCK_ANY | H2_CF_DEM_DFULL)))
h2c->flags |= H2_CF_DEM_SHORT_READ;
goto out; // missing data
}
@ -3175,7 +3177,7 @@ static struct h2s *h2c_frt_handle_headers(struct h2c *h2c, struct h2s *h2s)
if (error == 0) {
/* No error but missing data for demuxing, it is an incomplete frame */
if (!(h2c->flags &H2_CF_DEM_BLOCK_ANY))
if (!(h2c->flags & (H2_CF_DEM_BLOCK_ANY | H2_CF_DEM_DFULL)))
h2c->flags |= H2_CF_DEM_SHORT_READ;
goto out;
}
@ -3345,8 +3347,10 @@ static struct h2s *h2c_bck_handle_headers(struct h2c *h2c, struct h2s *h2s)
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))
/* Demux not blocked because of the stream, it is an incomplete frame,
* or the rxbuf is not empty (e.g. for trailers).
*/
if (!(h2c->flags & (H2_CF_DEM_BLOCK_ANY | H2_CF_DEM_DFULL)))
h2c->flags |= H2_CF_DEM_SHORT_READ;
goto fail; // missing data
}
@ -3886,6 +3890,10 @@ static void h2_process_demux(struct h2c *h2c)
while (1) {
int ret = 0;
/* Make sure to clear DFULL if contents were deleted */
if (!b_full(&h2c->dbuf))
h2c->flags &= ~H2_CF_DEM_DFULL;
if (!b_data(&h2c->dbuf)) {
TRACE_DEVEL("no more Rx data", H2_EV_RX_FRAME, h2c->conn);
h2c->flags |= H2_CF_DEM_SHORT_READ;
@ -4004,6 +4012,10 @@ static void h2_process_demux(struct h2c *h2c)
h2c->idle_start = now_ms;
}
/* Make sure to clear DFULL if contents were deleted */
if (!b_full(&h2c->dbuf))
h2c->flags &= ~H2_CF_DEM_DFULL;
/* Only H2_CS_FRAME_P, H2_CS_FRAME_A and H2_CS_FRAME_E here.
* H2_CS_FRAME_P indicates an incomplete previous operation
* (most often the first attempt) and requires some validity
@ -4196,6 +4208,10 @@ static void h2_process_demux(struct h2c *h2c)
h2c->flags |= H2_CF_END_REACHED;
}
/* Make sure to clear DFULL if contents were deleted */
if (!b_full(&h2c->dbuf))
h2c->flags &= ~H2_CF_DEM_DFULL;
if (h2s && h2s_sc(h2s) &&
(b_data(&h2s->rxbuf) ||
h2c_read0_pending(h2c) ||
@ -4659,9 +4675,6 @@ static int h2_process(struct h2c *h2c)
if (h2c->st0 >= H2_CS_ERROR || (h2c->flags & H2_CF_ERROR))
b_reset(&h2c->dbuf);
if (!b_full(&h2c->dbuf))
h2c->flags &= ~H2_CF_DEM_DFULL;
}
h2_send(h2c);