Conversation
dd3ee23 to
0442cf1
Compare
0442cf1 to
656735c
Compare
52512ce to
25227f3
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.
Suppressed comments (3)
tools/benchmark/benchmark_HdrParse.cc:797
- The --profile unknown-target error message omits the supported "wks-lower"/"wkslower" target even though parse_target() accepts it, which can mislead users.
Target t = parse_target(profile_target);
if (t == Target::Unknown) {
std::fprintf(stderr, "unknown target '%s' (want: request|response|mime|url|wks)\n", profile_target.c_str());
return 2;
src/proxy/hdrs/HdrToken.cc:606
- hdrtoken_tokenize_prehashed()’s comment says it does an “exact ASCII-case-insensitive byte compare”, but the implementation currently only checks (hash, length) and returns the bucket token without validating the bytes. Either adjust the comment or add the byte-compare; adding the compare also prevents accidental or crafted hash/length collisions from being misclassified as a WKS token.
// WKS lookup for a name whose FNV-1a hash the caller has already computed
// (e.g. fused into the field-name scan). Does the slot/length narrowing plus
// the exact ASCII-case-insensitive byte compare, but no hashing and no
// interned-pointer test, so it is only valid for a non-interned `string`.
int
hdrtoken_tokenize_prehashed(const char *string, int string_len, uint32_t hash, const char **wks_string_out)
{
uint32_t slot = hash_to_slot(hash);
HdrTokenHashBucket *bucket = &(hdrtoken_hash_table[slot]);
if ((bucket->wks != nullptr) && (bucket->hash == hash) && (hdrtoken_wks_to_length(bucket->wks) == string_len)) {
int wks_idx = hdrtoken_wks_to_index(bucket->wks);
if (wks_string_out) {
*wks_string_out = bucket->wks;
}
return wks_idx;
}
src/proxy/hdrs/URL.cc:1210
- url_is_mostly_compliant() no longer emits the debug message that previously identified the first offending byte (whitespace/non-printable). That makes troubleshooting strict_uri_parsing=2 failures harder. You can keep the vectorized scan and only do a second scalar scan when an invalid byte was detected, to log the first bad value.
// Mode 2 accepts exactly the printable, non-space ASCII range 0x21..0x7E --
// equivalent to the previous isspace()/isprint() pair, but locale-independent
// and call-free. This runs on every request target under the default
// strict_uri_parsing=2. OR-reducing an out-of-range flag over the whole target
// (no early exit, no data-dependent branch) lets the compiler auto-vectorize
// the scan to the build's SIMD; ATS builds -O3, where clang and GCC both do.
unsigned char bad = 0;
for (const char *i = start; i < end; ++i) {
unsigned char const c = static_cast<unsigned char>(*i);
bad |= static_cast<unsigned char>((c < 0x21) | (c > 0x7E));
}
return bad == 0;
25227f3 to
c0d1671
Compare
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Pull request overview
Copilot reviewed 9 out of 9 changed files in this pull request and generated 5 comments.
| int | ||
| hdrtoken_field_name_scan(const char *string, int maxlen, uint32_t *hash_out, bool *all_valid_out) | ||
| { | ||
| uint32_t hval = HDRTOKEN_HASH_SEED; // same FNV-1a name hash as hdrtoken_hash | ||
| bool all_valid = true; | ||
| int i = 0; | ||
|
|
||
| for (; i < maxlen; ++i) { | ||
| unsigned char const uc = static_cast<unsigned char>(string[i]); | ||
| if (uc == ':') { | ||
| break; | ||
| } | ||
| hval = hdrtoken_hash_step(hval, hdrtoken_ascii_toupper(uc)); | ||
| all_valid &= (ParseRules::is_http_field_name(static_cast<char>(uc)) != 0); | ||
| } | ||
|
|
||
| *hash_out = hval; | ||
| *all_valid_out = all_valid; | ||
| return (i < maxlen) ? i : -1; |
There was a problem hiding this comment.
hash_out is gone from hdrtoken_tokenize — it was dead, its only caller wrote it and never read it back.
For hdrtoken_field_name_scan both out-params are now documented as required rather than made optional. It is a hot-path helper with two in-tree callers; a conditional store would hide a caller bug instead of surfacing it.
| if (!profile_target.empty()) { | ||
| Target t = parse_target(profile_target); | ||
| if (t == Target::Unknown) { | ||
| std::fprintf(stderr, "unknown target '%s' (want: request|response|mime|url|wks)\n", profile_target.c_str()); |
There was a problem hiding this comment.
Added wks-lower to the list.
Header parsing needs repeatable measurements before its hot paths can be optimized. Cover zero-copy parsing under the default strict URI mode, copied inputs, modern browser headers, duplicate-heavy responses, and canonical and lowercase WKS names in one harness. Include a profiling loop and file-loaded corpora for investigating representative workloads.
Default URI validation pays for libc character classification on every byte. Use a branchless ASCII range reduction to enable vectorization and make acceptance locale-independent; rejection no longer logs the offending byte. Exhaustive differential tests cover every byte value across vector boundaries and scalar tails.
Request-target validation calls three URL getters and follows branches that reduce to a direct test of the stored host and scheme fields. Express that condition directly while preserving the existing treatment of origin, asterisk, absolute, and authority forms.
Field names were walked separately to find the colon, hash the name, and validate its characters. Fuse those passes and reuse the WKS lookup through a prehashed entry point, preserving whitespace normalization and the current table representation. Parity tests check the delimiter position, character validation, and token lookup.
A clear presence bit already proves that a well-known field has no duplicate in the header. Use that result when attaching parsed fields to avoid redundant lookup work. Well-known names without a presence mask and non-well-known names retain the normal duplicate search.
Consecutive fields such as Set-Cookie repeatedly search an existing duplicate chain even though their predecessor is already its tail. Derive that predecessor from the current header block and append directly, avoiding parser-held pointers that could outlive the header. Tests compare duplicate chains with normal attachment and cover parser reuse after a header is destroyed.
c0d1671 to
238fb0c
Compare
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Pull request overview
Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.
| extern void hdrtoken_init(); | ||
| extern int hdrtoken_tokenize(const char *string, int string_len, const char **wks_string_out = nullptr); | ||
| extern int hdrtoken_tokenize_prehashed(const char *string, int string_len, uint32_t hash, const char **wks_string_out = nullptr); | ||
| extern int hdrtoken_field_name_scan(const char *string, int maxlen, uint32_t *hash_out, bool *all_valid_out); | ||
| extern int hdrtoken_method_tokenize(const char *string, int string_len); |
| hdrtoken_field_name_scan(const char *string, int maxlen, uint32_t *hash_out, bool *all_valid_out) | ||
| { | ||
| uint32_t hval = HDRTOKEN_HASH_SEED; // same FNV-1a name hash as hdrtoken_hash | ||
| bool all_valid = true; | ||
| int i = 0; | ||
|
|
||
| for (; i < maxlen; ++i) { | ||
| unsigned char const uc = static_cast<unsigned char>(string[i]); | ||
| if (uc == ':') { | ||
| break; | ||
| } | ||
| hval = hdrtoken_hash_step(hval, hdrtoken_ascii_toupper(uc)); | ||
| all_valid &= (ParseRules::is_http_field_name(static_cast<char>(uc)) != 0); | ||
| } | ||
|
|
||
| *hash_out = hval; | ||
| *all_valid_out = all_valid; | ||
| return (i < maxlen) ? i : -1; | ||
| } |
| bad |= static_cast<unsigned char>((c < 0x21) | (c > 0x7E)); | ||
| } | ||
| return true; | ||
| return bad == 0; |
| auto t1 = std::chrono::steady_clock::now(); | ||
| double ns = std::chrono::duration<double, std::nano>(t1 - t0).count(); | ||
| double ns_per = ns / static_cast<double>(count); | ||
|
|
Reduce repeated work in HTTP header parsing.
Includes a header parsing benchmark harness and regression tests for validation, field-name scanning, duplicate attachment, and parser reuse.