]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: mux-h2/glitches: add a description to the H2 glitches
authorWilly Tarreau <w@1wt.eu>
Fri, 6 Dec 2024 16:55:05 +0000 (17:55 +0100)
committerWilly Tarreau <w@1wt.eu>
Fri, 6 Dec 2024 17:49:07 +0000 (18:49 +0100)
Since we can now list them using "debug counters" and now support a
description, better add the description to all glitches. This patch may
be backported to 3.1, but before this the following patches must also
be picked:

    86823c828 MINOR: mux-h2/traces: add a missing trace on negative initial window size
    7c8e9420a CLEANUP: mux-h2/traces: reword certain ambiguous traces

src/mux_h2.c

index ce55e54f90e9c1fc6277d6008fce8e0b99d85f66..c0022226be2ccb53458935b12af645637af48c4f 100644 (file)
@@ -1945,7 +1945,7 @@ static struct h2s *h2c_frt_stream_new(struct h2c *h2c, int id, struct buffer *in
        BUG_ON(conn_reverse_in_preconnect(h2c->conn));
 
        if (h2c->nb_streams >= h2c_max_concurrent_streams(h2c)) {
-               h2c_report_glitch(h2c, 1);
+               h2c_report_glitch(h2c, 1, "HEADERS frame causing MAX_CONCURRENT_STREAMS to be exceeded");
                TRACE_ERROR("HEADERS frame causing MAX_CONCURRENT_STREAMS to be exceeded", H2_EV_H2S_NEW|H2_EV_RX_FRAME|H2_EV_RX_HDR, h2c->conn);
                session_inc_http_req_ctr(sess);
                session_inc_http_err_ctr(sess);
@@ -2198,7 +2198,7 @@ static int h2c_frt_recv_preface(struct h2c *h2c)
                if (!ret1)
                        h2c->flags |= H2_CF_DEM_SHORT_READ;
                if (ret1 < 0 || (h2c->flags & H2_CF_RCVD_SHUT)) {
-                       h2c_report_glitch(h2c, 1);
+                       h2c_report_glitch(h2c, 1, "I/O error or short read on PREFACE");
                        TRACE_ERROR("I/O error or short read on PREFACE", H2_EV_RX_FRAME|H2_EV_RX_PREFACE, h2c->conn);
                        h2c_error(h2c, H2_ERR_PROTOCOL_ERROR);
                        if (b_data(&h2c->dbuf) ||
@@ -2666,7 +2666,7 @@ static int h2c_handle_settings(struct h2c *h2c)
                         */
                        if (arg < 0) { // RFC7540#6.5.2
                                error = H2_ERR_FLOW_CONTROL_ERROR;
-                               h2c_report_glitch(h2c, 1);
+                               h2c_report_glitch(h2c, 1, "negative INITIAL_WINDOW_SIZE");
                                TRACE_STATE("negative INITIAL_WINDOW_SIZE", H2_EV_RX_FRAME|H2_EV_RX_SETTINGS|H2_EV_H2C_ERR|H2_EV_PROTO_ERR, h2c->conn);
                                goto fail;
                        }
@@ -2676,7 +2676,7 @@ static int h2c_handle_settings(struct h2c *h2c)
                         * it's often suspicious.
                         */
                        if (h2c->st0 != H2_CS_SETTINGS1 && arg < h2c->miw)
-                               if (h2c_report_glitch(h2c, 1)) {
+                               if (h2c_report_glitch(h2c, 1, "reduced SETTINGS_INITIAL_WINDOW_SIZE")) {
                                        error = H2_ERR_ENHANCE_YOUR_CALM;
                                        TRACE_STATE("glitch limit reached on SETTINGS frame", H2_EV_RX_FRAME|H2_EV_RX_SETTINGS|H2_EV_H2C_ERR|H2_EV_PROTO_ERR, h2c->conn);
                                        goto fail;
@@ -2686,7 +2686,7 @@ static int h2c_handle_settings(struct h2c *h2c)
                        break;
                case H2_SETTINGS_MAX_FRAME_SIZE:
                        if (arg < 16384 || arg > 16777215) { // RFC7540#6.5.2
-                               h2c_report_glitch(h2c, 1);
+                               h2c_report_glitch(h2c, 1, "MAX_FRAME_SIZE out of range");
                                TRACE_ERROR("MAX_FRAME_SIZE out of range", H2_EV_RX_FRAME|H2_EV_RX_SETTINGS, h2c->conn);
                                error = H2_ERR_PROTOCOL_ERROR;
                                HA_ATOMIC_INC(&h2c->px_counters->conn_proto_err);
@@ -2699,7 +2699,7 @@ static int h2c_handle_settings(struct h2c *h2c)
                        break;
                case H2_SETTINGS_ENABLE_PUSH:
                        if (arg < 0 || arg > 1) { // RFC7540#6.5.2
-                               h2c_report_glitch(h2c, 1);
+                               h2c_report_glitch(h2c, 1, "ENABLE_PUSH out of range");
                                TRACE_ERROR("ENABLE_PUSH out of range", H2_EV_RX_FRAME|H2_EV_RX_SETTINGS, h2c->conn);
                                error = H2_ERR_PROTOCOL_ERROR;
                                HA_ATOMIC_INC(&h2c->px_counters->conn_proto_err);
@@ -3076,7 +3076,7 @@ static int h2c_handle_window_update(struct h2c *h2c, struct h2s *h2s)
                        goto done;
 
                if (!inc) {
-                       h2c_report_glitch(h2c, 1);
+                       h2c_report_glitch(h2c, 1, "stream WINDOW_UPDATE inc=0");
                        TRACE_ERROR("stream WINDOW_UPDATE inc=0", H2_EV_RX_FRAME|H2_EV_RX_WU, h2c->conn, h2s);
                        error = H2_ERR_PROTOCOL_ERROR;
                        HA_ATOMIC_INC(&h2c->px_counters->strm_proto_err);
@@ -3091,7 +3091,7 @@ static int h2c_handle_window_update(struct h2c *h2c, struct h2s *h2s)
                 */
 
                if (h2s_mws(h2s) >= 0 && h2s_mws(h2s) + inc < 0) {
-                       h2c_report_glitch(h2c, 1);
+                       h2c_report_glitch(h2c, 1, "stream WINDOW_UPDATE inc<0");
                        TRACE_ERROR("stream WINDOW_UPDATE inc<0", H2_EV_RX_FRAME|H2_EV_RX_WU, h2c->conn, h2s);
                        error = H2_ERR_FLOW_CONTROL_ERROR;
                        HA_ATOMIC_INC(&h2c->px_counters->strm_proto_err);
@@ -3110,7 +3110,7 @@ static int h2c_handle_window_update(struct h2c *h2c, struct h2s *h2s)
        else {
                /* connection window update */
                if (!inc) {
-                       h2c_report_glitch(h2c, 1);
+                       h2c_report_glitch(h2c, 1, "conn WINDOW_UPDATE inc=0");
                        TRACE_ERROR("conn WINDOW_UPDATE inc=0", H2_EV_RX_FRAME|H2_EV_RX_WU, h2c->conn);
                        error = H2_ERR_PROTOCOL_ERROR;
                        HA_ATOMIC_INC(&h2c->px_counters->conn_proto_err);
@@ -3118,7 +3118,7 @@ static int h2c_handle_window_update(struct h2c *h2c, struct h2s *h2s)
                }
 
                if (h2c->mws >= 0 && h2c->mws + inc < 0) {
-                       h2c_report_glitch(h2c, 1);
+                       h2c_report_glitch(h2c, 1, "conn WINDOW_UPDATE inc<0");
                        TRACE_ERROR("conn WINDOW_UPDATE inc<0", H2_EV_RX_FRAME|H2_EV_RX_WU, h2c->conn);
                        error = H2_ERR_FLOW_CONTROL_ERROR;
                        goto conn_err;
@@ -3188,7 +3188,7 @@ static int h2c_handle_priority(struct h2c *h2c)
 
        if (h2_get_n32(&h2c->dbuf, 0) == h2c->dsi) {
                /* 7540#5.3 : can't depend on itself */
-               h2c_report_glitch(h2c, 1);
+               h2c_report_glitch(h2c, 1, "PRIORITY depends on itself");
                TRACE_ERROR("PRIORITY depends on itself", H2_EV_RX_FRAME|H2_EV_RX_WU, h2c->conn);
                h2c_error(h2c, H2_ERR_PROTOCOL_ERROR);
                HA_ATOMIC_INC(&h2c->px_counters->conn_proto_err);
@@ -3314,7 +3314,7 @@ static struct h2s *h2c_frt_handle_headers(struct h2c *h2c, struct h2s *h2s)
        else if (h2c->dsi <= h2c->max_id || !(h2c->dsi & 1)) {
                /* RFC7540#5.1.1 stream id > prev ones, and must be odd here */
                error = H2_ERR_PROTOCOL_ERROR;
-               h2c_report_glitch(h2c, 1);
+               h2c_report_glitch(h2c, 1, "HEADERS on invalid stream ID");
                TRACE_ERROR("HEADERS on invalid stream ID", H2_EV_RX_FRAME|H2_EV_RX_HDR, h2c->conn);
                HA_ATOMIC_INC(&h2c->px_counters->conn_proto_err);
                sess_log(h2c->conn->owner);
@@ -3332,7 +3332,7 @@ static struct h2s *h2c_frt_handle_headers(struct h2c *h2c, struct h2s *h2s)
                 * stop processing its requests for real.
                 */
                error = H2_ERR_ENHANCE_YOUR_CALM;
-               h2c_report_glitch(h2c, 1);
+               h2c_report_glitch(h2c, 1, "Stream limit violated");
                TRACE_STATE("Stream limit violated", H2_EV_STRM_SHUT, h2c->conn);
                HA_ATOMIC_INC(&h2c->px_counters->conn_proto_err);
                sess_log(h2c->conn->owner);
@@ -3510,7 +3510,7 @@ static struct h2s *h2c_bck_handle_headers(struct h2c *h2c, struct h2s *h2s)
 
        if (h2s->st != H2_SS_OPEN && h2s->st != H2_SS_HLOC) {
                /* RFC7540#5.1 */
-               h2c_report_glitch(h2c, 1);
+               h2c_report_glitch(h2c, 1, "response HEADERS in invalid state");
                TRACE_ERROR("response HEADERS in invalid state", H2_EV_RX_FRAME|H2_EV_RX_HDR, h2c->conn, h2s);
                h2s_error(h2s, H2_ERR_STREAM_CLOSED);
                h2c->st0 = H2_CS_FRAME_E;
@@ -3611,7 +3611,7 @@ static int h2c_handle_data(struct h2c *h2c, struct h2s *h2s)
 
        if (!(h2s->flags & H2_SF_HEADERS_RCVD)) {
                /* RFC9113#8.1: The header section must be received before the message content */
-               h2c_report_glitch(h2c, 1);
+               h2c_report_glitch(h2c, 1, "Unexpected DATA frame before the message headers");
                TRACE_ERROR("Unexpected DATA frame before the message headers", H2_EV_RX_FRAME|H2_EV_RX_DATA, h2c->conn, h2s);
                error = H2_ERR_PROTOCOL_ERROR;
                HA_ATOMIC_INC(&h2c->px_counters->strm_proto_err);
@@ -3619,7 +3619,7 @@ static int h2c_handle_data(struct h2c *h2c, struct h2s *h2s)
        }
        if ((h2s->flags & H2_SF_DATA_CLEN) && (h2c->dfl - h2c->dpl) > h2s->body_len) {
                /* RFC7540#8.1.2 */
-               h2c_report_glitch(h2c, 1);
+               h2c_report_glitch(h2c, 1, "DATA frame larger than content-length");
                TRACE_ERROR("DATA frame larger than content-length", H2_EV_RX_FRAME|H2_EV_RX_DATA, h2c->conn, h2s);
                error = H2_ERR_PROTOCOL_ERROR;
                HA_ATOMIC_INC(&h2c->px_counters->strm_proto_err);
@@ -3679,7 +3679,7 @@ static int h2c_handle_data(struct h2c *h2c, struct h2s *h2s)
 
                if (h2s->flags & H2_SF_DATA_CLEN && h2s->body_len) {
                        /* RFC7540#8.1.2 */
-                       h2c_report_glitch(h2c, 1);
+                       h2c_report_glitch(h2c, 1, "ES on DATA frame before content-length");
                        TRACE_ERROR("ES on DATA frame before content-length", H2_EV_RX_FRAME|H2_EV_RX_DATA, h2c->conn, h2s);
                        error = H2_ERR_PROTOCOL_ERROR;
                        HA_ATOMIC_INC(&h2c->px_counters->strm_proto_err);
@@ -3728,7 +3728,7 @@ static int h2_frame_check_vs_state(struct h2c *h2c, struct h2s *h2s)
                /* RFC7540#5.1: any frame other than HEADERS or PRIORITY in
                 * this state MUST be treated as a connection error
                 */
-               h2c_report_glitch(h2c, 1);
+               h2c_report_glitch(h2c, 1, "invalid frame type for IDLE state");
                TRACE_ERROR("invalid frame type for IDLE state", H2_EV_RX_FRAME|H2_EV_RX_FHDR, h2c->conn, h2s);
                h2c_error(h2c, H2_ERR_PROTOCOL_ERROR);
                if (!h2c->nb_streams && !(h2c->flags & H2_CF_IS_BACK)) {
@@ -3742,7 +3742,7 @@ static int h2_frame_check_vs_state(struct h2c *h2c, struct h2s *h2s)
 
        if (h2s->st == H2_SS_IDLE && (h2c->flags & H2_CF_IS_BACK)) {
                /* only PUSH_PROMISE would be permitted here */
-               h2c_report_glitch(h2c, 1);
+               h2c_report_glitch(h2c, 1, "invalid frame type for IDLE state (back)");
                TRACE_ERROR("invalid frame type for IDLE state (back)", H2_EV_RX_FRAME|H2_EV_RX_FHDR, h2c->conn, h2s);
                h2c_error(h2c, H2_ERR_PROTOCOL_ERROR);
                HA_ATOMIC_INC(&h2c->px_counters->conn_proto_err);
@@ -3758,13 +3758,13 @@ static int h2_frame_check_vs_state(struct h2c *h2c, struct h2s *h2s)
                 * PUSH_PROMISE/CONTINUATION cause connection errors.
                 */
                if (h2_ft_bit(h2c->dft) & H2_FT_HDR_MASK) {
-                       h2c_report_glitch(h2c, 1);
+                       h2c_report_glitch(h2c, 1, "invalid frame type for HREM state");
                        TRACE_ERROR("invalid frame type for HREM state", H2_EV_RX_FRAME|H2_EV_RX_FHDR, h2c->conn, h2s);
                        h2c_error(h2c, H2_ERR_PROTOCOL_ERROR);
                        HA_ATOMIC_INC(&h2c->px_counters->conn_proto_err);
                }
                else {
-                       h2c_report_glitch(h2c, 1);
+                       h2c_report_glitch(h2c, 1, "invalid frame type in HREM state");
                        h2s_error(h2s, H2_ERR_STREAM_CLOSED);
                }
                TRACE_DEVEL("leaving in error (hrem&!wu&!rst&!prio)", H2_EV_RX_FRAME|H2_EV_RX_FHDR|H2_EV_PROTO_ERR, h2c->conn, h2s);
@@ -3794,7 +3794,7 @@ static int h2_frame_check_vs_state(struct h2c *h2c, struct h2s *h2s)
                         * receives an unexpected stream identifier
                         * MUST respond with a connection error.
                         */
-                       h2c_report_glitch(h2c, 1);
+                       h2c_report_glitch(h2c, 1, "invalid frame type in CLOSED state");
                        h2c_error(h2c, H2_ERR_STREAM_CLOSED);
                        TRACE_DEVEL("leaving in error (closed&hdrmask)", H2_EV_RX_FRAME|H2_EV_RX_FHDR|H2_EV_PROTO_ERR, h2c->conn, h2s);
                        return 0;
@@ -3828,7 +3828,7 @@ static int h2_frame_check_vs_state(struct h2c *h2c, struct h2s *h2s)
                                h2c->rcvd_c += h2c->dfl - h2c->dpl;
                        }
 
-                       h2c_report_glitch(h2c, 1);
+                       h2c_report_glitch(h2c, 1, "invalid frame type after receiving RST_STREAM");
                        h2s_error(h2s, H2_ERR_STREAM_CLOSED);
                        h2c->st0 = H2_CS_FRAME_E;
                        TRACE_DEVEL("leaving in error (rst_rcvd&!hdrmask)", H2_EV_RX_FRAME|H2_EV_RX_FHDR|H2_EV_PROTO_ERR, h2c->conn, h2s);
@@ -3853,7 +3853,7 @@ static int h2_frame_check_vs_state(struct h2c *h2c, struct h2s *h2s)
                        if (h2c->dft != H2_FT_RST_STREAM &&
                            h2c->dft != H2_FT_PRIORITY &&
                            h2c->dft != H2_FT_WINDOW_UPDATE) {
-                               h2c_report_glitch(h2c, 1);
+                               h2c_report_glitch(h2c, 1, "ignoring unacceptable frame type after RST_STREAM sent");
                                h2c_error(h2c, H2_ERR_STREAM_CLOSED);
                                TRACE_DEVEL("leaving in error (rst_sent&!rst&!prio&!wu)", H2_EV_RX_FRAME|H2_EV_RX_FHDR|H2_EV_PROTO_ERR, h2c->conn, h2s);
                                return 0;
@@ -3991,7 +3991,7 @@ static void h2_process_demux(struct h2c *h2c)
                                if (h2c->st0 == H2_CS_ERROR) {
                                        if (b_data(&h2c->dbuf) ||
                                            !(((const struct session *)h2c->conn->owner)->fe->options & (PR_O_NULLNOLOG|PR_O_IGNORE_PRB)))
-                                               h2c_report_glitch(h2c, 1);
+                                               h2c_report_glitch(h2c, 1, "invalid preface received");
 
                                        TRACE_PROTO("failed to receive preface", H2_EV_RX_PREFACE|H2_EV_PROTO_ERR, h2c->conn);
                                        h2c->st0 = H2_CS_ERROR2;
@@ -4017,7 +4017,7 @@ static void h2_process_demux(struct h2c *h2c)
                                /* RFC7540#3.5: a GOAWAY frame MAY be omitted */
                                h2c->flags |= H2_CF_DEM_SHORT_READ;
                                if (h2c->st0 == H2_CS_ERROR) {
-                                       h2c_report_glitch(h2c, 1);
+                                       h2c_report_glitch(h2c, 1, "failed to receive settings");
                                        TRACE_ERROR("failed to receive settings", H2_EV_RX_FRAME|H2_EV_RX_FHDR|H2_EV_RX_SETTINGS|H2_EV_PROTO_ERR, h2c->conn);
                                        h2c->st0 = H2_CS_ERROR2;
                                        if (!(h2c->flags & H2_CF_IS_BACK))
@@ -4028,7 +4028,7 @@ static void h2_process_demux(struct h2c *h2c)
 
                        if (hdr.sid || hdr.ft != H2_FT_SETTINGS || hdr.ff & H2_F_SETTINGS_ACK) {
                                /* RFC7540#3.5: a GOAWAY frame MAY be omitted */
-                               h2c_report_glitch(h2c, 1);
+                               h2c_report_glitch(h2c, 1, "unexpected frame type or flags while waiting for SETTINGS");
                                TRACE_ERROR("unexpected frame type or flags", H2_EV_RX_FRAME|H2_EV_RX_FHDR|H2_EV_RX_SETTINGS|H2_EV_PROTO_ERR, h2c->conn);
                                h2c_error(h2c, H2_ERR_PROTOCOL_ERROR);
                                h2c->st0 = H2_CS_ERROR2;
@@ -4040,7 +4040,7 @@ static void h2_process_demux(struct h2c *h2c)
 
                        if ((int)hdr.len < 0 || (int)hdr.len > global.tune.bufsize) {
                                /* RFC7540#3.5: a GOAWAY frame MAY be omitted */
-                               h2c_report_glitch(h2c, 1);
+                               h2c_report_glitch(h2c, 1, "invalid settings frame length");
                                TRACE_ERROR("invalid settings frame length", H2_EV_RX_FRAME|H2_EV_RX_FHDR|H2_EV_RX_SETTINGS|H2_EV_PROTO_ERR, h2c->conn);
                                h2c_error(h2c, H2_ERR_FRAME_SIZE_ERROR);
                                h2c->st0 = H2_CS_ERROR2;
@@ -4086,7 +4086,7 @@ static void h2_process_demux(struct h2c *h2c)
                        }
 
                        if ((int)hdr.len < 0 || (int)hdr.len > global.tune.bufsize) {
-                               h2c_report_glitch(h2c, 1);
+                               h2c_report_glitch(h2c, 1, "invalid H2 frame length");
                                TRACE_ERROR("invalid H2 frame length", H2_EV_RX_FRAME|H2_EV_RX_FHDR|H2_EV_PROTO_ERR, h2c->conn);
                                h2c_error(h2c, H2_ERR_FRAME_SIZE_ERROR);
                                if (!h2c->nb_streams && !(h2c->flags & H2_CF_IS_BACK)) {
@@ -4117,7 +4117,7 @@ static void h2_process_demux(struct h2c *h2c)
                                 * padlen in the flow control, so it must be adjusted.
                                 */
                                if (hdr.len < 1) {
-                                       h2c_report_glitch(h2c, 1);
+                                       h2c_report_glitch(h2c, 1, "invalid H2 padded frame length");
                                        TRACE_ERROR("invalid H2 padded frame length", H2_EV_RX_FRAME|H2_EV_RX_FHDR|H2_EV_PROTO_ERR, h2c->conn);
                                        h2c_error(h2c, H2_ERR_FRAME_SIZE_ERROR);
                                        if (!(h2c->flags & H2_CF_IS_BACK))
@@ -4135,7 +4135,7 @@ static void h2_process_demux(struct h2c *h2c)
                                padlen = *(uint8_t *)b_peek(&h2c->dbuf, 9);
 
                                if (padlen > hdr.len) {
-                                       h2c_report_glitch(h2c, 1);
+                                       h2c_report_glitch(h2c, 1, "invalid H2 padding length");
                                        TRACE_ERROR("invalid H2 padding length", H2_EV_RX_FRAME|H2_EV_RX_FHDR|H2_EV_PROTO_ERR, h2c->conn);
                                        /* RFC7540#6.1 : pad length = length of
                                         * frame payload or greater => error.
@@ -4168,7 +4168,7 @@ static void h2_process_demux(struct h2c *h2c)
                        /* check for minimum basic frame format validity */
                        ret = h2_frame_check(h2c->dft, 1, h2c->dsi, h2c->dfl, global.tune.bufsize);
                        if (ret != H2_ERR_NO_ERROR) {
-                               h2c_report_glitch(h2c, 1);
+                               h2c_report_glitch(h2c, 1, "received invalid H2 frame header");
                                TRACE_ERROR("received invalid H2 frame header", H2_EV_RX_FRAME|H2_EV_RX_FHDR|H2_EV_PROTO_ERR, h2c->conn);
                                h2c_error(h2c, ret);
                                if (!(h2c->flags & H2_CF_IS_BACK))
@@ -4261,7 +4261,7 @@ static void h2_process_demux(struct h2c *h2c)
                         * frames' parsers consume all following CONTINUATION
                         * frames so this one is out of sequence.
                         */
-                       h2c_report_glitch(h2c, 1);
+                       h2c_report_glitch(h2c, 1, "received unexpected H2 CONTINUATION frame");
                        TRACE_ERROR("received unexpected H2 CONTINUATION frame", H2_EV_RX_FRAME|H2_EV_RX_CONT|H2_EV_H2C_ERR, h2c->conn, h2s);
                        h2c_error(h2c, H2_ERR_PROTOCOL_ERROR);
                        if (!(h2c->flags & H2_CF_IS_BACK))
@@ -5716,7 +5716,7 @@ next_frame:
 
                if (hdr.ft != H2_FT_CONTINUATION) {
                        /* RFC7540#6.10: frame of unexpected type */
-                       h2c_report_glitch(h2c, 1);
+                       h2c_report_glitch(h2c, 1, "not a CONTINUATION frame");
                        TRACE_STATE("not a CONTINUATION frame", H2_EV_RX_FRAME|H2_EV_RX_FHDR|H2_EV_RX_HDR|H2_EV_RX_CONT|H2_EV_H2C_ERR|H2_EV_PROTO_ERR, h2c->conn);
                        h2c_error(h2c, H2_ERR_PROTOCOL_ERROR);
                        HA_ATOMIC_INC(&h2c->px_counters->conn_proto_err);
@@ -5725,7 +5725,7 @@ next_frame:
 
                if (hdr.sid != h2c->dsi) {
                        /* RFC7540#6.10: frame of different stream */
-                       h2c_report_glitch(h2c, 1);
+                       h2c_report_glitch(h2c, 1, "CONTINUATION on different stream ID");
                        TRACE_STATE("CONTINUATION on different stream ID", H2_EV_RX_FRAME|H2_EV_RX_FHDR|H2_EV_RX_HDR|H2_EV_RX_CONT|H2_EV_H2C_ERR|H2_EV_PROTO_ERR, h2c->conn);
                        h2c_error(h2c, H2_ERR_PROTOCOL_ERROR);
                        HA_ATOMIC_INC(&h2c->px_counters->conn_proto_err);
@@ -5734,7 +5734,7 @@ next_frame:
 
                if ((unsigned)hdr.len > (unsigned)global.tune.bufsize) {
                        /* RFC7540#4.2: invalid frame length */
-                       h2c_report_glitch(h2c, 1);
+                       h2c_report_glitch(h2c, 1, "too large CONTINUATION frame");
                        TRACE_STATE("too large CONTIUATION frame", H2_EV_RX_FRAME|H2_EV_RX_FHDR|H2_EV_RX_HDR|H2_EV_RX_CONT|H2_EV_H2C_ERR|H2_EV_PROTO_ERR, h2c->conn);
                        h2c_error(h2c, H2_ERR_FRAME_SIZE_ERROR);
                        goto fail;
@@ -5781,7 +5781,7 @@ next_frame:
        if (h2c->dff & H2_F_HEADERS_PRIORITY) {
                if (read_n32(hdrs) == h2c->dsi) {
                        /* RFC7540#5.3.1 : stream dep may not depend on itself */
-                       h2c_report_glitch(h2c, 1);
+                       h2c_report_glitch(h2c, 1, "PRIORITY frame referencing itself");
                        TRACE_STATE("PRIORITY frame referencing itself", H2_EV_RX_FRAME|H2_EV_RX_HDR|H2_EV_H2C_ERR|H2_EV_PROTO_ERR, h2c->conn);
                        h2c_error(h2c, H2_ERR_PROTOCOL_ERROR);
                        HA_ATOMIC_INC(&h2c->px_counters->conn_proto_err);
@@ -5789,7 +5789,7 @@ next_frame:
                }
 
                if (flen < 5) {
-                       h2c_report_glitch(h2c, 1);
+                       h2c_report_glitch(h2c, 1, "too short PRIORITY frame");
                        TRACE_STATE("too short PRIORITY frame", H2_EV_RX_FRAME|H2_EV_RX_HDR|H2_EV_H2C_ERR|H2_EV_PROTO_ERR, h2c->conn);
                        h2c_error(h2c, H2_ERR_FRAME_SIZE_ERROR);
                        goto fail;
@@ -5841,7 +5841,7 @@ next_frame:
        }
 
        if (outlen < 0) {
-               h2c_report_glitch(h2c, 1);
+               h2c_report_glitch(h2c, 1, "failed to decompress HPACK");
                TRACE_STATE("failed to decompress HPACK", H2_EV_RX_FRAME|H2_EV_RX_HDR|H2_EV_H2C_ERR|H2_EV_PROTO_ERR, h2c->conn);
                h2c_error(h2c, H2_ERR_COMPRESSION_ERROR);
                goto fail;
@@ -5874,7 +5874,7 @@ next_frame:
 
        if (outlen < 0 || htx_free_space(htx) < global.tune.maxrewrite) {
                /* too large headers? this is a stream error only */
-               h2c_report_glitch(h2c, 1);
+               h2c_report_glitch(h2c, 1, "decompressed headers too large or invalid");
                TRACE_STATE("decompressed headers too large or invalid", H2_EV_RX_FRAME|H2_EV_RX_HDR|H2_EV_H2S_ERR|H2_EV_PROTO_ERR, h2c->conn);
                htx->flags |= HTX_FL_PARSING_ERROR;
                goto fail;
@@ -5910,7 +5910,7 @@ next_frame:
        if (h2c->dff & H2_F_HEADERS_END_STREAM) {
                if (msgf & H2_MSGF_RSP_1XX) {
                        /* RFC9113#8.1 : HEADERS frame with the ES flag set that carries an informational status code is malformed */
-                       h2c_report_glitch(h2c, 1);
+                       h2c_report_glitch(h2c, 1, "invalid interim response with ES flag");
                        TRACE_STATE("invalid interim response with ES flag", H2_EV_RX_FRAME|H2_EV_RX_HDR|H2_EV_H2C_ERR|H2_EV_PROTO_ERR, h2c->conn);
                        goto fail;
                }
@@ -5954,7 +5954,7 @@ next_frame:
         * its counter by 100.
         */
        if (unlikely(fragments > 4) && fragments > flen / 1024 && ret != 0) {
-               if (h2c_report_glitch(h2c, (fragments + 15) / 16)) {
+               if (h2c_report_glitch(h2c, (fragments + 15) / 16), "too many CONTINUATION frames") {
                        TRACE_STATE("glitch limit reached on CONTINUATION frame", H2_EV_RX_FRAME|H2_EV_RX_HDR|H2_EV_H2C_ERR|H2_EV_PROTO_ERR, h2c->conn);
                        ret = -1;
                }
@@ -5970,7 +5970,7 @@ next_frame:
        /* This is the last HEADERS frame hence a trailer */
        if (!(h2c->dff & H2_F_HEADERS_END_STREAM)) {
                /* It's a trailer but it's missing ES flag */
-               h2c_report_glitch(h2c, 1);
+               h2c_report_glitch(h2c, 1, "missing EH on trailers frame");
                TRACE_STATE("missing EH on trailers frame", H2_EV_RX_FRAME|H2_EV_RX_HDR|H2_EV_H2C_ERR|H2_EV_PROTO_ERR, h2c->conn);
                h2c_error(h2c, H2_ERR_PROTOCOL_ERROR);
                HA_ATOMIC_INC(&h2c->px_counters->conn_proto_err);