diff --git a/src/mux_h2.c b/src/mux_h2.c index 8847e06c5..cd88c8874 100644 --- a/src/mux_h2.c +++ b/src/mux_h2.c @@ -2812,39 +2812,47 @@ static struct h2s *h2c_frt_handle_headers(struct h2c *h2c, struct h2s *h2s) error = h2c_dec_hdrs(h2c, &rxbuf, &flags, &body_len, NULL); - /* unrecoverable error ? */ - if (h2c->st0 >= H2_CS_ERROR) { - /* This is mainly used for completeness, but a stream error is - * currently not set by h2c_dec_hdrs(). - */ - TRACE_USER("Unrecoverable error decoding H2 request", H2_EV_RX_FRAME|H2_EV_RX_HDR|H2_EV_STRM_NEW|H2_EV_STRM_END, h2c->conn, 0, &rxbuf); - goto strm_err; + if (error == 0) { + /* No error but missing data for demuxing, it is an incomplete frame */ + if (!(h2c->flags &H2_CF_DEM_BLOCK_ANY)) + h2c->flags |= H2_CF_DEM_SHORT_READ; + goto out; } - if (error <= 0) { - if (error == 0) { - /* Demux not blocked because of the stream, it is an incomplete frame */ - if (!(h2c->flags &H2_CF_DEM_BLOCK_ANY)) - h2c->flags |= H2_CF_DEM_SHORT_READ; - goto out; // missing data + /* Now we cannot roll back and we won't come back here anymore for this + * stream, so this stream ID is open from a protocol perspective, even + * if incomplete or broken, we want to count it as attempted. + */ + if (h2c->dsi > h2c->max_id) + h2c->max_id = h2c->dsi; + h2c->stream_cnt++; + + if (error < 0) { + /* Failed to decode this stream. This might be due to a + * recoverable error affecting only the stream (e.g. too large + * request for buffer, that leaves the HPACK decompressor still + * synchronized), or a non-recoverable error such as an invalid + * frame type sequence (e.g. other frame type interleaved with + * CONTINUATION), in which h2c_dec_hdrs() has already set the + * error code in the connection and counted it in the relevant + * stats. We still count a req error in both cases. + */ + sess_log(h2c->conn->owner); + session_inc_http_req_ctr(h2c->conn->owner); + session_inc_http_err_ctr(h2c->conn->owner); + + if (h2c->st0 >= H2_CS_ERROR) { + TRACE_USER("Unrecoverable error decoding H2 request", H2_EV_RX_FRAME|H2_EV_RX_HDR|H2_EV_STRM_NEW|H2_EV_STRM_END, h2c->conn, 0, &rxbuf); + goto out; } - /* Failed to decode this stream (e.g. too large request) - * but the HPACK decompressor is still synchronized. - */ + /* recoverable stream error (e.g. too large request) */ TRACE_USER("rcvd unparsable H2 request", H2_EV_RX_FRAME|H2_EV_RX_HDR|H2_EV_STRM_NEW|H2_EV_STRM_END, h2c->conn, h2s, &rxbuf); goto strm_err; } TRACE_USER("rcvd H2 request ", H2_EV_RX_FRAME|H2_EV_RX_HDR|H2_EV_STRM_NEW, h2c->conn, 0, &rxbuf); - /* Now we cannot roll back and we won't come back here anymore for this - * stream, this stream ID is open. - */ - if (h2c->dsi > h2c->max_id) - h2c->max_id = h2c->dsi; - h2c->stream_cnt++; - /* Note: we don't emit any other logs below because if we return * positively from h2c_frt_stream_new(), the stream will report the error, * and if we return in error, h2c_frt_stream_new() will emit the error. @@ -2883,19 +2891,8 @@ static struct h2s *h2c_frt_handle_headers(struct h2c *h2c, struct h2s *h2s) goto leave; strm_err: - sess_log(h2c->conn->owner); - session_inc_http_req_ctr(h2c->conn->owner); - session_inc_http_err_ctr(h2c->conn->owner); - h2s = (struct h2s*)h2_error_stream; - /* This stream ID is now opened anyway until we send the RST on - * it, it must not be reused. - */ - if (h2c->dsi > h2c->max_id) - h2c->max_id = h2c->dsi; - h2c->stream_cnt++; - send_rst: /* make the demux send an RST for the current stream. We may only * do this if we're certain that the HEADERS frame was properly