mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-01-10 07:49:54 +00:00
BUG/MEDIUM: h2: support orphaned streams
When a stream_interface performs a shutw() then a shutr(), the stream is marked closed. Then cs_destroy() calls h2_detach() and it cannot fail since we're on the leaving path of the caller. The problem is that in order to close streams we usually have to send either an emty DATA frame with the ES flag set or an RST_STREAM frame, and the mux buffer might already be full, forcing the stream to be queued. The forced removal of this stream causes this last message to silently disappear, and the client to wait forever for a response. This commit ensures we can detach the conn_stream from the h2 stream if the stream is blocked, effectively making the h2 stream an orphan, ensures that the mux can deal with orphaned streams after processing them, and that the demux can kill them upon receipt of GOAWAY.
This commit is contained in:
parent
aa39860aef
commit
22cf59bbba
37
src/mux_h2.c
37
src/mux_h2.c
@ -984,14 +984,21 @@ static void h2_wake_some_streams(struct h2c *h2c, int last, uint32_t flags)
|
||||
if (h2s->id <= last)
|
||||
break;
|
||||
node = eb32_next(node);
|
||||
if (h2s->cs) {
|
||||
h2s->cs->flags |= flags;
|
||||
/* recv is used to force to detect CS_FL_EOS that wake()
|
||||
* doesn't handle in the stream int code.
|
||||
*/
|
||||
h2s->cs->data_cb->recv(h2s->cs);
|
||||
h2s->cs->data_cb->wake(h2s->cs);
|
||||
|
||||
if (!h2s->cs) {
|
||||
/* this stream was already orphaned */
|
||||
eb32_delete(&h2s->by_id);
|
||||
pool_free2(pool2_h2s, h2s);
|
||||
continue;
|
||||
}
|
||||
|
||||
h2s->cs->flags |= flags;
|
||||
/* recv is used to force to detect CS_FL_EOS that wake()
|
||||
* doesn't handle in the stream int code.
|
||||
*/
|
||||
h2s->cs->data_cb->recv(h2s->cs);
|
||||
h2s->cs->data_cb->wake(h2s->cs);
|
||||
|
||||
if (flags & CS_FL_ERROR && h2s->st < H2_SS_ERROR)
|
||||
h2s->st = H2_SS_ERROR;
|
||||
else if (flags & CS_FL_EOS && h2s->st == H2_SS_OPEN)
|
||||
@ -1884,6 +1891,11 @@ static int h2_process_mux(struct h2c *h2c)
|
||||
LIST_INIT(&h2s->list);
|
||||
if (h2s->cs)
|
||||
h2s->cs->flags &= ~CS_FL_DATA_WR_ENA;
|
||||
else {
|
||||
/* just sent the last frame for this orphaned stream */
|
||||
eb32_delete(&h2s->by_id);
|
||||
pool_free2(pool2_h2s, h2s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1921,6 +1933,11 @@ static int h2_process_mux(struct h2c *h2c)
|
||||
LIST_INIT(&h2s->list);
|
||||
if (h2s->cs)
|
||||
h2s->cs->flags &= ~CS_FL_DATA_WR_ENA;
|
||||
else {
|
||||
/* just sent the last frame for this orphaned stream */
|
||||
eb32_delete(&h2s->by_id);
|
||||
pool_free2(pool2_h2s, h2s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2237,6 +2254,12 @@ static void h2_detach(struct conn_stream *cs)
|
||||
h2c = h2s->h2c;
|
||||
h2s->cs = NULL;
|
||||
|
||||
/* this stream may be blocked waiting for some data to leave (possibly
|
||||
* an ES or RST frame), so orphan it in this case.
|
||||
*/
|
||||
if (h2s->flags & (H2_SF_BLK_MBUSY | H2_SF_BLK_MROOM | H2_SF_BLK_MFCTL))
|
||||
return;
|
||||
|
||||
if ((h2c->flags & H2_CF_DEM_BLOCK_ANY && h2s->id == h2c->dsi) ||
|
||||
(h2c->flags & H2_CF_MUX_BLOCK_ANY && h2s->id == h2c->msi)) {
|
||||
/* unblock the connection if it was blocked on this
|
||||
|
Loading…
Reference in New Issue
Block a user