]> git.kaiwu.me - haproxy.git/commitdiff
MINOR: http: speed up http_header_has_forbidden_char() to make it work alone
authorWilly Tarreau <w@1wt.eu>
Wed, 4 Nov 2026 09:58:53 +0000 (10:58 +0100)
committerWilly Tarreau <w@1wt.eu>
Wed, 4 Nov 2026 21:45:33 +0000 (22:45 +0100)
The function reads one char at a time and is systematically hidden behind
a first call to ist_find_http_ctl() to speed up the lookup of control chars.
Unfortunately, this construct doesn't permit to find other control chars
such as 0x7F. Better make http_header_has_forbidden_char() self-sustaining,
but for this we need to implement the speedup there. For this, we start
with a loop using is_char8_outside(0x20,0x7e) that allows to fly over most
non-offending bytes (SP, VCHAR). Only HT (9) and obs-text (0x80..0xFF) will
exit early, which is not a problem given that they are extremely rare in
header values. After that we continue the loop to search for offending
bytes starting from the block of 4 or 8 that triggered.

include/haproxy/http.h

index 2f70a771908f87a824796f7c4f01bfe7c8e3b66c..4c269c477f0c2117fa88950f63f4d0465bd21ab3 100644 (file)
@@ -220,18 +220,34 @@ static inline struct http_uri_parser http_uri_parser_init(const struct ist uri)
 
 /* Looks into <ist> for forbidden characters for header values (0x00, 0x0A,
  * 0x0D), starting at pointer <start> which must be within <ist>. Returns
- * non-zero if such a character is found, 0 otherwise. When run on unlikely
- * header match, it's recommended to first check for the presence of control
- * chars using ist_find_http_ctl().
+ * non-zero if such a character is found, 0 otherwise.
  */
 static inline int http_header_has_forbidden_char(const struct ist ist, const char *start)
 {
-       do {
+       /* speed-up: skip 4 or 8 non-offending chars at once when possible.
+        * We only skip 0x20-0x7e here. The rest is handled one byte at a time.
+        */
+#ifdef HA_UNALIGNED_LE64
+       while (start <= istend(ist) - sizeof(long)) {
+               if (is_char8_outside(*(ulong *)start, 0x20, 0x7e))
+                       break;
+               start += sizeof(long);
+       }
+#elif defined(HA_UNALIGNED_LE)
+       while (start <= istend(ist) - sizeof(int)) {
+               if (is_char4_outside(*(uint *)start, 0x20, 0x7e))
+                       break;
+               start += sizeof(int);
+       }
+#endif
+       /* here we might have skipped most SP+VCHAR (0x20-0x7e). What commonly
+        * remains is HT (rare), CTL, CR/LF (forbidden), or obs-text.
+        */
+       for (; start < istend(ist); start++) {
                if ((uint8_t)*start <= 0x0d &&
                    (1U << (uint8_t)*start) & ((1<<13) | (1<<10) | (1<<0)))
                        return 1;
-               start++;
-       } while (start < istend(ist));
+       }
        return 0;
 }