]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINIR: mux-h1: Return 414 or 431 when appropriate
authorChristopher Faulet <cfaulet@haproxy.com>
Mon, 18 Nov 2024 21:19:00 +0000 (22:19 +0100)
committerChristopher Faulet <cfaulet@haproxy.com>
Tue, 19 Nov 2024 14:29:40 +0000 (15:29 +0100)
When the request is too large to fit in a buffer a 414 or a 431 error
message is returned depending on the error state of the request parser. A
414 is returned if the URI is too long, otherwise a 431 is returned.

This patch should fix the issue #1309.

include/haproxy/h1.h
src/h1_htx.c
src/mux_h1.c

index b4e66908e03f7e43c187d66eebeb7e75c322cd11..5dcbc4f80da9e1f4455e750a12f219e465a4a1b0 100644 (file)
@@ -131,6 +131,7 @@ struct h1m {
        uint64_t curr_len;          // content-length or last chunk length
        uint64_t body_len;          // total known size of the body length
        uint32_t next;              // next byte to parse, relative to buffer's head
+       unsigned int err_code;      // the HTTP status code corresponding to the error, if it can be specified (0: unset)
        int err_pos;                // position in the byte stream of the first error (H1 or H2)
        int err_state;              // state where the first error was met (H1 or H2)
 };
@@ -358,6 +359,7 @@ static inline struct h1m *h1m_init_req(struct h1m *h1m)
        h1m->flags = H1_MF_NONE;
        h1m->curr_len = 0;
        h1m->body_len = 0;
+       h1m->err_code = 0;
        h1m->err_pos = -2;
        h1m->err_state = 0;
        return h1m;
@@ -371,6 +373,7 @@ static inline struct h1m *h1m_init_res(struct h1m *h1m)
        h1m->flags = H1_MF_RESP;
        h1m->curr_len = 0;
        h1m->body_len = 0;
+       h1m->err_code = 0;
        h1m->err_pos = -2;
        h1m->err_state = 0;
        return h1m;
index 37364b8c299adb469bbc60a92200817d9115f83c..33a86faa7fa0dce42b5ce38dff3aadd43ff36f92 100644 (file)
@@ -163,8 +163,10 @@ static int h1_postparse_req_hdrs(struct h1m *h1m, union h1_sl *h1sl, struct htx
         * size allowed.
         */
        if (h1_eval_htx_size(meth, uri, vsn, hdrs) > max) {
-               if (htx_is_empty(htx))
+               if (htx_is_empty(htx)) {
+                       h1m->err_code = 431;
                        goto error;
+               }
                goto output_full;
        }
 
@@ -364,8 +366,13 @@ int h1_parse_msg_hdrs(struct h1m *h1m, union h1_sl *h1sl, struct htx *dsthtx,
                 * contains headers and is full, which is detected by it being
                 * full and the offset to be zero, it's an error because
                 * headers are too large to be handled by the parser. */
-               if (ret < 0 || (!ret && !ofs && !buf_room_for_htx_data(srcbuf)))
+               if (ret < 0)
+                       goto error;
+               if (!ret && !ofs && !buf_room_for_htx_data(srcbuf)) {
+                       if (!(h1m->flags & H1_MF_RESP))
+                               h1m->err_code = (h1m->err_state < H1_MSG_HDR_FIRST) ? 414: 431;
                        goto error;
+               }
                goto end;
        }
        total = ret;
index 65044776387bea0ae435c64f1fc4e3df4ae18073..0382427634f5fd4c08ce98f4041204eb78adff6f 100644 (file)
@@ -1926,6 +1926,8 @@ static size_t h1_handle_headers(struct h1s *h1s, struct h1m *h1m, struct htx *ht
                TRACE_DEVEL("leaving on missing data or error", H1_EV_RX_DATA|H1_EV_RX_HDRS, h1s->h1c->conn, h1s);
                if (ret == -1) {
                        h1s->flags |= H1S_F_PARSING_ERROR;
+                       if (h1m->err_code)
+                               h1s->h1c->errcode = h1m->err_code;
                        TRACE_ERROR("parsing error, reject H1 message", H1_EV_RX_DATA|H1_EV_RX_HDRS|H1_EV_H1S_ERR, h1s->h1c->conn, h1s);
                        h1_capture_bad_message(h1s->h1c, h1s, h1m, buf);
                }