MEDIUM: mux-h2: Block client data on server side waiting tunnel establishment

On the server side, when a tunnel is not fully established, we must block
tunneled data, waiting for the server response. It is mandatory because the
server may refuse the tunnel. This happens when a DATA htx block is
processed in tunnel mode (H2_SF_BODY_TUNNEL flag set) but before the
response HEADERS frame is received (H2_SF_HEADERS_RCVD flag no set). In this
case, the H2_SF_BLK_MBUSY flag is set to mark the stream as busy. This flag
is removed when the tunnel is fully established or aborted.

This patch contributes to fix the tunnel mode between the H1 and the H2
muxes.
This commit is contained in:
Christopher Faulet 2021-01-22 11:59:07 +01:00
parent d0db42326d
commit f95f87650f

View File

@ -2796,6 +2796,16 @@ static struct h2s *h2c_bck_handle_headers(struct h2c *h2c, struct h2s *h2s)
h2s_close(h2s); h2s_close(h2s);
} }
/* Unblock busy server h2s waiting for the response headers to validate
* the tunnel establishment or the end of the response of an oborted
* tunnel
*/
if ((h2s->flags & (H2_SF_BODY_TUNNEL|H2_SF_BLK_MBUSY)) == (H2_SF_BODY_TUNNEL|H2_SF_BLK_MBUSY) ||
(h2s->flags & (H2_SF_TUNNEL_ABRT|H2_SF_ES_RCVD|H2_SF_BLK_MBUSY)) == (H2_SF_TUNNEL_ABRT|H2_SF_ES_RCVD|H2_SF_BLK_MBUSY)) {
TRACE_STATE("Unblock h2s blocked on tunnel establishment/abort", H2_EV_RX_FRAME|H2_EV_RX_DATA, h2c->conn, h2s);
h2s->flags &= ~H2_SF_BLK_MBUSY;
}
TRACE_USER("rcvd H2 response", H2_EV_RX_FRAME|H2_EV_RX_HDR, h2c->conn, 0, &h2s->rxbuf); TRACE_USER("rcvd H2 response", H2_EV_RX_FRAME|H2_EV_RX_HDR, h2c->conn, 0, &h2s->rxbuf);
TRACE_LEAVE(H2_EV_RX_FRAME|H2_EV_RX_HDR, h2c->conn, h2s); TRACE_LEAVE(H2_EV_RX_FRAME|H2_EV_RX_HDR, h2c->conn, h2s);
return h2s; return h2s;
@ -2897,6 +2907,15 @@ static int h2c_handle_data(struct h2c *h2c, struct h2s *h2s)
} }
} }
/* Unblock busy server h2s waiting for the end of the response for an
* aborted tunnel
*/
if ((h2c->flags & H2_CF_IS_BACK) &&
(h2s->flags & (H2_SF_TUNNEL_ABRT|H2_SF_ES_RCVD|H2_SF_BLK_MBUSY)) == (H2_SF_TUNNEL_ABRT|H2_SF_ES_RCVD|H2_SF_BLK_MBUSY)) {
TRACE_STATE("Unblock h2s blocked on tunnel abort", H2_EV_RX_FRAME|H2_EV_RX_DATA, h2c->conn, h2s);
h2s->flags &= ~H2_SF_BLK_MBUSY;
}
TRACE_LEAVE(H2_EV_RX_FRAME|H2_EV_RX_DATA, h2c->conn, h2s); TRACE_LEAVE(H2_EV_RX_FRAME|H2_EV_RX_DATA, h2c->conn, h2s);
return 1; return 1;
@ -5508,6 +5527,16 @@ static size_t h2s_make_data(struct h2s *h2s, struct buffer *buf, size_t count)
} }
else if (type != HTX_BLK_DATA) else if (type != HTX_BLK_DATA)
goto end; goto end;
else if ((h2c->flags & H2_CF_IS_BACK) &&
(h2s->flags & (H2_SF_HEADERS_RCVD|H2_SF_BODY_TUNNEL)) == H2_SF_BODY_TUNNEL) {
/* The response HEADERS frame not received yet. Thus the tunnel
* is not fully established yet. In this situation, we block
* data sending.
*/
h2s->flags |= H2_SF_BLK_MBUSY;
TRACE_STATE("Request DATA frame blocked waiting for tunnel establishment", H2_EV_TX_FRAME|H2_EV_TX_DATA, h2c->conn, h2s);
goto end;
}
mbuf = br_tail(h2c->mbuf); mbuf = br_tail(h2c->mbuf);
retry: retry: