From: Willy Tarreau Date: Wed, 4 Nov 2026 09:58:53 +0000 (+0100) Subject: MINOR: http: speed up http_header_has_forbidden_char() to make it work alone X-Git-Tag: v3.5-dev11~11 X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=de80a2699cddb10a475d9c90c0ad1225f83bd556;p=haproxy.git MINOR: http: speed up http_header_has_forbidden_char() to make it work alone 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. --- diff --git a/include/haproxy/http.h b/include/haproxy/http.h index 2f70a7719..4c269c477 100644 --- a/include/haproxy/http.h +++ b/include/haproxy/http.h @@ -220,18 +220,34 @@ static inline struct http_uri_parser http_uri_parser_init(const struct ist uri) /* Looks into for forbidden characters for header values (0x00, 0x0A, * 0x0D), starting at pointer which must be within . 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; }