mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-01-31 18:41:39 +00:00
MEDIUM: h2: send DATA+ES or RST_STREAM on shutw/shutr
When a stream sends a shutw, we send an empty DATA frame with the ES flag set, except if no HEADERS were sent, in which case we rather send RST_STREAM. On shutr(1) to abort a request, an RST_STREAM frame is sent if the stream is OPEN and the stream is closed. Care is taken to switch the stream's state accordingly and to avoid sending an ES bit again or another RST once already done.
This commit is contained in:
parent
cd234e9fb0
commit
c7576eac46
85
src/mux_h2.c
85
src/mux_h2.c
@ -828,6 +828,53 @@ static int h2c_send_rst_stream(struct h2c *h2c, struct h2s *h2s)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* try to send an empty DATA frame with the ES flag set to notify about the
|
||||
* end of stream and match a shutdown(write). If an ES was already sent as
|
||||
* indicated by HLOC/ERROR/RESET/CLOSED states, nothing is done. Returns > 0
|
||||
* on success or zero if nothing was done. In case of lack of room to write the
|
||||
* message, it subscribes the requesting stream to future notifications.
|
||||
*/
|
||||
static int h2_send_empty_data_es(struct h2s *h2s)
|
||||
{
|
||||
struct h2c *h2c = h2s->h2c;
|
||||
struct buffer *res;
|
||||
char str[9];
|
||||
int ret;
|
||||
|
||||
if (h2s->st == H2_SS_HLOC || h2s->st == H2_SS_ERROR ||
|
||||
h2s->st == H2_SS_RESET || h2s->st == H2_SS_CLOSED)
|
||||
return 1;
|
||||
|
||||
if (h2c_mux_busy(h2c, h2s)) {
|
||||
h2s->flags |= H2_SF_BLK_MBUSY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
res = h2_get_mbuf(h2c);
|
||||
if (!res) {
|
||||
h2c->flags |= H2_CF_MUX_MALLOC;
|
||||
h2s->flags |= H2_SF_BLK_MROOM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* len: 0x000000, type: 0(DATA), flags: ES=1 */
|
||||
memcpy(str, "\x00\x00\x00\x00\x01", 5);
|
||||
write_n32(str + 5, h2s->id);
|
||||
ret = bo_istput(res, ist2(str, 9));
|
||||
if (unlikely(ret <= 0)) {
|
||||
if (!ret) {
|
||||
h2c->flags |= H2_CF_MUX_MFULL;
|
||||
h2s->flags |= H2_SF_BLK_MROOM;
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
h2c_error(h2c, H2_ERR_INTERNAL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Increase all streams' outgoing window size by the difference passed in
|
||||
* argument. This is needed upon receipt of the settings frame if the initial
|
||||
* window size is different. The difference may be negative and the resulting
|
||||
@ -2003,10 +2050,48 @@ static void h2_detach(struct conn_stream *cs)
|
||||
|
||||
static void h2_shutr(struct conn_stream *cs, enum cs_shr_mode mode)
|
||||
{
|
||||
struct h2s *h2s = cs->ctx;
|
||||
|
||||
if (!mode)
|
||||
return;
|
||||
|
||||
if (h2s->st == H2_SS_HLOC || h2s->st == H2_SS_ERROR ||
|
||||
h2s->st == H2_SS_RESET || h2s->st == H2_SS_CLOSED)
|
||||
return;
|
||||
|
||||
if (h2c_send_rst_stream(h2s->h2c, h2s) <= 0)
|
||||
return;
|
||||
|
||||
if (h2s->h2c->mbuf->o && !(cs->conn->flags & CO_FL_XPRT_WR_ENA))
|
||||
conn_xprt_want_send(cs->conn);
|
||||
|
||||
h2s->st = H2_SS_CLOSED;
|
||||
}
|
||||
|
||||
static void h2_shutw(struct conn_stream *cs, enum cs_shw_mode mode)
|
||||
{
|
||||
struct h2s *h2s = cs->ctx;
|
||||
|
||||
if (h2s->st == H2_SS_HLOC || h2s->st == H2_SS_ERROR ||
|
||||
h2s->st == H2_SS_RESET || h2s->st == H2_SS_CLOSED)
|
||||
return;
|
||||
|
||||
if (h2s->h2c->flags & H2_CF_HEADERS_SENT) {
|
||||
if (h2_send_empty_data_es(h2s) <= 0)
|
||||
return;
|
||||
} else {
|
||||
if (h2c_send_rst_stream(h2s->h2c, h2s) <= 0)
|
||||
return;
|
||||
}
|
||||
|
||||
if (h2s->h2c->mbuf->o && !(cs->conn->flags & CO_FL_XPRT_WR_ENA))
|
||||
conn_xprt_want_send(cs->conn);
|
||||
|
||||
if (h2s->st == H2_SS_OPEN && !(h2s->flags & H2_SF_RST_SENT))
|
||||
h2s->st = H2_SS_HLOC;
|
||||
else
|
||||
h2s->st = H2_SS_CLOSED;
|
||||
|
||||
}
|
||||
|
||||
/* Decode the payload of a HEADERS frame and produce the equivalent HTTP/1
|
||||
|
Loading…
Reference in New Issue
Block a user