BUG/MEDIUM: h2: debug incoming traffic in h2_wake()
Even after previous commit ("BUG/MEDIUM: h2: work around a connection API limitation") there is still a problem with some requests. Sometimes when polling for more request data while some pending data lies in the buffer, there's no way to enter h2_recv() because the FD is not marked ready for reading. We need to slightly change the approach and make h2_recv() only receive from the buffer and h2_wake() always attempt to demux if the demux is not blocked. However, if the connection is already being polled for reading, it will not wake up from polling. For this reason we need to cheat and also pretend a request for sending data, which ensures that as soon as any direction may move, we can continue to demux. This shows that in the long term we probably need a better way to resume an interrupted operation at the mux level. With this fix, no more hangups happen during uploads. Note that this time the setup required to provoke the hangups was a bit complex : - client is "curl" running on local host, uploading 1.7 MB of data via haproxy - haproxy running on local host, forwarding to a remote server through a 100 Mbps only switch - timeouts disabled on haproxy - remote server made of thttpd executing a cgi reading request data through "dd bs=10" to slow down everything. With such a setup, around 3-5% of the connections would hang up. This fix needs to be backported to 1.8.
This commit is contained in:
parent
6042aeb1e8
commit
d13bf27e78
23
src/mux_h2.c
23
src/mux_h2.c
@ -2094,15 +2094,6 @@ static void h2_recv(struct connection *conn)
|
|||||||
|
|
||||||
if (buf->i == buf->size)
|
if (buf->i == buf->size)
|
||||||
h2c->flags |= H2_CF_DEM_DFULL;
|
h2c->flags |= H2_CF_DEM_DFULL;
|
||||||
|
|
||||||
h2_process_demux(h2c);
|
|
||||||
|
|
||||||
/* after streams have been processed, we should have made some room */
|
|
||||||
if (h2c->st0 >= H2_CS_ERROR || conn->flags & CO_FL_ERROR)
|
|
||||||
buf->i = 0;
|
|
||||||
|
|
||||||
if (buf->i != buf->size)
|
|
||||||
h2c->flags &= ~H2_CF_DEM_DFULL;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2174,6 +2165,16 @@ static int h2_wake(struct connection *conn)
|
|||||||
{
|
{
|
||||||
struct h2c *h2c = conn->mux_ctx;
|
struct h2c *h2c = conn->mux_ctx;
|
||||||
|
|
||||||
|
if (h2c->dbuf->i && !(h2c->flags & H2_CF_DEM_BLOCK_ANY)) {
|
||||||
|
h2_process_demux(h2c);
|
||||||
|
|
||||||
|
if (h2c->st0 >= H2_CS_ERROR || conn->flags & CO_FL_ERROR)
|
||||||
|
h2c->dbuf->i = 0;
|
||||||
|
|
||||||
|
if (h2c->dbuf->i != h2c->dbuf->size)
|
||||||
|
h2c->flags &= ~H2_CF_DEM_DFULL;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we received early data, try to wake any stream, just in case
|
* If we received early data, try to wake any stream, just in case
|
||||||
* at least one of them was waiting for the handshake
|
* at least one of them was waiting for the handshake
|
||||||
@ -2313,8 +2314,10 @@ static void h2_update_poll(struct conn_stream *cs)
|
|||||||
if (cs->flags & CS_FL_DATA_RD_ENA) {
|
if (cs->flags & CS_FL_DATA_RD_ENA) {
|
||||||
/* the stream indicates it's willing to read */
|
/* the stream indicates it's willing to read */
|
||||||
h2s->h2c->flags &= ~H2_CF_DEM_SFULL;
|
h2s->h2c->flags &= ~H2_CF_DEM_SFULL;
|
||||||
if (h2s->h2c->dsi == h2s->id)
|
if (h2s->h2c->dsi == h2s->id) {
|
||||||
conn_xprt_want_recv(cs->conn);
|
conn_xprt_want_recv(cs->conn);
|
||||||
|
conn_xprt_want_send(cs->conn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Note: the stream and stream-int code doesn't allow us to perform a
|
/* Note: the stream and stream-int code doesn't allow us to perform a
|
||||||
|
Loading…
x
Reference in New Issue
Block a user