]> git.kaiwu.me - haproxy.git/commitdiff
MEDIUM: http: add the "short-status-code" violation exception
authorWilly Tarreau <w@1wt.eu>
Wed, 21 Oct 2026 06:51:18 +0000 (08:51 +0200)
committerWilly Tarreau <w@1wt.eu>
Wed, 21 Oct 2026 15:41:42 +0000 (17:41 +0200)
Now by default we reject status codes shorter than 3 digits, though
this exception permits to continue to accept them. There is no valid
reason for accepting these and no known client currently supports
them, but it has been supported due to historical reasons that are
long outdated.

It is expected that noone will notice, and may be candidate for
backporting only to the latest LTS version after some observation
time.

doc/configuration.txt
include/haproxy/http-t.h
src/h1.c
src/http.c

index e57ad909858871961354cf4df2af3d1d69a2ba24..25bae693885865a321738b25ff722038c20b5f2f 100644 (file)
@@ -2208,6 +2208,11 @@ acceptable-http-response-violations { [-+]<http-violation>[,...] }
       risk is moderate. Only ever enable this with known clients if absolutely
       needed.
 
+    - "short-status-code" (response): this controls acceptance of status codes
+      shorter than 3 characters (e.g. "0" or "99"). A lazy regex-based parser
+      in a client may get confused. The risk is low. Only ever enable this with
+      known clients if really needed.
+
     - "non-token-in-header-name" (both): this controls the acceptance of
       forbidden characters in header field names. It is often used to adapt to
       internally developed non-standard applications which use forbidden
index 385088099b813e6ee4114cd7ac1076b0a18ee7b8..4a003f81e6266a3d6414f4703c04402d99f097f5 100644 (file)
@@ -211,6 +211,7 @@ enum http_violation_idx {
        HTTP_VIO_URL_FRAG = 0,     // fragment in url ('#')
        HTTP_VIO_URL_NON_ASCII,    // non-ASCII (>=128) in URL
        HTTP_VIO_STATUS_LONG,      // status longer than 3 characters
+       HTTP_VIO_STATUS_SHORT,     // status shorter than 3 characters
        HTTP_VIO_HDR_NAME_NON_TOK, // non-token in header name
        HTTP_VIO_HDR_VALUE_NUL,    // NUL byte in header value
        HTTP_VIO_TE_BAD,           // inconsistent transfer encoding
index 8608c99c1cb0d9885eada88d1f418d800eb8a433..8a1d455d7c6aa32d3434cde1f9e493e03048bdd4 100644 (file)
--- a/src/h1.c
+++ b/src/h1.c
@@ -765,6 +765,16 @@ int h1_headers_to_hdr_list(char *start, const char *stop,
 
                if (likely(HTTP_IS_SPHT(*ptr))) {
                        sl.st.c.len = ptr - sl.st.c.ptr;
+                       if (sl.st.c.len < 3) {
+                               /* less than 3 digits */
+                               if (h1m->err_pos < -1 || !(global.acc_hres_vio & (1U << HTTP_VIO_STATUS_SHORT))) {
+                                       state = H1_MSG_RPCODE;
+                                       goto http_msg_invalid;
+                               } else if (h1m->err_pos == -1) {
+                                       /* only capture the error pointer */
+                                       h1m->err_pos = ptr - start + skip;
+                               }
+                       }
                        EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rpcode_sp, http_msg_ood, state, H1_MSG_RPCODE_SP);
                }
 
index 3c99bd3541da23136b8b5427137eef9bb65c6378..33b5116ddfde44a384412d4a2abe99ae04b68ba8 100644 (file)
@@ -1634,6 +1634,7 @@ const struct http_violation http_violations[] = {
        { "fragment-in-url",                HTTP_VIO_URL_FRAG,         HTTP_DIR_REQ  },
        { "non-ascii-in-url",               HTTP_VIO_URL_NON_ASCII,    HTTP_DIR_REQ  },
        { "long-status-code",               HTTP_VIO_STATUS_LONG,      HTTP_DIR_RES  },
+       { "short-status-code",              HTTP_VIO_STATUS_SHORT,     HTTP_DIR_RES  },
        { "non-token-in-header-name",       HTTP_VIO_HDR_NAME_NON_TOK, HTTP_DIR_BOTH },
        { "nul-in-header-value",            HTTP_VIO_HDR_VALUE_NUL,    HTTP_DIR_BOTH },
        { "inconsistent-transfer-encoding", HTTP_VIO_TE_BAD,           HTTP_DIR_RES  },