You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
lab-ops-hub: container validator's #577 backslash normalization overreaches into query and fragment — WHATWG keeps \ as data there, so ?q=a\b is fetched as ?q=a/b #620
The container validator's backslash normalization (#577, pkgs/lab-ops-hub/container/app.py in validate_crawl_url) replaces every\ in the whole input with / for http/https URLs. WHATWG treats a backslash as a path delimiter only in the scheme/authority/path portion of a special-scheme URL — in the query and fragment it is ordinary data and is kept verbatim. The container therefore judges and returns a different URL than the Worker for any spelling with a backslash after the ? or #.
Evidence (verified 2026-10-22, current main)
validate_crawl_url (Python) vs new URL(...).toString() (the Worker's serializer):
Input
Container returns
Worker returns
http://example.com/?q=a\b
http://example.com/?q=a/b
http://example.com/?q=a\b
http://example.com/#a\b
http://example.com/#a/b
http://example.com/#a\b
https://example.com/?q=a\b\c#x\y
https://example.com/?q=a/b/c#x/y
https://example.com/?q=a\b\c#x\y
http://example.com/a\b
http://example.com/a/b
http://example.com/a/b (path arm agrees — control)
Found by the 470-case ASCII differential run for #618; this was the only remaining returned-URL mismatch class outside structural-delimiter spellings.
The fragment arm changes the returned/recorded URL identity even though fragments are not fetched.
Acceptance criteria
The \ → / replacement applies only up to the first ? or # (the scheme/authority/path portion); backslashes in the query and fragment pass through verbatim, matching the Worker byte-for-byte.
New tests pin the query and fragment spellings in the table above.
Python suite (test_container_validate.py) and TS suite (lib.test.ts) both green.
Suggested fix
Split the input at the first ?/# before the replacement and rejoin afterwards — or scope the existing raw.replace("\\", "/") to the head segment — taking care that a \ inside the authority is still replaced even when a ? appears later in the same spelling (it does: the head segment includes the full authority and path).
Activity
Merge pull request #621 from developing-today/creator/620-backslash-s…