From 91b21dc8d89ca050e033603de16782454665bcfa Mon Sep 17 00:00:00 2001 From: Christopher Faulet Date: Fri, 22 Jan 2021 12:13:15 +0100 Subject: [PATCH] MEDIUM: mux-h2: Close streams when processing data for an aborted tunnel In the previous patch ("MEDIUM: mux-h2: Block client data on server side waiting tunnel establishment"), we added a way to block client data for not fully established tunnel on the server side. This one closes the stream with an ERR_CANCEL erorr if there are some pending tunneled data while the tunnel was aborted. This may happen on the client side if a non-empty DATA frame or an empty DATA frame without the ES flag is received. This may also happen on the server side if there is a DATA htx block. However in this last case, we first wait the response is fully forwarded. This patch contributes to fix the tunnel mode between the H1 and the H2 muxes. --- src/mux_h2.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/mux_h2.c b/src/mux_h2.c index 38c53fef7..38a0e2b8b 100644 --- a/src/mux_h2.c +++ b/src/mux_h2.c @@ -2860,6 +2860,19 @@ static int h2c_handle_data(struct h2c *h2c, struct h2s *h2s) HA_ATOMIC_ADD(&h2c->px_counters->strm_proto_err, 1); goto strm_err; } + if (!(h2c->flags & H2_CF_IS_BACK) && + (h2s->flags & (H2_SF_TUNNEL_ABRT|H2_SF_ES_SENT)) == (H2_SF_TUNNEL_ABRT|H2_SF_ES_SENT) && + ((h2c->dfl - h2c->dpl) || !(h2c->dff & H2_F_DATA_END_STREAM))) { + /* a tunnel attempt was aborted but the client still try to send some raw data. + * Thus the stream is closed with the CANCEL error. Here we take care it is not + * an empty DATA Frame with the ES flag. The error is only handled if ES was + * already sent to the client because depending on the scheduling, these data may + * have been sent before the server respnse but not handle here. + */ + TRACE_ERROR("Request DATA frame for aborted tunnel", H2_EV_RX_FRAME|H2_EV_RX_DATA, h2c->conn, h2s); + error = H2_ERR_CANCEL; + goto strm_err; + } if (!h2_frt_transfer_data(h2s)) goto fail; @@ -5537,6 +5550,22 @@ static size_t h2s_make_data(struct h2s *h2s, struct buffer *buf, size_t count) TRACE_STATE("Request DATA frame blocked waiting for tunnel establishment", H2_EV_TX_FRAME|H2_EV_TX_DATA, h2c->conn, h2s); goto end; } + else if ((h2c->flags & H2_CF_IS_BACK) && (h2s->flags & H2_SF_TUNNEL_ABRT)) { + /* a tunnel attempt was aborted but the is pending raw data to xfer to the server. + * Thus the stream is closed with the CANCEL error. The error will be reported to + * the upper layer as aserver abort. But at this stage there is nothing more we can + * do. We just wait for the end of the response to be sure to not truncate it. + */ + if (!(h2s->flags & H2_SF_ES_RCVD)) { + TRACE_STATE("Request DATA frame blocked waiting end of aborted tunnel", H2_EV_TX_FRAME|H2_EV_TX_DATA, h2c->conn, h2s); + h2s->flags |= H2_SF_BLK_MBUSY; + } + else { + TRACE_ERROR("Request DATA frame for aborted tunnel", H2_EV_RX_FRAME|H2_EV_RX_DATA, h2c->conn, h2s); + h2s_error(h2s, H2_ERR_CANCEL); + } + goto end; + } mbuf = br_tail(h2c->mbuf); retry: