perf: fast path for normalized absolute special URLs#1
Conversation
Parsing an already-normalized absolute `http`/`https`/`ws`/`wss`/`ftp`
URL previously always went through the full WHATWG state machine. This
adds a single byte-scan fast path (modeled on ada-url's
`try_parse_simple_absolute`) that handles the overwhelmingly common case
of a clean URL — lower-case ASCII host, no credentials/port/IPv4/IDNA,
and path/query/fragment that need no percent-encoding or dot-segment
normalization — building the `Url` directly.
Anything that would require normalization, encoding, punycode, or
C0/tab/newline stripping returns `None` and defers to the general
parser, so behavior is unchanged. In debug builds every fast-path hit is
cross-checked field-by-field against the general parser, so the extensive
WPT `urltestdata` suite validates equivalence.
Benchmarks (`cargo bench -p url --bench parse_url`):
short 126 -> 70 ns (-44%)
long 149 -> 80 ns (-46%)
plain 112 -> 71 ns (-37%)
hyphen 153 -> 73 ns (-52%)
leading_digit 161 -> 72 ns (-55%)
fragment 160 -> 84 ns (-48%)
URLs not eligible for the fast path (port, IDNA, punycode) are unchanged.
Extend the normalized-URL fast path to also handle a port, as long as it is already in the form the general parser would serialize verbatim: all digits, in u16 range, no redundant leading zeros, and not the scheme's default port (which is otherwise stripped). Ports needing normalization still defer to the general parser. Bench (parse_url): port 149 -> 58 ns (-61%).
|
Extended the fast path to also cover a canonical New benchmark:
|
try_fast_parse only accepts complete absolute special URLs (scheme + "//"), which the WHATWG algorithm resolves without consulting the base. So drop the base_url.is_none() gate: base.join(abs_url) now takes the fast path and yields the same result as parsing abs_url standalone. The debug cross-check now re-parses through the general parser with the same base, so the WPT suite validates base-independence across its full base+input corpus. Adds a join_absolute benchmark. Bench (parse_url/join_absolute): 141 -> 84 ns/iter (-40%).
|
Relaxed the
New benchmark:
|
For a host made only of ASCII [A-Za-z0-9.-], IDNA's sole transformation is ASCII lower-casing, so the fast path can handle upper-case hosts by lower-casing the host itself (length-preserving, so all offsets stay valid). The xn-- and ends_in_a_number checks run on the lower-cased host. The debug cross-check (vs the general parser) and the WPT suite validate equivalence, including the many mixed-case host cases in urltestdata. Adds an uppercase_host benchmark. Bench (parse_url/uppercase_host): 194 -> 82 ns/iter (-58%).
|
Extended the fast path to accept mixed-case ASCII hosts (e.g. New benchmark:
|
Adds try_fast_parse_nonspecial, a sibling of the special-scheme fast path, for non-special URLs with an authority (redis://, postgres://, web+demo://, ...). These serialize verbatim: the host is an opaque host that is neither lower-cased nor IDNA/IPv4-processed, there is no default port, and an empty path stays empty. It accepts only inputs needing no transformation (clean ASCII opaque host, no credentials, canonical port, verbatim path/query/fragment, no dot-segments) and defers everything else to the general parser. Kept as a separate function so the special path is untouched. The debug cross-check (vs the general parser, same base) and the WPT suite validate equivalence. Adds a nonspecial_scheme benchmark. Bench (parse_url/nonspecial_scheme): 125 -> 51 ns/iter (-59%).
|
Added a sibling fast path for normalized absolute non-special URLs with an authority ( New benchmark:
|
The fast path previously bailed on any '%' in the path, sending common percent-encoded URLs (e.g. /wiki/C%2B%2B) through the full parser. The URL parser leaves '%' and its following bytes verbatim in the path; the only path normalization is dot-segments. So allow '%' as a verbatim path byte and expand the dot-segment guard from '.'/'..' to the exact set the parser rewrites, including the %2e/%2E escape forms (is_dot_path_segment). Applies to both the special and non-special path scans; the debug cross-check and WPT (rich in %2e/dot-segment cases) validate equivalence. Adds an encoded_path benchmark. Bench (parse_url/encoded_path): 214 -> 103 ns/iter (-52%).
|
Extended the fast path to accept percent-escapes in the path (e.g. New benchmark:
|
Special-scheme URLs with an IPv4 host previously always deferred (the host 'ends in a number'). But an already-canonical dotted-decimal address (four base-10 octets 0..=255, no leading zeros) serializes verbatim and maps straight to HostInternal::Ipv4. parse_canonical_ipv4 recognizes exactly that form and defers everything else (leading zeros, hex/octal, fewer than four parts) to the general IPv4 parser. The debug cross-check and WPT (extensive IPv4 coverage) validate equivalence. Adds an ipv4_host benchmark. Bench (parse_url/ipv4_host): 286 -> 81 ns/iter (-72%).
|
Extended the fast path to accept canonical dotted-decimal IPv4 hosts ( New benchmark:
|
Summary
Adds a single-pass fast path for parsing already-normalized absolute URLs, modeled on ada-url's
try_parse_simple_absolute.Today every
Url::parsecall runs the full WHATWG state machine (char-by-char iteration with tab/newline filtering, percent-encode set lookups, IDNA, etc.). The overwhelming majority of real-world URLs are already normalized. This PR adds two sibling byte-scan fast paths that construct theUrldirectly for them, deferring anything that needs normalization/encoding to the existing parser so observable behavior is unchanged:try_fast_parse— special schemes (http/https/ws/wss/ftp): clean ASCII host (mixed-case allowed, lower-cased like IDNA would), optional canonical port, verbatim path/query/fragment (percent-escapes in the path are kept verbatim; only dot-segments defer). Because it only accepts complete absolute URLs (scheme://…), which the WHATWG algorithm resolves without the base, it also servesUrl::joinwith an absolute argument.try_fast_parse_nonspecial— non-special schemes with an authority (redis://,postgres://,web+demo://, …), which serialize verbatim (opaque host, no lower-casing/IDNA/IPv4, no default port, empty path stays empty).Correctness
debug_check_fast_parse). The test suite runs in debug, so the full WPTurltestdatacorpus (thousands of URLs, many with base URLs, mixed-case hosts, and non-special schemes) validates byte-for-byte equivalence, including base-independence. This guard caught several subtle cases during development (xn--punycode labels, IPv4-looking hosts, default/leading-zero ports), all now deferred.test_fast_path_parsecovers accepted (special, ports, mixed-case, non-special), deferred, andjoin-vs-parseinputs explicitly (also runscheck_invariants).urltests pass (unit+wpt).Benchmarks
cargo bench -p url --bench parse_url(median of runs;unicode_*/punycode_*don't hit the fast path and are unchanged):