mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-09-22 14:21:25 +02:00
MEDIUM: h2: honor WINDOW_UPDATE frames
Now they really increase the window size of connections and streams. If a stream was not queued but requested to send, it means it was flow-controlled so it's added again into the connection's send list.
This commit is contained in:
parent
f3ee0697f3
commit
26f95954fe
90
src/mux_h2.c
90
src/mux_h2.c
@ -952,6 +952,91 @@ static int h2c_ack_ping(struct h2c *h2c)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* processes a WINDOW_UPDATE frame whose payload is <payload> for <plen> bytes.
|
||||||
|
* Returns > 0 on success or zero on missing data. It may return an error in
|
||||||
|
* h2c or h2s. Described in RFC7540#6.9.
|
||||||
|
*/
|
||||||
|
static int h2c_handle_window_update(struct h2c *h2c, struct h2s *h2s)
|
||||||
|
{
|
||||||
|
int32_t inc;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
if (h2c->dfl != 4) {
|
||||||
|
error = H2_ERR_FRAME_SIZE_ERROR;
|
||||||
|
goto conn_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* process full frame only */
|
||||||
|
if (h2c->dbuf->i < h2c->dfl)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
inc = h2_get_n32(h2c->dbuf, 0);
|
||||||
|
|
||||||
|
if (h2c->dsi != 0) {
|
||||||
|
/* stream window update */
|
||||||
|
if (h2s->st == H2_SS_IDLE) {
|
||||||
|
error = H2_ERR_PROTOCOL_ERROR;
|
||||||
|
goto conn_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* it's not an error to receive WU on a closed stream */
|
||||||
|
if (h2s->st == H2_SS_CLOSED)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (!inc) {
|
||||||
|
error = H2_ERR_PROTOCOL_ERROR;
|
||||||
|
goto strm_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (h2s->mws >= 0 && h2s->mws + inc < 0) {
|
||||||
|
error = H2_ERR_FLOW_CONTROL_ERROR;
|
||||||
|
goto strm_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2s->mws += inc;
|
||||||
|
if (h2s->mws > 0 && (h2s->flags & H2_SF_BLK_SFCTL)) {
|
||||||
|
h2s->flags &= ~H2_SF_BLK_SFCTL;
|
||||||
|
if (h2s->cs && LIST_ISEMPTY(&h2s->list) &&
|
||||||
|
(h2s->cs->flags & CS_FL_DATA_WR_ENA)) {
|
||||||
|
/* This stream wanted to send but could not due to its
|
||||||
|
* own flow control. We can put it back into the send
|
||||||
|
* list now, it will be handled upon next send() call.
|
||||||
|
*/
|
||||||
|
LIST_ADDQ(&h2c->send_list, &h2s->list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* connection window update */
|
||||||
|
if (!inc) {
|
||||||
|
error = H2_ERR_PROTOCOL_ERROR;
|
||||||
|
goto conn_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (h2c->mws >= 0 && h2c->mws + inc < 0) {
|
||||||
|
error = H2_ERR_FLOW_CONTROL_ERROR;
|
||||||
|
goto conn_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2c->mws += inc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
conn_err:
|
||||||
|
h2c_error(h2c, error);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
strm_err:
|
||||||
|
if (h2s) {
|
||||||
|
h2s_error(h2s, error);
|
||||||
|
h2c->st0 = H2_CS_FRAME_A;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
h2c_error(h2c, error);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* process Rx frames to be demultiplexed */
|
/* process Rx frames to be demultiplexed */
|
||||||
static void h2_process_demux(struct h2c *h2c)
|
static void h2_process_demux(struct h2c *h2c)
|
||||||
{
|
{
|
||||||
@ -1056,6 +1141,11 @@ static void h2_process_demux(struct h2c *h2c)
|
|||||||
ret = h2c_ack_ping(h2c);
|
ret = h2c_ack_ping(h2c);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case H2_FT_WINDOW_UPDATE:
|
||||||
|
if (h2c->st0 == H2_CS_FRAME_P)
|
||||||
|
ret = h2c_handle_window_update(h2c, h2s);
|
||||||
|
break;
|
||||||
|
|
||||||
/* FIXME: implement all supported frame types here */
|
/* FIXME: implement all supported frame types here */
|
||||||
default:
|
default:
|
||||||
/* drop frames that we ignore. They may be larger than
|
/* drop frames that we ignore. They may be larger than
|
||||||
|
Loading…
x
Reference in New Issue
Block a user