diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 33e520bc7..48fefbb87 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -49,12 +49,12 @@ jobs: # Run tests enabling the serde feature - name: Run tests with the serde feature run: cargo test --features "url/serde,url/expose_internals" - # The #[debugger_visualizer] attribute is currently gated behind an unstable feature flag. - # In order to test the visualizers for the url crate, they have to be tested on a nightly build. + # The #[debugger_visualizer] attribute is currently gated behind a feature flag until #[debugger_visualizer] + # is available in all rustc versions past our MSRV. As such, we only run the tests on newer rustc versions. - name: Run debugger_visualizer tests if: | matrix.os == 'windows-latest' && - matrix.rust == 'nightly' + matrix.rust != '1.56.0' run: cargo test --test debugger_visualizer --features "url/debugger_visualizer,url_debug_tests/debugger_visualizer" -- --test-threads=1 - name: Test `no_std` support run: cargo test --no-default-features --features=alloc,no_std_net diff --git a/debug_metadata/README.md b/debug_metadata/README.md index 785a45467..ddf038d16 100644 --- a/debug_metadata/README.md +++ b/debug_metadata/README.md @@ -22,8 +22,8 @@ types, descibe how to display those types. (For writing a pretty printer, see: h ### Embedding Visualizers -Through the use of the currently unstable `#[debugger_visualizer]` attribute, the `url` -crate can embed debugger visualizers into the crate metadata. +Through the use of the `#[debugger_visualizer]` attribute, the `url` crate can embed +debugger visualizers into the crate metadata. Currently the two types of visualizers supported are Natvis and Pretty printers. diff --git a/url/Cargo.toml b/url/Cargo.toml index fb985d28a..ca7977fdd 100644 --- a/url/Cargo.toml +++ b/url/Cargo.toml @@ -32,13 +32,13 @@ no-std-net = { version = "0.6.0", default-features = false, optional = true } default = ["std"] std = ["idna/std", "percent-encoding/std", "form_urlencoded/std", "alloc"] alloc = [] -# UNSTABLE FEATURES (requires Rust nightly) -# Enable to use the #[debugger_visualizer] attribute. +# Enable to use the #[debugger_visualizer] attribute. This feature requires Rust >= 1.71. debugger_visualizer = [] # Expose internal offsets of the URL. expose_internals = [] # For no_std: Allow the use of no_std_net instead of nightly no_std_net = ["no-std-net"] +# UNSTABLE FEATURES (requires Rust nightly) # For no_std: Use errors_in_core and net_in_core unstable = ["idna/unstable"] diff --git a/url/src/lib.rs b/url/src/lib.rs index c785183e3..a7acdb22f 100644 --- a/url/src/lib.rs +++ b/url/src/lib.rs @@ -119,13 +119,25 @@ See [serde documentation](https://serde.rs) for more information. url = { version = "2", features = ["serde"] } ``` +# Feature: `debugger_visualizer` + +If you enable the `debugger_visualizer` feature, the `url` crate will include +a [natvis file](https://docs.microsoft.com/en-us/visualstudio/debugger/create-custom-views-of-native-objects) +for [Visual Studio](https://www.visualstudio.com/) that allows you to view +[`Url`](struct.Url.html) objects in the debugger. + +This feature requires Rust 1.71 or later. + +```toml +url = { version = "2", features = ["debugger_visualizer"] } +``` + */ #![no_std] #![doc(html_root_url = "https://docs.rs/url/2.4.0")] #![cfg_attr( feature = "debugger_visualizer", - feature(debugger_visualizer), debugger_visualizer(natvis_file = "../../debug_metadata/url.natvis") )] #![cfg_attr( diff --git a/url/tests/expected_failures.txt b/url/tests/expected_failures.txt index 229636de7..1c404a8b7 100644 --- a/url/tests/expected_failures.txt +++ b/url/tests/expected_failures.txt @@ -1,12 +1,12 @@ against - against - against - against - against - against - against - against - against + + + + + + + + against <\\/localhost//pig> against against @@ -19,19 +19,35 @@ against against against - against - against - against + + + against against against against - against - against - against + + + against against against - against - against - against + + + set hostname to + set hostname to + set hostname to + set hostname to <> + set pathname to <> + set pathname to <> + set port to + set href to + set search to <> + set search to <> + set pathname to <\\\\> + set pathname to + set pathname to + set pathname to + set pathname to + set pathname to + set pathname to

\ No newline at end of file diff --git a/url/tests/setters_tests.json b/url/tests/setters_tests.json index 6a922af92..2c6ebee64 100644 --- a/url/tests/setters_tests.json +++ b/url/tests/setters_tests.json @@ -1,6 +1,6 @@ { "comment": [ - "AS OF https://github.com/web-platform-tests/wpt/blob/09b34ae130cd946e111cd427d6bcf2d6f257aed8/url/resources/setters_tests.json, but only passing tests", + "# Pulled from https://github.com/web-platform-tests/wpt/blob/befe66343e5f21dc464c8c772c6d20695936714f/url/resources/setters_tests.json", "## Tests for setters of https://url.spec.whatwg.org/#urlutils-members", "", "This file contains a JSON object.", @@ -120,11 +120,11 @@ } }, { - "href": "gopher://example.net:1234", + "href": "https://example.net:1234", "new_value": "file", "expected": { - "href": "gopher://example.net:1234", - "protocol": "gopher:" + "href": "https://example.net:1234/", + "protocol": "https:" } }, { @@ -146,7 +146,7 @@ }, { "href": "file:///test", - "new_value": "gopher", + "new_value": "https", "expected": { "href": "file:///test", "protocol": "file:" @@ -270,6 +270,57 @@ "protocol": "https:", "port": "" } + }, + { + "comment": "Tab and newline are stripped", + "href": "http://test/", + "new_value": "h\u000D\u000Att\u0009ps", + "expected": { + "href": "https://test/", + "protocol": "https:", + "port": "" + } + }, + { + "href": "http://test/", + "new_value": "https\u000D", + "expected": { + "href": "https://test/", + "protocol": "https:" + } + }, + { + "comment": "Non-tab/newline C0 controls result in no-op", + "href": "http://test/", + "new_value": "https\u0000", + "expected": { + "href": "http://test/", + "protocol": "http:" + } + }, + { + "href": "http://test/", + "new_value": "https\u000C", + "expected": { + "href": "http://test/", + "protocol": "http:" + } + }, + { + "href": "http://test/", + "new_value": "https\u000E", + "expected": { + "href": "http://test/", + "protocol": "http:" + } + }, + { + "href": "http://test/", + "new_value": "https\u0020", + "expected": { + "href": "http://test/", + "protocol": "http:" + } } ], "username": [ @@ -962,6 +1013,16 @@ "port": "" } }, + { + "href": "file://hi/x", + "new_value": "", + "expected": { + "href": "file:///x", + "host": "", + "hostname": "", + "port": "" + } + }, { "href": "sc://test@test/", "new_value": "", @@ -981,6 +1042,62 @@ "hostname": "test", "port": "12" } + }, + { + "comment": "Leading / is not stripped", + "href": "http://example.com/", + "new_value": "///bad.com", + "expected": { + "href": "http://example.com/", + "host": "example.com", + "hostname": "example.com" + } + }, + { + "comment": "Leading / is not stripped", + "href": "sc://example.com/", + "new_value": "///bad.com", + "expected": { + "href": "sc:///", + "host": "", + "hostname": "" + } + }, + { + "href": "https://example.com/", + "new_value": "a%C2%ADb", + "expected": { + "href": "https://ab/", + "host": "ab", + "hostname": "ab" + } + }, + { + "href": "https://example.com/", + "new_value": "\u00AD", + "expected": { + "href": "https://example.com/", + "host": "example.com", + "hostname": "example.com" + } + }, + { + "href": "https://example.com/", + "new_value": "%C2%AD", + "expected": { + "href": "https://example.com/", + "host": "example.com", + "hostname": "example.com" + } + }, + { + "href": "https://example.com/", + "new_value": "xn--", + "expected": { + "href": "https://example.com/", + "host": "example.com", + "hostname": "example.com" + } } ], "hostname": [ @@ -1144,24 +1261,24 @@ } }, { - "comment": "Stuff after a : delimiter is ignored", + "comment": ": delimiter invalidates entire value", "href": "http://example.net/path", "new_value": "example.com:8080", "expected": { - "href": "http://example.com/path", - "host": "example.com", - "hostname": "example.com", + "href": "http://example.net/path", + "host": "example.net", + "hostname": "example.net", "port": "" } }, { - "comment": "Stuff after a : delimiter is ignored", + "comment": ": delimiter invalidates entire value", "href": "http://example.net:8080/path", "new_value": "example.com:", "expected": { - "href": "http://example.com:8080/path", - "host": "example.com:8080", - "hostname": "example.com", + "href": "http://example.net:8080/path", + "host": "example.net:8080", + "hostname": "example.net", "port": "8080" } }, @@ -1286,6 +1403,16 @@ "port": "" } }, + { + "href": "file://hi/x", + "new_value": "", + "expected": { + "href": "file:///x", + "host": "", + "hostname": "", + "port": "" + } + }, { "href": "sc://test@test/", "new_value": "", @@ -1305,6 +1432,83 @@ "hostname": "test", "port": "12" } + }, + { + "comment": "Drop /. from path", + "href": "non-spec:/.//p", + "new_value": "h", + "expected": { + "href": "non-spec://h//p", + "host": "h", + "hostname": "h", + "pathname": "//p" + } + }, + { + "href": "non-spec:/.//p", + "new_value": "", + "expected": { + "href": "non-spec:////p", + "host": "", + "hostname": "", + "pathname": "//p" + } + }, + { + "comment": "Leading / is not stripped", + "href": "http://example.com/", + "new_value": "///bad.com", + "expected": { + "href": "http://example.com/", + "host": "example.com", + "hostname": "example.com" + } + }, + { + "comment": "Leading / is not stripped", + "href": "sc://example.com/", + "new_value": "///bad.com", + "expected": { + "href": "sc:///", + "host": "", + "hostname": "" + } + }, + { + "href": "https://example.com/", + "new_value": "a%C2%ADb", + "expected": { + "href": "https://ab/", + "host": "ab", + "hostname": "ab" + } + }, + { + "href": "https://example.com/", + "new_value": "\u00AD", + "expected": { + "href": "https://example.com/", + "host": "example.com", + "hostname": "example.com" + } + }, + { + "href": "https://example.com/", + "new_value": "%C2%AD", + "expected": { + "href": "https://example.com/", + "host": "example.com", + "hostname": "example.com" + } + }, + { + "href": "https://example.com/", + "new_value": "xn--", + "expected": { + "href": "https://example.com/", + "host": "example.com", + "hostname": "example.com" + } } ], "port": [ @@ -1461,6 +1665,17 @@ "port": "8080" } }, + { + "comment": "Setting port to a string that doesn't parse as a number", + "href": "http://example.net:8080/path", + "new_value": "randomstring", + "expected": { + "href": "http://example.net:8080/path", + "host": "example.net:8080", + "hostname": "example.net", + "port": "8080" + } + }, { "comment": "Port numbers are 16 bit integers, overflowing is an error", "href": "non-special://example.net:8080/path", @@ -1519,11 +1734,35 @@ "href": "javascript://x:12/", "port": "12" } + }, + { + "comment": "Leading u0009 on special scheme", + "href": "https://domain.com:443", + "new_value": "\u00098080", + "expected": { + "port": "8080" + } + }, + { + "comment": "Leading u0009 on non-special scheme", + "href": "wpt++://domain.com:443", + "new_value": "\u00098080", + "expected": { + "port": "8080" + } + }, + { + "comment": "Should use all ascii prefixed characters as port", + "href": "https://www.google.com:4343", + "new_value": "4wpt", + "expected": { + "port": "4" + } } ], "pathname": [ { - "comment": "Cannot-be-a-base don’t have a path", + "comment": "Opaque paths cannot be set", "href": "mailto:me@example.net", "new_value": "/foo", "expected": { @@ -1531,6 +1770,67 @@ "pathname": "me@example.net" } }, + { + "href": "data:original", + "new_value": "new value", + "expected": { + "href": "data:original", + "pathname": "original" + } + }, + { + "href": "sc:original", + "new_value": "new value", + "expected": { + "href": "sc:original", + "pathname": "original" + } + }, + { + "comment": "Special URLs cannot have their paths erased", + "href": "file:///some/path", + "new_value": "", + "expected": { + "href": "file:///", + "pathname": "/" + } + }, + { + "comment": "Non-special URLs can have their paths erased", + "href": "foo://somehost/some/path", + "new_value": "", + "expected": { + "href": "foo://somehost", + "pathname": "" + } + }, + { + "comment": "Non-special URLs with an empty host can have their paths erased", + "href": "foo:///some/path", + "new_value": "", + "expected": { + "href": "foo://", + "pathname": "" + } + }, + { + "comment": "Path-only URLs cannot have their paths erased", + "href": "foo:/some/path", + "new_value": "", + "expected": { + "href": "foo:/", + "pathname": "/" + } + }, + { + "comment": "Path-only URLs always have an initial slash", + "href": "foo:/some/path", + "new_value": "test", + "expected": { + "href": "foo:/test", + "pathname": "/test" + } + }, { "href": "unix:/run/foo.socket?timeout=10", "new_value": "/var/log/../run/bar.socket", @@ -1627,13 +1927,31 @@ "pathname": "/%23" } }, + { + "comment": "? doesn't mess up encoding", + "href": "http://example.net", + "new_value": "/?é", + "expected": { + "href": "http://example.net/%3F%C3%A9", + "pathname": "/%3F%C3%A9" + } + }, + { + "comment": "# doesn't mess up encoding", + "href": "http://example.net", + "new_value": "/#é", + "expected": { + "href": "http://example.net/%23%C3%A9", + "pathname": "/%23%C3%A9" + } + }, { "comment": "File URLs and (back)slashes", "href": "file://monkey/", "new_value": "\\\\", "expected": { - "href": "file://monkey/", - "pathname": "/" + "href": "file://monkey//", + "pathname": "//" } }, { @@ -1641,8 +1959,8 @@ "href": "file:///unicorn", "new_value": "//\\/", "expected": { - "href": "file:///", - "pathname": "/" + "href": "file://////", + "pathname": "////" } }, { @@ -1650,8 +1968,59 @@ "href": "file:///unicorn", "new_value": "//monkey/..//", "expected": { - "href": "file:///", - "pathname": "/" + "href": "file://///", + "pathname": "///" + } + }, + { + "comment": "Serialize /. in path", + "href": "non-spec:/", + "new_value": "/.//p", + "expected": { + "href": "non-spec:/.//p", + "pathname": "//p" + } + }, + { + "href": "non-spec:/", + "new_value": "/..//p", + "expected": { + "href": "non-spec:/.//p", + "pathname": "//p" + } + }, + { + "href": "non-spec:/", + "new_value": "//p", + "expected": { + "href": "non-spec:/.//p", + "pathname": "//p" + } + }, + { + "comment": "Drop /. from path", + "href": "non-spec:/.//", + "new_value": "p", + "expected": { + "href": "non-spec:/p", + "pathname": "/p" + } + }, + { + "comment": "Non-special URLs with non-opaque paths percent-encode U+0020", + "href": "data:/nospace", + "new_value": "space ", + "expected": { + "href": "data:/space%20", + "pathname": "/space%20" + } + }, + { + "href": "sc:/nospace", + "new_value": "space ", + "expected": { + "href": "sc:/space%20", + "pathname": "/space%20" } }, { @@ -1756,6 +2125,42 @@ "search": "?%c3%89t%C3%A9" } }, + { + "comment": "Drop trailing spaces from trailing opaque paths", + "href": "data:space ?query", + "new_value": "", + "expected": { + "href": "data:space", + "pathname": "space", + "search": "" + } + }, + { + "href": "sc:space ?query", + "new_value": "", + "expected": { + "href": "sc:space", + "pathname": "space", + "search": "" + } + }, + { + "comment": "Do not drop trailing spaces from non-trailing opaque paths", + "href": "data:space ?query#fragment", + "new_value": "", + "expected": { + "href": "data:space #fragment", + "search": "" + } + }, + { + "href": "sc:space ?query#fragment", + "new_value": "", + "expected": { + "href": "sc:space #fragment", + "search": "" + } + }, { "comment": "Trailing space should be encoded", "href": "http://example.net", @@ -1908,6 +2313,42 @@ "hash": "#castle" } }, + { + "comment": "Drop trailing spaces from trailing opaque paths", + "href": "data:space #fragment", + "new_value": "", + "expected": { + "href": "data:space", + "pathname": "space", + "hash": "" + } + }, + { + "href": "sc:space #fragment", + "new_value": "", + "expected": { + "href": "sc:space", + "pathname": "space", + "hash": "" + } + }, + { + "comment": "Do not drop trailing spaces from non-trailing opaque paths", + "href": "data:space ?query#fragment", + "new_value": "", + "expected": { + "href": "data:space ?query", + "hash": "" + } + }, + { + "href": "sc:space ?query#fragment", + "new_value": "", + "expected": { + "href": "sc:space ?query", + "hash": "" + } + }, { "comment": "Trailing space should be encoded", "href": "http://example.net", @@ -1926,5 +2367,15 @@ "hash": "#%00" } } + ], + "href": [ + { + "href": "file:///var/log/system.log", + "new_value": "http://0300.168.0xF0", + "expected": { + "href": "http://192.168.0.240/", + "protocol": "http:" + } + } ] } diff --git a/url/tests/urltestdata.json b/url/tests/urltestdata.json index 75a4bc2fd..1e61729d1 100644 --- a/url/tests/urltestdata.json +++ b/url/tests/urltestdata.json @@ -1,5 +1,5 @@ [ - "# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/script-tests/segments.js", + "# Pulled from https://github.com/web-platform-tests/wpt/blob/befe66343e5f21dc464c8c772c6d20695936714f/url/resources/urltestdata.json", { "input": "http://example\t.\norg", "base": "http://example.org/foo/bar", @@ -32,7 +32,7 @@ }, { "input": "https://test:@test", - "base": "about:blank", + "base": null, "href": "https://test@test/", "origin": "https://test", "protocol": "https:", @@ -47,7 +47,7 @@ }, { "input": "https://:@test", - "base": "about:blank", + "base": null, "href": "https://test/", "origin": "https://test", "protocol": "https:", @@ -62,7 +62,7 @@ }, { "input": "non-special://test:@test/x", - "base": "about:blank", + "base": null, "href": "non-special://test@test/x", "origin": "null", "protocol": "non-special:", @@ -77,7 +77,7 @@ }, { "input": "non-special://:@test/x", - "base": "about:blank", + "base": null, "href": "non-special://test/x", "origin": "null", "protocol": "non-special:", @@ -167,7 +167,7 @@ }, { "input": "lolscheme:x x#x x", - "base": "about:blank", + "base": null, "href": "lolscheme:x x#x%20x", "protocol": "lolscheme:", "username": "", @@ -1075,22 +1075,22 @@ }, { "input": "file://example:1/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "file://example:test/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "file://example%/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "file://[example]/", - "base": "about:blank", + "base": null, "failure": true }, { @@ -1754,7 +1754,7 @@ "# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/script-tests/path.js", { "input": "http://example.com/././foo", - "base": "about:blank", + "base": null, "href": "http://example.com/foo", "origin": "http://example.com", "protocol": "http:", @@ -1769,7 +1769,7 @@ }, { "input": "http://example.com/./.foo", - "base": "about:blank", + "base": null, "href": "http://example.com/.foo", "origin": "http://example.com", "protocol": "http:", @@ -1784,7 +1784,7 @@ }, { "input": "http://example.com/foo/.", - "base": "about:blank", + "base": null, "href": "http://example.com/foo/", "origin": "http://example.com", "protocol": "http:", @@ -1799,7 +1799,7 @@ }, { "input": "http://example.com/foo/./", - "base": "about:blank", + "base": null, "href": "http://example.com/foo/", "origin": "http://example.com", "protocol": "http:", @@ -1814,7 +1814,7 @@ }, { "input": "http://example.com/foo/bar/..", - "base": "about:blank", + "base": null, "href": "http://example.com/foo/", "origin": "http://example.com", "protocol": "http:", @@ -1829,7 +1829,7 @@ }, { "input": "http://example.com/foo/bar/../", - "base": "about:blank", + "base": null, "href": "http://example.com/foo/", "origin": "http://example.com", "protocol": "http:", @@ -1844,7 +1844,7 @@ }, { "input": "http://example.com/foo/..bar", - "base": "about:blank", + "base": null, "href": "http://example.com/foo/..bar", "origin": "http://example.com", "protocol": "http:", @@ -1859,7 +1859,7 @@ }, { "input": "http://example.com/foo/bar/../ton", - "base": "about:blank", + "base": null, "href": "http://example.com/foo/ton", "origin": "http://example.com", "protocol": "http:", @@ -1874,7 +1874,7 @@ }, { "input": "http://example.com/foo/bar/../ton/../../a", - "base": "about:blank", + "base": null, "href": "http://example.com/a", "origin": "http://example.com", "protocol": "http:", @@ -1889,7 +1889,7 @@ }, { "input": "http://example.com/foo/../../..", - "base": "about:blank", + "base": null, "href": "http://example.com/", "origin": "http://example.com", "protocol": "http:", @@ -1904,7 +1904,7 @@ }, { "input": "http://example.com/foo/../../../ton", - "base": "about:blank", + "base": null, "href": "http://example.com/ton", "origin": "http://example.com", "protocol": "http:", @@ -1919,7 +1919,7 @@ }, { "input": "http://example.com/foo/%2e", - "base": "about:blank", + "base": null, "href": "http://example.com/foo/", "origin": "http://example.com", "protocol": "http:", @@ -1934,7 +1934,7 @@ }, { "input": "http://example.com/foo/%2e%2", - "base": "about:blank", + "base": null, "href": "http://example.com/foo/%2e%2", "origin": "http://example.com", "protocol": "http:", @@ -1949,7 +1949,7 @@ }, { "input": "http://example.com/foo/%2e./%2e%2e/.%2e/%2e.bar", - "base": "about:blank", + "base": null, "href": "http://example.com/%2e.bar", "origin": "http://example.com", "protocol": "http:", @@ -1964,7 +1964,7 @@ }, { "input": "http://example.com////../..", - "base": "about:blank", + "base": null, "href": "http://example.com//", "origin": "http://example.com", "protocol": "http:", @@ -1979,7 +1979,7 @@ }, { "input": "http://example.com/foo/bar//../..", - "base": "about:blank", + "base": null, "href": "http://example.com/foo/", "origin": "http://example.com", "protocol": "http:", @@ -1994,7 +1994,7 @@ }, { "input": "http://example.com/foo/bar//..", - "base": "about:blank", + "base": null, "href": "http://example.com/foo/bar/", "origin": "http://example.com", "protocol": "http:", @@ -2009,7 +2009,7 @@ }, { "input": "http://example.com/foo", - "base": "about:blank", + "base": null, "href": "http://example.com/foo", "origin": "http://example.com", "protocol": "http:", @@ -2024,7 +2024,7 @@ }, { "input": "http://example.com/%20foo", - "base": "about:blank", + "base": null, "href": "http://example.com/%20foo", "origin": "http://example.com", "protocol": "http:", @@ -2039,7 +2039,7 @@ }, { "input": "http://example.com/foo%", - "base": "about:blank", + "base": null, "href": "http://example.com/foo%", "origin": "http://example.com", "protocol": "http:", @@ -2054,7 +2054,7 @@ }, { "input": "http://example.com/foo%2", - "base": "about:blank", + "base": null, "href": "http://example.com/foo%2", "origin": "http://example.com", "protocol": "http:", @@ -2069,7 +2069,7 @@ }, { "input": "http://example.com/foo%2zbar", - "base": "about:blank", + "base": null, "href": "http://example.com/foo%2zbar", "origin": "http://example.com", "protocol": "http:", @@ -2084,7 +2084,7 @@ }, { "input": "http://example.com/foo%2©zbar", - "base": "about:blank", + "base": null, "href": "http://example.com/foo%2%C3%82%C2%A9zbar", "origin": "http://example.com", "protocol": "http:", @@ -2099,7 +2099,7 @@ }, { "input": "http://example.com/foo%41%7a", - "base": "about:blank", + "base": null, "href": "http://example.com/foo%41%7a", "origin": "http://example.com", "protocol": "http:", @@ -2114,7 +2114,7 @@ }, { "input": "http://example.com/foo\t\u0091%91", - "base": "about:blank", + "base": null, "href": "http://example.com/foo%C2%91%91", "origin": "http://example.com", "protocol": "http:", @@ -2129,7 +2129,7 @@ }, { "input": "http://example.com/foo%00%51", - "base": "about:blank", + "base": null, "href": "http://example.com/foo%00%51", "origin": "http://example.com", "protocol": "http:", @@ -2144,7 +2144,7 @@ }, { "input": "http://example.com/(%28:%3A%29)", - "base": "about:blank", + "base": null, "href": "http://example.com/(%28:%3A%29)", "origin": "http://example.com", "protocol": "http:", @@ -2159,7 +2159,7 @@ }, { "input": "http://example.com/%3A%3a%3C%3c", - "base": "about:blank", + "base": null, "href": "http://example.com/%3A%3a%3C%3c", "origin": "http://example.com", "protocol": "http:", @@ -2174,7 +2174,7 @@ }, { "input": "http://example.com/foo\tbar", - "base": "about:blank", + "base": null, "href": "http://example.com/foobar", "origin": "http://example.com", "protocol": "http:", @@ -2189,7 +2189,7 @@ }, { "input": "http://example.com\\\\foo\\\\bar", - "base": "about:blank", + "base": null, "href": "http://example.com//foo//bar", "origin": "http://example.com", "protocol": "http:", @@ -2204,7 +2204,7 @@ }, { "input": "http://example.com/%7Ffp3%3Eju%3Dduvgw%3Dd", - "base": "about:blank", + "base": null, "href": "http://example.com/%7Ffp3%3Eju%3Dduvgw%3Dd", "origin": "http://example.com", "protocol": "http:", @@ -2219,7 +2219,7 @@ }, { "input": "http://example.com/@asdf%40", - "base": "about:blank", + "base": null, "href": "http://example.com/@asdf%40", "origin": "http://example.com", "protocol": "http:", @@ -2234,7 +2234,7 @@ }, { "input": "http://example.com/你好你好", - "base": "about:blank", + "base": null, "href": "http://example.com/%E4%BD%A0%E5%A5%BD%E4%BD%A0%E5%A5%BD", "origin": "http://example.com", "protocol": "http:", @@ -2249,7 +2249,7 @@ }, { "input": "http://example.com/‥/foo", - "base": "about:blank", + "base": null, "href": "http://example.com/%E2%80%A5/foo", "origin": "http://example.com", "protocol": "http:", @@ -2264,7 +2264,7 @@ }, { "input": "http://example.com//foo", - "base": "about:blank", + "base": null, "href": "http://example.com/%EF%BB%BF/foo", "origin": "http://example.com", "protocol": "http:", @@ -2279,7 +2279,7 @@ }, { "input": "http://example.com/‮/foo/‭/bar", - "base": "about:blank", + "base": null, "href": "http://example.com/%E2%80%AE/foo/%E2%80%AD/bar", "origin": "http://example.com", "protocol": "http:", @@ -2295,7 +2295,7 @@ "# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/script-tests/relative.js", { "input": "http://www.google.com/foo?bar=baz#", - "base": "about:blank", + "base": null, "href": "http://www.google.com/foo?bar=baz#", "origin": "http://www.google.com", "protocol": "http:", @@ -2310,7 +2310,7 @@ }, { "input": "http://www.google.com/foo?bar=baz# »", - "base": "about:blank", + "base": null, "href": "http://www.google.com/foo?bar=baz#%20%C2%BB", "origin": "http://www.google.com", "protocol": "http:", @@ -2325,7 +2325,7 @@ }, { "input": "data:test# »", - "base": "about:blank", + "base": null, "href": "data:test#%20%C2%BB", "origin": "null", "protocol": "data:", @@ -2340,7 +2340,7 @@ }, { "input": "http://www.google.com", - "base": "about:blank", + "base": null, "href": "http://www.google.com/", "origin": "http://www.google.com", "protocol": "http:", @@ -2355,7 +2355,7 @@ }, { "input": "http://192.0x00A80001", - "base": "about:blank", + "base": null, "href": "http://192.168.0.1/", "origin": "http://192.168.0.1", "protocol": "http:", @@ -2370,7 +2370,7 @@ }, { "input": "http://www/foo%2Ehtml", - "base": "about:blank", + "base": null, "href": "http://www/foo%2Ehtml", "origin": "http://www", "protocol": "http:", @@ -2385,7 +2385,7 @@ }, { "input": "http://www/foo/%2E/html", - "base": "about:blank", + "base": null, "href": "http://www/foo/html", "origin": "http://www", "protocol": "http:", @@ -2400,12 +2400,12 @@ }, { "input": "http://user:pass@/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://%25DOMAIN:foobar@foodomain.com/", - "base": "about:blank", + "base": null, "href": "http://%25DOMAIN:foobar@foodomain.com/", "origin": "http://foodomain.com", "protocol": "http:", @@ -2420,7 +2420,7 @@ }, { "input": "http:\\\\www.google.com\\foo", - "base": "about:blank", + "base": null, "href": "http://www.google.com/foo", "origin": "http://www.google.com", "protocol": "http:", @@ -2435,7 +2435,7 @@ }, { "input": "http://foo:80/", - "base": "about:blank", + "base": null, "href": "http://foo/", "origin": "http://foo", "protocol": "http:", @@ -2450,7 +2450,7 @@ }, { "input": "http://foo:81/", - "base": "about:blank", + "base": null, "href": "http://foo:81/", "origin": "http://foo:81", "protocol": "http:", @@ -2465,7 +2465,7 @@ }, { "input": "httpa://foo:80/", - "base": "about:blank", + "base": null, "href": "httpa://foo:80/", "origin": "null", "protocol": "httpa:", @@ -2480,12 +2480,12 @@ }, { "input": "http://foo:-80/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "https://foo:443/", - "base": "about:blank", + "base": null, "href": "https://foo/", "origin": "https://foo", "protocol": "https:", @@ -2500,7 +2500,7 @@ }, { "input": "https://foo:80/", - "base": "about:blank", + "base": null, "href": "https://foo:80/", "origin": "https://foo:80", "protocol": "https:", @@ -2515,7 +2515,7 @@ }, { "input": "ftp://foo:21/", - "base": "about:blank", + "base": null, "href": "ftp://foo/", "origin": "ftp://foo", "protocol": "ftp:", @@ -2530,7 +2530,7 @@ }, { "input": "ftp://foo:80/", - "base": "about:blank", + "base": null, "href": "ftp://foo:80/", "origin": "ftp://foo:80", "protocol": "ftp:", @@ -2545,7 +2545,7 @@ }, { "input": "gopher://foo:70/", - "base": "about:blank", + "base": null, "href": "gopher://foo:70/", "origin": "null", "protocol": "gopher:", @@ -2560,7 +2560,7 @@ }, { "input": "gopher://foo:443/", - "base": "about:blank", + "base": null, "href": "gopher://foo:443/", "origin": "null", "protocol": "gopher:", @@ -2575,7 +2575,7 @@ }, { "input": "ws://foo:80/", - "base": "about:blank", + "base": null, "href": "ws://foo/", "origin": "ws://foo", "protocol": "ws:", @@ -2590,7 +2590,7 @@ }, { "input": "ws://foo:81/", - "base": "about:blank", + "base": null, "href": "ws://foo:81/", "origin": "ws://foo:81", "protocol": "ws:", @@ -2605,7 +2605,7 @@ }, { "input": "ws://foo:443/", - "base": "about:blank", + "base": null, "href": "ws://foo:443/", "origin": "ws://foo:443", "protocol": "ws:", @@ -2620,7 +2620,7 @@ }, { "input": "ws://foo:815/", - "base": "about:blank", + "base": null, "href": "ws://foo:815/", "origin": "ws://foo:815", "protocol": "ws:", @@ -2635,7 +2635,7 @@ }, { "input": "wss://foo:80/", - "base": "about:blank", + "base": null, "href": "wss://foo:80/", "origin": "wss://foo:80", "protocol": "wss:", @@ -2650,7 +2650,7 @@ }, { "input": "wss://foo:81/", - "base": "about:blank", + "base": null, "href": "wss://foo:81/", "origin": "wss://foo:81", "protocol": "wss:", @@ -2665,7 +2665,7 @@ }, { "input": "wss://foo:443/", - "base": "about:blank", + "base": null, "href": "wss://foo/", "origin": "wss://foo", "protocol": "wss:", @@ -2680,7 +2680,7 @@ }, { "input": "wss://foo:815/", - "base": "about:blank", + "base": null, "href": "wss://foo:815/", "origin": "wss://foo:815", "protocol": "wss:", @@ -2695,7 +2695,7 @@ }, { "input": "http:/example.com/", - "base": "about:blank", + "base": null, "href": "http://example.com/", "origin": "http://example.com", "protocol": "http:", @@ -2710,7 +2710,7 @@ }, { "input": "ftp:/example.com/", - "base": "about:blank", + "base": null, "href": "ftp://example.com/", "origin": "ftp://example.com", "protocol": "ftp:", @@ -2725,7 +2725,7 @@ }, { "input": "https:/example.com/", - "base": "about:blank", + "base": null, "href": "https://example.com/", "origin": "https://example.com", "protocol": "https:", @@ -2740,7 +2740,7 @@ }, { "input": "madeupscheme:/example.com/", - "base": "about:blank", + "base": null, "href": "madeupscheme:/example.com/", "origin": "null", "protocol": "madeupscheme:", @@ -2755,7 +2755,7 @@ }, { "input": "file:/example.com/", - "base": "about:blank", + "base": null, "href": "file:///example.com/", "protocol": "file:", "username": "", @@ -2769,7 +2769,7 @@ }, { "input": "ftps:/example.com/", - "base": "about:blank", + "base": null, "href": "ftps:/example.com/", "origin": "null", "protocol": "ftps:", @@ -2784,7 +2784,7 @@ }, { "input": "gopher:/example.com/", - "base": "about:blank", + "base": null, "href": "gopher:/example.com/", "origin": "null", "protocol": "gopher:", @@ -2799,7 +2799,7 @@ }, { "input": "ws:/example.com/", - "base": "about:blank", + "base": null, "href": "ws://example.com/", "origin": "ws://example.com", "protocol": "ws:", @@ -2814,7 +2814,7 @@ }, { "input": "wss:/example.com/", - "base": "about:blank", + "base": null, "href": "wss://example.com/", "origin": "wss://example.com", "protocol": "wss:", @@ -2829,7 +2829,7 @@ }, { "input": "data:/example.com/", - "base": "about:blank", + "base": null, "href": "data:/example.com/", "origin": "null", "protocol": "data:", @@ -2844,7 +2844,7 @@ }, { "input": "javascript:/example.com/", - "base": "about:blank", + "base": null, "href": "javascript:/example.com/", "origin": "null", "protocol": "javascript:", @@ -2859,7 +2859,7 @@ }, { "input": "mailto:/example.com/", - "base": "about:blank", + "base": null, "href": "mailto:/example.com/", "origin": "null", "protocol": "mailto:", @@ -2874,7 +2874,7 @@ }, { "input": "http:example.com/", - "base": "about:blank", + "base": null, "href": "http://example.com/", "origin": "http://example.com", "protocol": "http:", @@ -2889,7 +2889,7 @@ }, { "input": "ftp:example.com/", - "base": "about:blank", + "base": null, "href": "ftp://example.com/", "origin": "ftp://example.com", "protocol": "ftp:", @@ -2904,7 +2904,7 @@ }, { "input": "https:example.com/", - "base": "about:blank", + "base": null, "href": "https://example.com/", "origin": "https://example.com", "protocol": "https:", @@ -2919,7 +2919,7 @@ }, { "input": "madeupscheme:example.com/", - "base": "about:blank", + "base": null, "href": "madeupscheme:example.com/", "origin": "null", "protocol": "madeupscheme:", @@ -2934,7 +2934,7 @@ }, { "input": "ftps:example.com/", - "base": "about:blank", + "base": null, "href": "ftps:example.com/", "origin": "null", "protocol": "ftps:", @@ -2949,7 +2949,7 @@ }, { "input": "gopher:example.com/", - "base": "about:blank", + "base": null, "href": "gopher:example.com/", "origin": "null", "protocol": "gopher:", @@ -2964,7 +2964,7 @@ }, { "input": "ws:example.com/", - "base": "about:blank", + "base": null, "href": "ws://example.com/", "origin": "ws://example.com", "protocol": "ws:", @@ -2979,7 +2979,7 @@ }, { "input": "wss:example.com/", - "base": "about:blank", + "base": null, "href": "wss://example.com/", "origin": "wss://example.com", "protocol": "wss:", @@ -2994,7 +2994,7 @@ }, { "input": "data:example.com/", - "base": "about:blank", + "base": null, "href": "data:example.com/", "origin": "null", "protocol": "data:", @@ -3009,7 +3009,7 @@ }, { "input": "javascript:example.com/", - "base": "about:blank", + "base": null, "href": "javascript:example.com/", "origin": "null", "protocol": "javascript:", @@ -3024,7 +3024,7 @@ }, { "input": "mailto:example.com/", - "base": "about:blank", + "base": null, "href": "mailto:example.com/", "origin": "null", "protocol": "mailto:", @@ -3040,7 +3040,7 @@ "# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/segments-userinfo-vs-host.html", { "input": "http:@www.example.com", - "base": "about:blank", + "base": null, "href": "http://www.example.com/", "origin": "http://www.example.com", "protocol": "http:", @@ -3055,7 +3055,7 @@ }, { "input": "http:/@www.example.com", - "base": "about:blank", + "base": null, "href": "http://www.example.com/", "origin": "http://www.example.com", "protocol": "http:", @@ -3070,7 +3070,7 @@ }, { "input": "http://@www.example.com", - "base": "about:blank", + "base": null, "href": "http://www.example.com/", "origin": "http://www.example.com", "protocol": "http:", @@ -3085,7 +3085,7 @@ }, { "input": "http:a:b@www.example.com", - "base": "about:blank", + "base": null, "href": "http://a:b@www.example.com/", "origin": "http://www.example.com", "protocol": "http:", @@ -3100,7 +3100,7 @@ }, { "input": "http:/a:b@www.example.com", - "base": "about:blank", + "base": null, "href": "http://a:b@www.example.com/", "origin": "http://www.example.com", "protocol": "http:", @@ -3115,7 +3115,7 @@ }, { "input": "http://a:b@www.example.com", - "base": "about:blank", + "base": null, "href": "http://a:b@www.example.com/", "origin": "http://www.example.com", "protocol": "http:", @@ -3130,7 +3130,7 @@ }, { "input": "http://@pple.com", - "base": "about:blank", + "base": null, "href": "http://pple.com/", "origin": "http://pple.com", "protocol": "http:", @@ -3145,7 +3145,7 @@ }, { "input": "http::b@www.example.com", - "base": "about:blank", + "base": null, "href": "http://:b@www.example.com/", "origin": "http://www.example.com", "protocol": "http:", @@ -3160,7 +3160,7 @@ }, { "input": "http:/:b@www.example.com", - "base": "about:blank", + "base": null, "href": "http://:b@www.example.com/", "origin": "http://www.example.com", "protocol": "http:", @@ -3175,7 +3175,7 @@ }, { "input": "http://:b@www.example.com", - "base": "about:blank", + "base": null, "href": "http://:b@www.example.com/", "origin": "http://www.example.com", "protocol": "http:", @@ -3190,64 +3190,64 @@ }, { "input": "http:/:@/www.example.com", - "base": "about:blank", + "base": null, "failure": true, - "inputCanBeRelative": true + "relativeTo": "non-opaque-path-base" }, { "input": "http://user@/www.example.com", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http:@/www.example.com", - "base": "about:blank", + "base": null, "failure": true, - "inputCanBeRelative": true + "relativeTo": "non-opaque-path-base" }, { "input": "http:/@/www.example.com", - "base": "about:blank", + "base": null, "failure": true, - "inputCanBeRelative": true + "relativeTo": "non-opaque-path-base" }, { "input": "http://@/www.example.com", - "base": "about:blank", + "base": null, "failure": true }, { "input": "https:@/www.example.com", - "base": "about:blank", + "base": null, "failure": true, - "inputCanBeRelative": true + "relativeTo": "non-opaque-path-base" }, { "input": "http:a:b@/www.example.com", - "base": "about:blank", + "base": null, "failure": true, - "inputCanBeRelative": true + "relativeTo": "non-opaque-path-base" }, { "input": "http:/a:b@/www.example.com", - "base": "about:blank", + "base": null, "failure": true, - "inputCanBeRelative": true + "relativeTo": "non-opaque-path-base" }, { "input": "http://a:b@/www.example.com", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http::@/www.example.com", - "base": "about:blank", + "base": null, "failure": true, - "inputCanBeRelative": true + "relativeTo": "non-opaque-path-base" }, { "input": "http:a:@www.example.com", - "base": "about:blank", + "base": null, "href": "http://a@www.example.com/", "origin": "http://www.example.com", "protocol": "http:", @@ -3262,7 +3262,7 @@ }, { "input": "http:/a:@www.example.com", - "base": "about:blank", + "base": null, "href": "http://a@www.example.com/", "origin": "http://www.example.com", "protocol": "http:", @@ -3277,7 +3277,7 @@ }, { "input": "http://a:@www.example.com", - "base": "about:blank", + "base": null, "href": "http://a@www.example.com/", "origin": "http://www.example.com", "protocol": "http:", @@ -3292,7 +3292,7 @@ }, { "input": "http://www.@pple.com", - "base": "about:blank", + "base": null, "href": "http://www.@pple.com/", "origin": "http://pple.com", "protocol": "http:", @@ -3307,24 +3307,24 @@ }, { "input": "http:@:www.example.com", - "base": "about:blank", + "base": null, "failure": true, - "inputCanBeRelative": true + "relativeTo": "non-opaque-path-base" }, { "input": "http:/@:www.example.com", - "base": "about:blank", + "base": null, "failure": true, - "inputCanBeRelative": true + "relativeTo": "non-opaque-path-base" }, { "input": "http://@:www.example.com", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://:@www.example.com", - "base": "about:blank", + "base": null, "href": "http://www.example.com/", "origin": "http://www.example.com", "protocol": "http:", @@ -3622,7 +3622,7 @@ "Leading and trailing C0 control or space", { "input": "\u0000\u001b\u0004\u0012 http://example.com/\u001f \u000d ", - "base": "about:blank", + "base": null, "href": "http://example.com/", "origin": "http://example.com", "protocol": "http:", @@ -3666,17 +3666,17 @@ "U+FFFD", { "input": "https://\ufffd", - "base": "about:blank", + "base": null, "failure": true }, { "input": "https://%EF%BF%BD", - "base": "about:blank", + "base": null, "failure": true }, { "input": "https://x/\ufffd?\ufffd#\ufffd", - "base": "about:blank", + "base": null, "href": "https://x/%EF%BF%BD?%EF%BF%BD#%EF%BF%BD", "origin": "https://x", "protocol": "https:", @@ -3692,33 +3692,33 @@ "Domain is ASCII, but a label is invalid IDNA", { "input": "http://a.b.c.xn--pokxncvks", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://10.0.0.xn--pokxncvks", - "base": "about:blank", + "base": null, "failure": true }, "IDNA labels should be matched case-insensitively", { "input": "http://a.b.c.XN--pokxncvks", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://a.b.c.Xn--pokxncvks", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://10.0.0.XN--pokxncvks", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://10.0.0.xN--pokxncvks", - "base": "about:blank", + "base": null, "failure": true }, "Test name prepping, fullwidth input should be converted to ASCII and NOT IDN-ized. This is 'Go' in fullwidth UTF-8/UTF-16.", @@ -3777,7 +3777,7 @@ }, { "input": "https://faß.ExAmPlE/", - "base": "about:blank", + "base": null, "href": "https://xn--fa-hia.example/", "origin": "https://xn--fa-hia.example", "protocol": "https:", @@ -3792,7 +3792,7 @@ }, { "input": "sc://faß.ExAmPlE/", - "base": "about:blank", + "base": null, "href": "sc://fa%C3%9F.ExAmPlE/", "origin": "null", "protocol": "sc:", @@ -3872,7 +3872,7 @@ }, { "input": "https://x x:12", - "base": "about:blank", + "base": null, "failure": true }, "Fullwidth and escaped UTF-8 fullwidth should still be treated as IP", @@ -3894,7 +3894,7 @@ "Domains with empty labels", { "input": "http://./", - "base": "about:blank", + "base": null, "href": "http://./", "origin": "http://.", "protocol": "http:", @@ -3909,7 +3909,7 @@ }, { "input": "http://../", - "base": "about:blank", + "base": null, "href": "http://../", "origin": "http://..", "protocol": "http:", @@ -3925,7 +3925,7 @@ "Non-special domains with empty labels", { "input": "h://.", - "base": "about:blank", + "base": null, "href": "h://.", "origin": "null", "protocol": "h:", @@ -3941,7 +3941,7 @@ "Broken IPv6", { "input": "http://[www.google.com]/", - "base": "about:blank", + "base": null, "failure": true }, { @@ -4066,6 +4066,21 @@ "search": "", "hash": "#x" }, + { + "input": "#x:y", + "base": "about:blank", + "href": "about:blank#x:y", + "origin": "null", + "protocol": "about:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "blank", + "search": "", + "hash": "#x:y" + }, { "input": "#", "base": "test:test?test", @@ -4131,7 +4146,7 @@ "byte is ' and url is special", { "input": "http://host/?'", - "base": "about:blank", + "base": null, "href": "http://host/?%27", "origin": "http://host", "protocol": "http:", @@ -4146,7 +4161,7 @@ }, { "input": "notspecial://host/?'", - "base": "about:blank", + "base": null, "href": "notspecial://host/?'", "origin": "null", "protocol": "notspecial:", @@ -4504,7 +4519,7 @@ "# make sure that relative URL logic works on known typically non-relative schemes too", { "input": "about:/../", - "base": "about:blank", + "base": null, "href": "about:/", "origin": "null", "protocol": "about:", @@ -4519,7 +4534,7 @@ }, { "input": "data:/../", - "base": "about:blank", + "base": null, "href": "data:/", "origin": "null", "protocol": "data:", @@ -4534,7 +4549,7 @@ }, { "input": "javascript:/../", - "base": "about:blank", + "base": null, "href": "javascript:/", "origin": "null", "protocol": "javascript:", @@ -4549,7 +4564,7 @@ }, { "input": "mailto:/../", - "base": "about:blank", + "base": null, "href": "mailto:/", "origin": "null", "protocol": "mailto:", @@ -4565,7 +4580,7 @@ "# unknown schemes and their hosts", { "input": "sc://ñ.test/", - "base": "about:blank", + "base": null, "href": "sc://%C3%B1.test/", "origin": "null", "protocol": "sc:", @@ -4580,7 +4595,7 @@ }, { "input": "sc://%/", - "base": "about:blank", + "base": null, "href": "sc://%/", "protocol": "sc:", "username": "", @@ -4594,22 +4609,22 @@ }, { "input": "sc://@/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "sc://te@s:t@/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "sc://:/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "sc://:12/", - "base": "about:blank", + "base": null, "failure": true }, { @@ -4630,7 +4645,7 @@ "# unknown schemes and backslashes", { "input": "sc:\\../", - "base": "about:blank", + "base": null, "href": "sc:\\../", "origin": "null", "protocol": "sc:", @@ -4646,7 +4661,7 @@ "# unknown scheme with path looking like a password", { "input": "sc::a@example.net", - "base": "about:blank", + "base": null, "href": "sc::a@example.net", "origin": "null", "protocol": "sc:", @@ -4662,7 +4677,7 @@ "# unknown scheme with bogus percent-encoding", { "input": "wow:%NBD", - "base": "about:blank", + "base": null, "href": "wow:%NBD", "origin": "null", "protocol": "wow:", @@ -4677,7 +4692,7 @@ }, { "input": "wow:%1G", - "base": "about:blank", + "base": null, "href": "wow:%1G", "origin": "null", "protocol": "wow:", @@ -4693,7 +4708,7 @@ "# unknown scheme with non-URL characters", { "input": "wow:\uFFFF", - "base": "about:blank", + "base": null, "href": "wow:%EF%BF%BF", "origin": "null", "protocol": "wow:", @@ -4709,88 +4724,88 @@ "Forbidden host code points", { "input": "sc://a\u0000b/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "sc://a b/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "sc://ab", - "base": "about:blank", + "base": null, "failure": true }, { "input": "sc://a[b/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "sc://a\\b/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "sc://a]b/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "sc://a^b", - "base": "about:blank", + "base": null, "failure": true }, { "input": "sc://a|b/", - "base": "about:blank", + "base": null, "failure": true }, "Forbidden host codepoints: tabs and newlines are removed during preprocessing", { "input": "foo://ho\u0009st/", - "base": "about:blank", + "base": null, "hash": "", "host": "host", "hostname": "host", - "href": "foo://host/", + "href":"foo://host/", "password": "", "pathname": "/", - "port": "", + "port":"", "protocol": "foo:", "search": "", "username": "" }, { "input": "foo://ho\u000Ast/", - "base": "about:blank", + "base": null, "hash": "", "host": "host", "hostname": "host", - "href": "foo://host/", + "href":"foo://host/", "password": "", "pathname": "/", - "port": "", + "port":"", "protocol": "foo:", "search": "", "username": "" }, { "input": "foo://ho\u000Dst/", - "base": "about:blank", + "base": null, "hash": "", "host": "host", "hostname": "host", - "href": "foo://host/", + "href":"foo://host/", "password": "", "pathname": "/", - "port": "", + "port":"", "protocol": "foo:", "search": "", "username": "" @@ -4798,233 +4813,233 @@ "Forbidden domain code-points", { "input": "http://a\u0000b/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://a\u0001b/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://a\u0002b/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://a\u0003b/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://a\u0004b/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://a\u0005b/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://a\u0006b/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://a\u0007b/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://a\u0008b/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://a\u000Bb/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://a\u000Cb/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://a\u000Eb/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://a\u000Fb/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://a\u0010b/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://a\u0011b/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://a\u0012b/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://a\u0013b/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://a\u0014b/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://a\u0015b/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://a\u0016b/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://a\u0017b/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://a\u0018b/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://a\u0019b/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://a\u001Ab/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://a\u001Bb/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://a\u001Cb/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://a\u001Db/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://a\u001Eb/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://a\u001Fb/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://a b/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://a%b/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ab", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://a[b/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://a]b/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://a^b", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://a|b/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://a\u007Fb/", - "base": "about:blank", + "base": null, "failure": true }, "Forbidden domain codepoints: tabs and newlines are removed during preprocessing", { "input": "http://ho\u0009st/", - "base": "about:blank", + "base": null, "hash": "", "host": "host", "hostname": "host", - "href": "http://host/", + "href":"http://host/", "password": "", "pathname": "/", - "port": "", + "port":"", "protocol": "http:", "search": "", "username": "" }, { "input": "http://ho\u000Ast/", - "base": "about:blank", + "base": null, "hash": "", "host": "host", "hostname": "host", - "href": "http://host/", + "href":"http://host/", "password": "", "pathname": "/", - "port": "", + "port":"", "protocol": "http:", "search": "", "username": "" }, { "input": "http://ho\u000Dst/", - "base": "about:blank", + "base": null, "hash": "", "host": "host", "hostname": "host", - "href": "http://host/", + "href":"http://host/", "password": "", "pathname": "/", - "port": "", + "port":"", "protocol": "http:", "search": "", "username": "" @@ -5032,238 +5047,238 @@ "Encoded forbidden domain codepoints in special URLs", { "input": "http://ho%00st/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%01st/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%02st/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%03st/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%04st/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%05st/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%06st/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%07st/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%08st/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%09st/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%0Ast/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%0Bst/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%0Cst/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%0Dst/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%0Est/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%0Fst/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%10st/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%11st/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%12st/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%13st/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%14st/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%15st/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%16st/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%17st/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%18st/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%19st/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%1Ast/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%1Bst/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%1Cst/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%1Dst/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%1Est/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%1Fst/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%20st/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%23st/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%25st/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%2Fst/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%3Ast/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%3Cst/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%3Est/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%3Fst/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%40st/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%5Bst/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%5Cst/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%5Dst/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%7Cst/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://ho%7Fst/", - "base": "about:blank", + "base": null, "failure": true }, "Allowed host/domain code points", { "input": "http://!\"$&'()*+,-.;=_`{}~/", - "base": "about:blank", + "base": null, "href": "http://!\"$&'()*+,-.;=_`{}~/", "origin": "http://!\"$&'()*+,-.;=_`{}~", "protocol": "http:", @@ -5278,7 +5293,7 @@ }, { "input": "sc://\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u000B\u000C\u000E\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001F\u007F!\"$%&'()*+,-.;=_`{}~/", - "base": "about:blank", + "base": null, "href": "sc://%01%02%03%04%05%06%07%08%0B%0C%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F%7F!\"$%&'()*+,-.;=_`{}~/", "origin": "null", "protocol": "sc:", @@ -5294,27 +5309,27 @@ "# Hosts and percent-encoding", { "input": "ftp://example.com%80/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "ftp://example.com%A0/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "https://example.com%80/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "https://example.com%A0/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "ftp://%e2%98%83", - "base": "about:blank", + "base": null, "href": "ftp://xn--n3h/", "origin": "ftp://xn--n3h", "protocol": "ftp:", @@ -5329,7 +5344,7 @@ }, { "input": "https://%e2%98%83", - "base": "about:blank", + "base": null, "href": "https://xn--n3h/", "origin": "https://xn--n3h", "protocol": "https:", @@ -5345,7 +5360,7 @@ "# tests from jsdom/whatwg-url designed for code coverage", { "input": "http://127.0.0.1:10100/relative_import.html", - "base": "about:blank", + "base": null, "href": "http://127.0.0.1:10100/relative_import.html", "origin": "http://127.0.0.1:10100", "protocol": "http:", @@ -5360,7 +5375,7 @@ }, { "input": "http://facebook.com/?foo=%7B%22abc%22", - "base": "about:blank", + "base": null, "href": "http://facebook.com/?foo=%7B%22abc%22", "origin": "http://facebook.com", "protocol": "http:", @@ -5375,7 +5390,7 @@ }, { "input": "https://localhost:3000/jqueryui@1.2.3", - "base": "about:blank", + "base": null, "href": "https://localhost:3000/jqueryui@1.2.3", "origin": "https://localhost:3000", "protocol": "https:", @@ -5391,7 +5406,7 @@ "# tab/LF/CR", { "input": "h\tt\nt\rp://h\to\ns\rt:9\t0\n0\r0/p\ta\nt\rh?q\tu\ne\rry#f\tr\na\rg", - "base": "about:blank", + "base": null, "href": "http://host:9000/path?query#frag", "origin": "http://host:9000", "protocol": "http:", @@ -5478,7 +5493,7 @@ "# Percent encoding of fragments", { "input": "http://foo.bar/baz?qux#foo\bbar", - "base": "about:blank", + "base": null, "href": "http://foo.bar/baz?qux#foo%08bar", "origin": "http://foo.bar", "protocol": "http:", @@ -5494,7 +5509,7 @@ }, { "input": "http://foo.bar/baz?qux#foo\"bar", - "base": "about:blank", + "base": null, "href": "http://foo.bar/baz?qux#foo%22bar", "origin": "http://foo.bar", "protocol": "http:", @@ -5510,7 +5525,7 @@ }, { "input": "http://foo.bar/baz?qux#foobar", - "base": "about:blank", + "base": null, "href": "http://foo.bar/baz?qux#foo%3Ebar", "origin": "http://foo.bar", "protocol": "http:", @@ -5542,7 +5557,7 @@ }, { "input": "http://foo.bar/baz?qux#foo`bar", - "base": "about:blank", + "base": null, "href": "http://foo.bar/baz?qux#foo%60bar", "origin": "http://foo.bar", "protocol": "http:", @@ -5774,7 +5789,7 @@ }, { "input": "https://0x.0x.0", - "base": "about:blank", + "base": null, "href": "https://0.0.0.0/", "origin": "https://0.0.0.0", "protocol": "https:", @@ -5790,18 +5805,18 @@ "More IPv4 parsing (via https://github.com/jsdom/whatwg-url/issues/92)", { "input": "https://0x100000000/test", - "base": "about:blank", + "base": null, "failure": true }, { "input": "https://256.0.0.1/test", - "base": "about:blank", + "base": null, "failure": true }, "# file URLs containing percent-encoded Windows drive letters (shouldn't work)", { "input": "file:///C%3A/", - "base": "about:blank", + "base": null, "href": "file:///C%3A/", "protocol": "file:", "username": "", @@ -5815,7 +5830,7 @@ }, { "input": "file:///C%7C/", - "base": "about:blank", + "base": null, "href": "file:///C%7C/", "protocol": "file:", "username": "", @@ -5829,42 +5844,42 @@ }, { "input": "file://%43%3A", - "base": "about:blank", + "base": null, "failure": true }, { "input": "file://%43%7C", - "base": "about:blank", + "base": null, "failure": true }, { "input": "file://%43|", - "base": "about:blank", + "base": null, "failure": true }, { "input": "file://C%7C", - "base": "about:blank", + "base": null, "failure": true }, { "input": "file://%43%7C/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "https://%43%7C/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "asdf://%43|/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "asdf://%43%7C/", - "base": "about:blank", + "base": null, "href": "asdf://%43%7C/", "origin": "null", "protocol": "asdf:", @@ -6106,7 +6121,7 @@ "# File URLs and many (back)slashes", { "input": "file:\\\\//", - "base": "about:blank", + "base": null, "href": "file:////", "protocol": "file:", "username": "", @@ -6120,7 +6135,7 @@ }, { "input": "file:\\\\\\\\", - "base": "about:blank", + "base": null, "href": "file:////", "protocol": "file:", "username": "", @@ -6134,7 +6149,7 @@ }, { "input": "file:\\\\\\\\?fox", - "base": "about:blank", + "base": null, "href": "file:////?fox", "protocol": "file:", "username": "", @@ -6148,7 +6163,7 @@ }, { "input": "file:\\\\\\\\#guppy", - "base": "about:blank", + "base": null, "href": "file:////#guppy", "protocol": "file:", "username": "", @@ -6162,7 +6177,7 @@ }, { "input": "file://spider///", - "base": "about:blank", + "base": null, "href": "file://spider///", "protocol": "file:", "username": "", @@ -6176,7 +6191,7 @@ }, { "input": "file:\\\\localhost//", - "base": "about:blank", + "base": null, "href": "file:////", "protocol": "file:", "username": "", @@ -6190,7 +6205,7 @@ }, { "input": "file:///localhost//cat", - "base": "about:blank", + "base": null, "href": "file:///localhost//cat", "protocol": "file:", "username": "", @@ -6204,7 +6219,7 @@ }, { "input": "file://\\/localhost//cat", - "base": "about:blank", + "base": null, "href": "file:////localhost//cat", "protocol": "file:", "username": "", @@ -6218,7 +6233,7 @@ }, { "input": "file://localhost//a//../..//", - "base": "about:blank", + "base": null, "href": "file://///", "protocol": "file:", "username": "", @@ -6530,7 +6545,7 @@ "# Do not drop the host in the presence of a drive letter", { "input": "file://example.net/C:/", - "base": "about:blank", + "base": null, "href": "file://example.net/C:/", "protocol": "file:", "username": "", @@ -6544,7 +6559,7 @@ }, { "input": "file://1.2.3.4/C:/", - "base": "about:blank", + "base": null, "href": "file://1.2.3.4/C:/", "protocol": "file:", "username": "", @@ -6558,7 +6573,7 @@ }, { "input": "file://[1::8]/C:/", - "base": "about:blank", + "base": null, "href": "file://[1::8]/C:/", "protocol": "file:", "username": "", @@ -6687,7 +6702,7 @@ "# Windows drive letter quirk (no host)", { "input": "file:/C|/", - "base": "about:blank", + "base": null, "href": "file:///C:/", "protocol": "file:", "username": "", @@ -6701,7 +6716,7 @@ }, { "input": "file://C|/", - "base": "about:blank", + "base": null, "href": "file:///C:/", "protocol": "file:", "username": "", @@ -6716,7 +6731,7 @@ "# file URLs without base URL by Rimas Misevičius", { "input": "file:", - "base": "about:blank", + "base": null, "href": "file:///", "protocol": "file:", "username": "", @@ -6730,7 +6745,7 @@ }, { "input": "file:?q=v", - "base": "about:blank", + "base": null, "href": "file:///?q=v", "protocol": "file:", "username": "", @@ -6744,7 +6759,7 @@ }, { "input": "file:#frag", - "base": "about:blank", + "base": null, "href": "file:///#frag", "protocol": "file:", "username": "", @@ -6759,7 +6774,7 @@ "# file: drive letter cases from https://crbug.com/1078698", { "input": "file:///Y:", - "base": "about:blank", + "base": null, "href": "file:///Y:", "protocol": "file:", "username": "", @@ -6773,7 +6788,7 @@ }, { "input": "file:///Y:/", - "base": "about:blank", + "base": null, "href": "file:///Y:/", "protocol": "file:", "username": "", @@ -6787,7 +6802,7 @@ }, { "input": "file:///./Y", - "base": "about:blank", + "base": null, "href": "file:///Y", "protocol": "file:", "username": "", @@ -6801,7 +6816,7 @@ }, { "input": "file:///./Y:", - "base": "about:blank", + "base": null, "href": "file:///Y:", "protocol": "file:", "username": "", @@ -6815,14 +6830,14 @@ }, { "input": "\\\\\\.\\Y:", - "base": "about:blank", + "base": null, "failure": true, - "inputCanBeRelative": true + "relativeTo": "non-opaque-path-base" }, "# file: drive letter cases from https://crbug.com/1078698 but lowercased", { "input": "file:///y:", - "base": "about:blank", + "base": null, "href": "file:///y:", "protocol": "file:", "username": "", @@ -6836,7 +6851,7 @@ }, { "input": "file:///y:/", - "base": "about:blank", + "base": null, "href": "file:///y:/", "protocol": "file:", "username": "", @@ -6850,7 +6865,7 @@ }, { "input": "file:///./y", - "base": "about:blank", + "base": null, "href": "file:///y", "protocol": "file:", "username": "", @@ -6864,7 +6879,7 @@ }, { "input": "file:///./y:", - "base": "about:blank", + "base": null, "href": "file:///y:", "protocol": "file:", "username": "", @@ -6878,14 +6893,14 @@ }, { "input": "\\\\\\.\\y:", - "base": "about:blank", + "base": null, "failure": true, - "inputCanBeRelative": true + "relativeTo": "non-opaque-path-base" }, "# Additional file URL tests for (https://github.com/whatwg/url/issues/405)", { "input": "file://localhost//a//../..//foo", - "base": "about:blank", + "base": null, "href": "file://///foo", "protocol": "file:", "username": "", @@ -6899,7 +6914,7 @@ }, { "input": "file://localhost////foo", - "base": "about:blank", + "base": null, "href": "file://////foo", "protocol": "file:", "username": "", @@ -6913,7 +6928,7 @@ }, { "input": "file:////foo", - "base": "about:blank", + "base": null, "href": "file:////foo", "protocol": "file:", "username": "", @@ -7012,7 +7027,7 @@ "File URL tests for https://github.com/whatwg/url/issues/549", { "input": "file:.//p", - "base": "about:blank", + "base": null, "href": "file:////p", "protocol": "file:", "username": "", @@ -7026,7 +7041,7 @@ }, { "input": "file:/.//p", - "base": "about:blank", + "base": null, "href": "file:////p", "protocol": "file:", "username": "", @@ -7061,48 +7076,48 @@ }, { "input": "https://[0::0::0]", - "base": "about:blank", + "base": null, "failure": true }, { "input": "https://[0:.0]", - "base": "about:blank", + "base": null, "failure": true }, { "input": "https://[0:0:]", - "base": "about:blank", + "base": null, "failure": true }, { "input": "https://[0:1:2:3:4:5:6:7.0.0.0.1]", - "base": "about:blank", + "base": null, "failure": true }, { "input": "https://[0:1.00.0.0.0]", - "base": "about:blank", + "base": null, "failure": true }, { "input": "https://[0:1.290.0.0.0]", - "base": "about:blank", + "base": null, "failure": true }, { "input": "https://[0:1.23.23]", - "base": "about:blank", + "base": null, "failure": true }, "# Empty host", { "input": "http://?", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://#", - "base": "about:blank", + "base": null, "failure": true }, "Port overflow (2^32 + 81)", @@ -7126,7 +7141,7 @@ "# Non-special-URL path tests", { "input": "sc://ñ", - "base": "about:blank", + "base": null, "href": "sc://%C3%B1", "origin": "null", "protocol": "sc:", @@ -7141,7 +7156,7 @@ }, { "input": "sc://ñ?x", - "base": "about:blank", + "base": null, "href": "sc://%C3%B1?x", "origin": "null", "protocol": "sc:", @@ -7156,7 +7171,7 @@ }, { "input": "sc://ñ#x", - "base": "about:blank", + "base": null, "href": "sc://%C3%B1#x", "origin": "null", "protocol": "sc:", @@ -7201,7 +7216,7 @@ }, { "input": "sc://?", - "base": "about:blank", + "base": null, "href": "sc://?", "protocol": "sc:", "username": "", @@ -7215,7 +7230,7 @@ }, { "input": "sc://#", - "base": "about:blank", + "base": null, "href": "sc://#", "protocol": "sc:", "username": "", @@ -7271,7 +7286,7 @@ }, { "input": "tftp://foobar.com/someconfig;mode=netascii", - "base": "about:blank", + "base": null, "href": "tftp://foobar.com/someconfig;mode=netascii", "origin": "null", "protocol": "tftp:", @@ -7286,7 +7301,7 @@ }, { "input": "telnet://user:pass@foobar.com:23/", - "base": "about:blank", + "base": null, "href": "telnet://user:pass@foobar.com:23/", "origin": "null", "protocol": "telnet:", @@ -7301,7 +7316,7 @@ }, { "input": "ut2004://10.10.10.10:7777/Index.ut2", - "base": "about:blank", + "base": null, "href": "ut2004://10.10.10.10:7777/Index.ut2", "origin": "null", "protocol": "ut2004:", @@ -7316,7 +7331,7 @@ }, { "input": "redis://foo:bar@somehost:6379/0?baz=bam&qux=baz", - "base": "about:blank", + "base": null, "href": "redis://foo:bar@somehost:6379/0?baz=bam&qux=baz", "origin": "null", "protocol": "redis:", @@ -7331,7 +7346,7 @@ }, { "input": "rsync://foo@host:911/sup", - "base": "about:blank", + "base": null, "href": "rsync://foo@host:911/sup", "origin": "null", "protocol": "rsync:", @@ -7346,7 +7361,7 @@ }, { "input": "git://github.com/foo/bar.git", - "base": "about:blank", + "base": null, "href": "git://github.com/foo/bar.git", "origin": "null", "protocol": "git:", @@ -7361,7 +7376,7 @@ }, { "input": "irc://myserver.com:6999/channel?passwd", - "base": "about:blank", + "base": null, "href": "irc://myserver.com:6999/channel?passwd", "origin": "null", "protocol": "irc:", @@ -7376,7 +7391,7 @@ }, { "input": "dns://fw.example.org:9999/foo.bar.org?type=TXT", - "base": "about:blank", + "base": null, "href": "dns://fw.example.org:9999/foo.bar.org?type=TXT", "origin": "null", "protocol": "dns:", @@ -7391,7 +7406,7 @@ }, { "input": "ldap://localhost:389/ou=People,o=JNDITutorial", - "base": "about:blank", + "base": null, "href": "ldap://localhost:389/ou=People,o=JNDITutorial", "origin": "null", "protocol": "ldap:", @@ -7406,7 +7421,7 @@ }, { "input": "git+https://github.com/foo/bar", - "base": "about:blank", + "base": null, "href": "git+https://github.com/foo/bar", "origin": "null", "protocol": "git+https:", @@ -7421,7 +7436,7 @@ }, { "input": "urn:ietf:rfc:2648", - "base": "about:blank", + "base": null, "href": "urn:ietf:rfc:2648", "origin": "null", "protocol": "urn:", @@ -7436,7 +7451,7 @@ }, { "input": "tag:joe@example.org,2001:foo/bar", - "base": "about:blank", + "base": null, "href": "tag:joe@example.org,2001:foo/bar", "origin": "null", "protocol": "tag:", @@ -7452,7 +7467,7 @@ "Serialize /. in path", { "input": "non-spec:/.//", - "base": "about:blank", + "base": null, "href": "non-spec:/.//", "protocol": "non-spec:", "username": "", @@ -7466,7 +7481,7 @@ }, { "input": "non-spec:/..//", - "base": "about:blank", + "base": null, "href": "non-spec:/.//", "protocol": "non-spec:", "username": "", @@ -7480,7 +7495,7 @@ }, { "input": "non-spec:/a/..//", - "base": "about:blank", + "base": null, "href": "non-spec:/.//", "protocol": "non-spec:", "username": "", @@ -7494,7 +7509,7 @@ }, { "input": "non-spec:/.//path", - "base": "about:blank", + "base": null, "href": "non-spec:/.//path", "protocol": "non-spec:", "username": "", @@ -7508,7 +7523,7 @@ }, { "input": "non-spec:/..//path", - "base": "about:blank", + "base": null, "href": "non-spec:/.//path", "protocol": "non-spec:", "username": "", @@ -7522,7 +7537,7 @@ }, { "input": "non-spec:/a/..//path", - "base": "about:blank", + "base": null, "href": "non-spec:/.//path", "protocol": "non-spec:", "username": "", @@ -7636,7 +7651,7 @@ "# percent encoded hosts in non-special-URLs", { "input": "non-special://%E2%80%A0/", - "base": "about:blank", + "base": null, "href": "non-special://%E2%80%A0/", "protocol": "non-special:", "username": "", @@ -7650,7 +7665,7 @@ }, { "input": "non-special://H%4fSt/path", - "base": "about:blank", + "base": null, "href": "non-special://H%4fSt/path", "protocol": "non-special:", "username": "", @@ -7665,7 +7680,7 @@ "# IPv6 in non-special-URLs", { "input": "non-special://[1:2:0:0:5:0:0:0]/", - "base": "about:blank", + "base": null, "href": "non-special://[1:2:0:0:5::]/", "protocol": "non-special:", "username": "", @@ -7679,7 +7694,7 @@ }, { "input": "non-special://[1:2:0:0:0:0:0:3]/", - "base": "about:blank", + "base": null, "href": "non-special://[1:2::3]/", "protocol": "non-special:", "username": "", @@ -7693,7 +7708,7 @@ }, { "input": "non-special://[1:2::3]:80/", - "base": "about:blank", + "base": null, "href": "non-special://[1:2::3]:80/", "protocol": "non-special:", "username": "", @@ -7707,12 +7722,12 @@ }, { "input": "non-special://[:80/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "blob:https://example.com:443/", - "base": "about:blank", + "base": null, "href": "blob:https://example.com:443/", "origin": "https://example.com", "protocol": "blob:", @@ -7725,9 +7740,24 @@ "search": "", "hash": "" }, + { + "input": "blob:http://example.org:88/", + "base": null, + "href": "blob:http://example.org:88/", + "origin": "http://example.org:88", + "protocol": "blob:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "http://example.org:88/", + "search": "", + "hash": "" + }, { "input": "blob:d3958f5c-0777-0845-9dcf-2cb28783acaf", - "base": "about:blank", + "base": null, "href": "blob:d3958f5c-0777-0845-9dcf-2cb28783acaf", "origin": "null", "protocol": "blob:", @@ -7742,7 +7772,7 @@ }, { "input": "blob:", - "base": "about:blank", + "base": null, "href": "blob:", "origin": "null", "protocol": "blob:", @@ -7755,28 +7785,151 @@ "search": "", "hash": "" }, - "Invalid IPv4 radix digits", + "blob: in blob:", { - "input": "http://0x7f.0.0.0x7g", - "base": "about:blank", - "href": "http://0x7f.0.0.0x7g/", - "protocol": "http:", + "input": "blob:blob:", + "base": null, + "href": "blob:blob:", + "origin": "null", + "protocol": "blob:", "username": "", "password": "", - "host": "0x7f.0.0.0x7g", - "hostname": "0x7f.0.0.0x7g", + "host": "", + "hostname": "", "port": "", - "pathname": "/", + "pathname": "blob:", "search": "", "hash": "" }, { - "input": "http://0X7F.0.0.0X7G", - "base": "about:blank", - "href": "http://0x7f.0.0.0x7g/", - "protocol": "http:", - "username": "", - "password": "", + "input": "blob:blob:https://example.org/", + "base": null, + "href": "blob:blob:https://example.org/", + "origin": "null", + "protocol": "blob:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "blob:https://example.org/", + "search": "", + "hash": "" + }, + "Non-http(s): in blob:", + { + "input": "blob:about:blank", + "base": null, + "href": "blob:about:blank", + "origin": "null", + "protocol": "blob:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "about:blank", + "search": "", + "hash": "" + }, + { + "input": "blob:file://host/path", + "base": null, + "href": "blob:file://host/path", + "origin": "null", + "protocol": "blob:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "file://host/path", + "search": "", + "hash": "" + }, + { + "input": "blob:ftp://host/path", + "base": null, + "href": "blob:ftp://host/path", + "origin": "null", + "protocol": "blob:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "ftp://host/path", + "search": "", + "hash": "" + }, + { + "input": "blob:ws://example.org/", + "base": null, + "href": "blob:ws://example.org/", + "origin": "null", + "protocol": "blob:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "ws://example.org/", + "search": "", + "hash": "" + }, + { + "input": "blob:wss://example.org/", + "base": null, + "href": "blob:wss://example.org/", + "origin": "null", + "protocol": "blob:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "wss://example.org/", + "search": "", + "hash": "" + }, + "Percent-encoded http: in blob:", + { + "input": "blob:http%3a//example.org/", + "base": null, + "href": "blob:http%3a//example.org/", + "origin": "null", + "protocol": "blob:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "http%3a//example.org/", + "search": "", + "hash": "" + }, + "Invalid IPv4 radix digits", + { + "input": "http://0x7f.0.0.0x7g", + "base": null, + "href": "http://0x7f.0.0.0x7g/", + "protocol": "http:", + "username": "", + "password": "", + "host": "0x7f.0.0.0x7g", + "hostname": "0x7f.0.0.0x7g", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://0X7F.0.0.0X7G", + "base": null, + "href": "http://0x7f.0.0.0x7g/", + "protocol": "http:", + "username": "", + "password": "", "host": "0x7f.0.0.0x7g", "hostname": "0x7f.0.0.0x7g", "port": "", @@ -7787,13 +7940,13 @@ "Invalid IPv4 portion of IPv6 address", { "input": "http://[::127.0.0.0.1]", - "base": "about:blank", + "base": null, "failure": true }, "Uncompressed IPv6 addresses with 0", { "input": "http://[0:1:0:1:0:1:0:1]", - "base": "about:blank", + "base": null, "href": "http://[0:1:0:1:0:1:0:1]/", "protocol": "http:", "username": "", @@ -7807,7 +7960,7 @@ }, { "input": "http://[1:0:1:0:1:0:1:0]", - "base": "about:blank", + "base": null, "href": "http://[1:0:1:0:1:0:1:0]/", "protocol": "http:", "username": "", @@ -7822,7 +7975,7 @@ "Percent-encoded query and fragment", { "input": "http://example.org/test?\u0022", - "base": "about:blank", + "base": null, "href": "http://example.org/test?%22", "protocol": "http:", "username": "", @@ -7836,7 +7989,7 @@ }, { "input": "http://example.org/test?\u0023", - "base": "about:blank", + "base": null, "href": "http://example.org/test?#", "protocol": "http:", "username": "", @@ -7850,7 +8003,7 @@ }, { "input": "http://example.org/test?\u003C", - "base": "about:blank", + "base": null, "href": "http://example.org/test?%3C", "protocol": "http:", "username": "", @@ -7864,7 +8017,7 @@ }, { "input": "http://example.org/test?\u003E", - "base": "about:blank", + "base": null, "href": "http://example.org/test?%3E", "protocol": "http:", "username": "", @@ -7878,7 +8031,7 @@ }, { "input": "http://example.org/test?\u2323", - "base": "about:blank", + "base": null, "href": "http://example.org/test?%E2%8C%A3", "protocol": "http:", "username": "", @@ -7892,7 +8045,7 @@ }, { "input": "http://example.org/test?%23%23", - "base": "about:blank", + "base": null, "href": "http://example.org/test?%23%23", "protocol": "http:", "username": "", @@ -7906,7 +8059,7 @@ }, { "input": "http://example.org/test?%GH", - "base": "about:blank", + "base": null, "href": "http://example.org/test?%GH", "protocol": "http:", "username": "", @@ -7920,7 +8073,7 @@ }, { "input": "http://example.org/test?a#%EF", - "base": "about:blank", + "base": null, "href": "http://example.org/test?a#%EF", "protocol": "http:", "username": "", @@ -7934,7 +8087,7 @@ }, { "input": "http://example.org/test?a#%GH", - "base": "about:blank", + "base": null, "href": "http://example.org/test?a#%GH", "protocol": "http:", "username": "", @@ -7949,21 +8102,21 @@ "URLs that require a non-about:blank base. (Also serve as invalid base tests.)", { "input": "a", - "base": "about:blank", + "base": null, "failure": true, - "inputCanBeRelative": true + "relativeTo": "non-opaque-path-base" }, { "input": "a/", - "base": "about:blank", + "base": null, "failure": true, - "inputCanBeRelative": true + "relativeTo": "non-opaque-path-base" }, { "input": "a//", - "base": "about:blank", + "base": null, "failure": true, - "inputCanBeRelative": true + "relativeTo": "non-opaque-path-base" }, "Bases that don't fail to parse but fail to be bases", { @@ -8036,7 +8189,7 @@ "Null code point in fragment", { "input": "http://example.org/test?a#b\u0000c", - "base": "about:blank", + "base": null, "href": "http://example.org/test?a#b%00c", "protocol": "http:", "username": "", @@ -8050,7 +8203,7 @@ }, { "input": "non-spec://example.org/test?a#b\u0000c", - "base": "about:blank", + "base": null, "href": "non-spec://example.org/test?a#b%00c", "protocol": "non-spec:", "username": "", @@ -8064,7 +8217,7 @@ }, { "input": "non-spec:/test?a#b\u0000c", - "base": "about:blank", + "base": null, "href": "non-spec:/test?a#b%00c", "protocol": "non-spec:", "username": "", @@ -8124,7 +8277,7 @@ "IDNA ignored code points in file URLs hosts", { "input": "file://a\u00ADb/p", - "base": "about:blank", + "base": null, "href": "file://ab/p", "protocol": "file:", "username": "", @@ -8138,7 +8291,7 @@ }, { "input": "file://a%C2%ADb/p", - "base": "about:blank", + "base": null, "href": "file://ab/p", "protocol": "file:", "username": "", @@ -8153,7 +8306,7 @@ "IDNA hostnames which get mapped to 'localhost'", { "input": "file://loC𝐀𝐋𝐇𝐨𝐬𝐭/usr/bin", - "base": "about:blank", + "base": null, "href": "file:///usr/bin", "protocol": "file:", "username": "", @@ -8168,17 +8321,17 @@ "Empty host after the domain to ASCII", { "input": "file://\u00ad/p", - "base": "about:blank", + "base": null, "failure": true }, { "input": "file://%C2%AD/p", - "base": "about:blank", + "base": null, "failure": true }, { "input": "file://xn--/p", - "base": "about:blank", + "base": null, "failure": true }, "https://bugzilla.mozilla.org/show_bug.cgi?id=1647058", @@ -8199,7 +8352,7 @@ "UTF-8 percent-encode of C0 control percent-encode set and supersets", { "input": "non-special:cannot-be-a-base-url-\u0000\u0001\u001F\u001E\u007E\u007F\u0080", - "base": "about:blank", + "base": null, "hash": "", "host": "", "hostname": "", @@ -8214,7 +8367,7 @@ }, { "input": "https://www.example.com/path{\u007Fpath.html?query'\u007F=query#fragment<\u007Ffragment", - "base": "about:blank", + "base": null, "hash": "#fragment%3C%7Ffragment", "host": "www.example.com", "hostname": "www.example.com", @@ -8245,7 +8398,7 @@ "Tests for the distinct percent-encode sets", { "input": "foo:// !\"$%&'()*+,-.;<=>@[\\]^_`{|}~@host/", - "base": "about:blank", + "base": null, "hash": "", "host": "host", "hostname": "host", @@ -8253,14 +8406,14 @@ "origin": "null", "password": "", "pathname": "/", - "port": "", + "port":"", "protocol": "foo:", "search": "", "username": "%20!%22$%&'()*+,-.%3B%3C%3D%3E%40%5B%5C%5D%5E_%60%7B%7C%7D~" }, { "input": "wss:// !\"$%&'()*+,-.;<=>@[]^_`{|}~@host/", - "base": "about:blank", + "base": null, "hash": "", "host": "host", "hostname": "host", @@ -8268,14 +8421,14 @@ "origin": "wss://host", "password": "", "pathname": "/", - "port": "", + "port":"", "protocol": "wss:", "search": "", "username": "%20!%22$%&'()*+,-.%3B%3C%3D%3E%40%5B%5D%5E_%60%7B%7C%7D~" }, { "input": "foo://joe: !\"$%&'()*+,-.:;<=>@[\\]^_`{|}~@host/", - "base": "about:blank", + "base": null, "hash": "", "host": "host", "hostname": "host", @@ -8283,14 +8436,14 @@ "origin": "null", "password": "%20!%22$%&'()*+,-.%3A%3B%3C%3D%3E%40%5B%5C%5D%5E_%60%7B%7C%7D~", "pathname": "/", - "port": "", + "port":"", "protocol": "foo:", "search": "", "username": "joe" }, { "input": "wss://joe: !\"$%&'()*+,-.:;<=>@[]^_`{|}~@host/", - "base": "about:blank", + "base": null, "hash": "", "host": "host", "hostname": "host", @@ -8298,44 +8451,44 @@ "origin": "wss://host", "password": "%20!%22$%&'()*+,-.%3A%3B%3C%3D%3E%40%5B%5D%5E_%60%7B%7C%7D~", "pathname": "/", - "port": "", + "port":"", "protocol": "wss:", "search": "", "username": "joe" }, { "input": "foo://!\"$%&'()*+,-.;=_`{}~/", - "base": "about:blank", + "base": null, "hash": "", "host": "!\"$%&'()*+,-.;=_`{}~", "hostname": "!\"$%&'()*+,-.;=_`{}~", - "href": "foo://!\"$%&'()*+,-.;=_`{}~/", + "href":"foo://!\"$%&'()*+,-.;=_`{}~/", "origin": "null", "password": "", "pathname": "/", - "port": "", + "port":"", "protocol": "foo:", "search": "", "username": "" }, { "input": "wss://!\"$&'()*+,-.;=_`{}~/", - "base": "about:blank", + "base": null, "hash": "", "host": "!\"$&'()*+,-.;=_`{}~", "hostname": "!\"$&'()*+,-.;=_`{}~", - "href": "wss://!\"$&'()*+,-.;=_`{}~/", + "href":"wss://!\"$&'()*+,-.;=_`{}~/", "origin": "wss://!\"$&'()*+,-.;=_`{}~", "password": "", "pathname": "/", - "port": "", + "port":"", "protocol": "wss:", "search": "", "username": "" }, { "input": "foo://host/ !\"$%&'()*+,-./:;<=>@[\\]^_`{|}~", - "base": "about:blank", + "base": null, "hash": "", "host": "host", "hostname": "host", @@ -8343,14 +8496,14 @@ "origin": "null", "password": "", "pathname": "/%20!%22$%&'()*+,-./:;%3C=%3E@[\\]^_%60%7B|%7D~", - "port": "", + "port":"", "protocol": "foo:", "search": "", "username": "" }, { "input": "wss://host/ !\"$%&'()*+,-./:;<=>@[\\]^_`{|}~", - "base": "about:blank", + "base": null, "hash": "", "host": "host", "hostname": "host", @@ -8358,14 +8511,14 @@ "origin": "wss://host", "password": "", "pathname": "/%20!%22$%&'()*+,-./:;%3C=%3E@[/]^_%60%7B|%7D~", - "port": "", + "port":"", "protocol": "wss:", "search": "", "username": "" }, { "input": "foo://host/dir/? !\"$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - "base": "about:blank", + "base": null, "hash": "", "host": "host", "hostname": "host", @@ -8373,14 +8526,14 @@ "origin": "null", "password": "", "pathname": "/dir/", - "port": "", + "port":"", "protocol": "foo:", "search": "?%20!%22$%&'()*+,-./:;%3C=%3E?@[\\]^_`{|}~", "username": "" }, { "input": "wss://host/dir/? !\"$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - "base": "about:blank", + "base": null, "hash": "", "host": "host", "hostname": "host", @@ -8388,14 +8541,14 @@ "origin": "wss://host", "password": "", "pathname": "/dir/", - "port": "", + "port":"", "protocol": "wss:", "search": "?%20!%22$%&%27()*+,-./:;%3C=%3E?@[\\]^_`{|}~", "username": "" }, { "input": "foo://host/dir/# !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - "base": "about:blank", + "base": null, "hash": "#%20!%22#$%&'()*+,-./:;%3C=%3E?@[\\]^_%60{|}~", "host": "host", "hostname": "host", @@ -8403,14 +8556,14 @@ "origin": "null", "password": "", "pathname": "/dir/", - "port": "", + "port":"", "protocol": "foo:", "search": "", "username": "" }, { "input": "wss://host/dir/# !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - "base": "about:blank", + "base": null, "hash": "#%20!%22#$%&'()*+,-./:;%3C=%3E?@[\\]^_%60{|}~", "host": "host", "hostname": "host", @@ -8418,7 +8571,7 @@ "origin": "wss://host", "password": "", "pathname": "/dir/", - "port": "", + "port":"", "protocol": "wss:", "search": "", "username": "" @@ -8430,10 +8583,10 @@ "hash": "", "host": "", "hostname": "", - "href": "abc:rootless", + "href":"abc:rootless", "password": "", "pathname": "rootless", - "port": "", + "port":"", "protocol": "abc:", "search": "", "username": "" @@ -8444,10 +8597,10 @@ "hash": "", "host": "", "hostname": "", - "href": "abc:rootless", + "href":"abc:rootless", "password": "", "pathname": "rootless", - "port": "", + "port":"", "protocol": "abc:", "search": "", "username": "" @@ -8458,10 +8611,10 @@ "hash": "", "host": "", "hostname": "", - "href": "abc:rootless", + "href":"abc:rootless", "password": "", "pathname": "rootless", - "port": "", + "port":"", "protocol": "abc:", "search": "", "username": "" @@ -8472,10 +8625,10 @@ "hash": "", "host": "", "hostname": "", - "href": "abc:/rooted", + "href":"abc:/rooted", "password": "", "pathname": "/rooted", - "port": "", + "port":"", "protocol": "abc:", "search": "", "username": "" @@ -8484,12 +8637,14 @@ { "input": "#", "base": null, - "failure": true + "failure": true, + "relativeTo": "any-base" }, { "input": "?", "base": null, - "failure": true + "failure": true, + "relativeTo": "non-opaque-path-base" }, "Last component looks like a number, but not valid IPv4", { @@ -8504,12 +8659,12 @@ }, { "input": "http://0..0x300/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://0..0x300./", - "base": "about:blank", + "base": null, "failure": true }, { @@ -8524,142 +8679,142 @@ }, { "input": "http://1.2.3.08", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://1.2.3.08.", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://1.2.3.09", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://09.2.3.4", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://09.2.3.4.", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://01.2.3.4.5", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://01.2.3.4.5.", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://0x100.2.3.4", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://0x100.2.3.4.", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://0x1.2.3.4.5", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://0x1.2.3.4.5.", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://foo.1.2.3.4", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://foo.1.2.3.4.", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://foo.2.3.4", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://foo.2.3.4.", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://foo.09", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://foo.09.", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://foo.0x4", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://foo.0x4.", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://foo.09..", - "base": "about:blank", + "base": null, "hash": "", "host": "foo.09..", "hostname": "foo.09..", - "href": "http://foo.09../", + "href":"http://foo.09../", "password": "", "pathname": "/", - "port": "", + "port":"", "protocol": "http:", "search": "", "username": "" }, { "input": "http://0999999999999999999/", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://foo.0x", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://foo.0XFfFfFfFfFfFfFfFfFfAcE123", - "base": "about:blank", + "base": null, "failure": true }, { "input": "http://💩.123/", - "base": "about:blank", + "base": null, "failure": true }, "U+0000 and U+FFFF in various places", { "input": "https://\u0000y", - "base": "about:blank", + "base": null, "failure": true }, { "input": "https://x/\u0000y", - "base": "about:blank", + "base": null, "hash": "", "host": "x", "hostname": "x", @@ -8673,7 +8828,7 @@ }, { "input": "https://x/?\u0000y", - "base": "about:blank", + "base": null, "hash": "", "host": "x", "hostname": "x", @@ -8687,7 +8842,7 @@ }, { "input": "https://x/?#\u0000y", - "base": "about:blank", + "base": null, "hash": "#%00y", "host": "x", "hostname": "x", @@ -8695,18 +8850,18 @@ "password": "", "pathname": "/", "port": "", - "protocol": "http:", + "protocol": "https:", "search": "", "username": "" }, { "input": "https://\uFFFFy", - "base": "about:blank", + "base": null, "failure": true }, { "input": "https://x/\uFFFFy", - "base": "about:blank", + "base": null, "hash": "", "host": "x", "hostname": "x", @@ -8720,7 +8875,7 @@ }, { "input": "https://x/?\uFFFFy", - "base": "about:blank", + "base": null, "hash": "", "host": "x", "hostname": "x", @@ -8734,7 +8889,7 @@ }, { "input": "https://x/?#\uFFFFy", - "base": "about:blank", + "base": null, "hash": "#%EF%BF%BFy", "host": "x", "hostname": "x", @@ -8748,7 +8903,7 @@ }, { "input": "non-special:\u0000y", - "base": "about:blank", + "base": null, "hash": "", "host": "", "hostname": "", @@ -8762,7 +8917,7 @@ }, { "input": "non-special:x/\u0000y", - "base": "about:blank", + "base": null, "hash": "", "host": "", "hostname": "", @@ -8776,7 +8931,7 @@ }, { "input": "non-special:x/?\u0000y", - "base": "about:blank", + "base": null, "hash": "", "host": "", "hostname": "", @@ -8790,7 +8945,7 @@ }, { "input": "non-special:x/?#\u0000y", - "base": "about:blank", + "base": null, "hash": "#%00y", "host": "", "hostname": "", @@ -8804,7 +8959,7 @@ }, { "input": "non-special:\uFFFFy", - "base": "about:blank", + "base": null, "hash": "", "host": "", "hostname": "", @@ -8818,7 +8973,7 @@ }, { "input": "non-special:x/\uFFFFy", - "base": "about:blank", + "base": null, "hash": "", "host": "", "hostname": "", @@ -8832,7 +8987,7 @@ }, { "input": "non-special:x/?\uFFFFy", - "base": "about:blank", + "base": null, "hash": "", "host": "", "hostname": "", @@ -8846,7 +9001,7 @@ }, { "input": "non-special:x/?#\uFFFFy", - "base": "about:blank", + "base": null, "hash": "#%EF%BF%BFy", "host": "", "hostname": "", @@ -8860,12 +9015,13 @@ }, { "input": "", - "base": "about:blank", - "failure": true + "base": null, + "failure": true, + "relativeTo": "non-opaque-path-base" }, { "input": "https://example.com/\"quoted\"", - "base": "about:blank", + "base": null, "hash": "", "host": "example.com", "hostname": "example.com", @@ -8877,5 +9033,487 @@ "protocol": "https:", "search": "", "username": "" + }, + { + "input": "https://a%C2%ADb/", + "base": null, + "hash": "", + "host": "ab", + "hostname": "ab", + "href": "https://ab/", + "origin": "https://ab", + "password": "", + "pathname": "/", + "port": "", + "protocol": "https:", + "search": "", + "username": "" + }, + { + "comment": "Empty host after domain to ASCII", + "input": "https://\u00AD/", + "base": null, + "failure": true + }, + { + "input": "https://%C2%AD/", + "base": null, + "failure": true + }, + { + "input": "https://xn--/", + "base": null, + "failure": true + }, + "Non-special schemes that some implementations might incorrectly treat as special", + { + "input": "data://example.com:8080/pathname?search#hash", + "base": null, + "href": "data://example.com:8080/pathname?search#hash", + "origin": "null", + "protocol": "data:", + "username": "", + "password": "", + "host": "example.com:8080", + "hostname": "example.com", + "port": "8080", + "pathname": "/pathname", + "search": "?search", + "hash": "#hash" + }, + { + "input": "data:///test", + "base": null, + "href": "data:///test", + "origin": "null", + "protocol": "data:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test", + "search": "", + "hash": "" + }, + { + "input": "data://test/a/../b", + "base": null, + "href": "data://test/b", + "origin": "null", + "protocol": "data:", + "username": "", + "password": "", + "host": "test", + "hostname": "test", + "port": "", + "pathname": "/b", + "search": "", + "hash": "" + }, + { + "input": "data://:443", + "base": null, + "failure": true + }, + { + "input": "data://test:test", + "base": null, + "failure": true + }, + { + "input": "data://[:1]", + "base": null, + "failure": true + }, + { + "input": "javascript://example.com:8080/pathname?search#hash", + "base": null, + "href": "javascript://example.com:8080/pathname?search#hash", + "origin": "null", + "protocol": "javascript:", + "username": "", + "password": "", + "host": "example.com:8080", + "hostname": "example.com", + "port": "8080", + "pathname": "/pathname", + "search": "?search", + "hash": "#hash" + }, + { + "input": "javascript:///test", + "base": null, + "href": "javascript:///test", + "origin": "null", + "protocol": "javascript:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test", + "search": "", + "hash": "" + }, + { + "input": "javascript://test/a/../b", + "base": null, + "href": "javascript://test/b", + "origin": "null", + "protocol": "javascript:", + "username": "", + "password": "", + "host": "test", + "hostname": "test", + "port": "", + "pathname": "/b", + "search": "", + "hash": "" + }, + { + "input": "javascript://:443", + "base": null, + "failure": true + }, + { + "input": "javascript://test:test", + "base": null, + "failure": true + }, + { + "input": "javascript://[:1]", + "base": null, + "failure": true + }, + { + "input": "mailto://example.com:8080/pathname?search#hash", + "base": null, + "href": "mailto://example.com:8080/pathname?search#hash", + "origin": "null", + "protocol": "mailto:", + "username": "", + "password": "", + "host": "example.com:8080", + "hostname": "example.com", + "port": "8080", + "pathname": "/pathname", + "search": "?search", + "hash": "#hash" + }, + { + "input": "mailto:///test", + "base": null, + "href": "mailto:///test", + "origin": "null", + "protocol": "mailto:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test", + "search": "", + "hash": "" + }, + { + "input": "mailto://test/a/../b", + "base": null, + "href": "mailto://test/b", + "origin": "null", + "protocol": "mailto:", + "username": "", + "password": "", + "host": "test", + "hostname": "test", + "port": "", + "pathname": "/b", + "search": "", + "hash": "" + }, + { + "input": "mailto://:443", + "base": null, + "failure": true + }, + { + "input": "mailto://test:test", + "base": null, + "failure": true + }, + { + "input": "mailto://[:1]", + "base": null, + "failure": true + }, + { + "input": "intent://example.com:8080/pathname?search#hash", + "base": null, + "href": "intent://example.com:8080/pathname?search#hash", + "origin": "null", + "protocol": "intent:", + "username": "", + "password": "", + "host": "example.com:8080", + "hostname": "example.com", + "port": "8080", + "pathname": "/pathname", + "search": "?search", + "hash": "#hash" + }, + { + "input": "intent:///test", + "base": null, + "href": "intent:///test", + "origin": "null", + "protocol": "intent:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test", + "search": "", + "hash": "" + }, + { + "input": "intent://test/a/../b", + "base": null, + "href": "intent://test/b", + "origin": "null", + "protocol": "intent:", + "username": "", + "password": "", + "host": "test", + "hostname": "test", + "port": "", + "pathname": "/b", + "search": "", + "hash": "" + }, + { + "input": "intent://:443", + "base": null, + "failure": true + }, + { + "input": "intent://test:test", + "base": null, + "failure": true + }, + { + "input": "intent://[:1]", + "base": null, + "failure": true + }, + { + "input": "urn://example.com:8080/pathname?search#hash", + "base": null, + "href": "urn://example.com:8080/pathname?search#hash", + "origin": "null", + "protocol": "urn:", + "username": "", + "password": "", + "host": "example.com:8080", + "hostname": "example.com", + "port": "8080", + "pathname": "/pathname", + "search": "?search", + "hash": "#hash" + }, + { + "input": "urn:///test", + "base": null, + "href": "urn:///test", + "origin": "null", + "protocol": "urn:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test", + "search": "", + "hash": "" + }, + { + "input": "urn://test/a/../b", + "base": null, + "href": "urn://test/b", + "origin": "null", + "protocol": "urn:", + "username": "", + "password": "", + "host": "test", + "hostname": "test", + "port": "", + "pathname": "/b", + "search": "", + "hash": "" + }, + { + "input": "urn://:443", + "base": null, + "failure": true + }, + { + "input": "urn://test:test", + "base": null, + "failure": true + }, + { + "input": "urn://[:1]", + "base": null, + "failure": true + }, + { + "input": "turn://example.com:8080/pathname?search#hash", + "base": null, + "href": "turn://example.com:8080/pathname?search#hash", + "origin": "null", + "protocol": "turn:", + "username": "", + "password": "", + "host": "example.com:8080", + "hostname": "example.com", + "port": "8080", + "pathname": "/pathname", + "search": "?search", + "hash": "#hash" + }, + { + "input": "turn:///test", + "base": null, + "href": "turn:///test", + "origin": "null", + "protocol": "turn:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test", + "search": "", + "hash": "" + }, + { + "input": "turn://test/a/../b", + "base": null, + "href": "turn://test/b", + "origin": "null", + "protocol": "turn:", + "username": "", + "password": "", + "host": "test", + "hostname": "test", + "port": "", + "pathname": "/b", + "search": "", + "hash": "" + }, + { + "input": "turn://:443", + "base": null, + "failure": true + }, + { + "input": "turn://test:test", + "base": null, + "failure": true + }, + { + "input": "turn://[:1]", + "base": null, + "failure": true + }, + { + "input": "stun://example.com:8080/pathname?search#hash", + "base": null, + "href": "stun://example.com:8080/pathname?search#hash", + "origin": "null", + "protocol": "stun:", + "username": "", + "password": "", + "host": "example.com:8080", + "hostname": "example.com", + "port": "8080", + "pathname": "/pathname", + "search": "?search", + "hash": "#hash" + }, + { + "input": "stun:///test", + "base": null, + "href": "stun:///test", + "origin": "null", + "protocol": "stun:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test", + "search": "", + "hash": "" + }, + { + "input": "stun://test/a/../b", + "base": null, + "href": "stun://test/b", + "origin": "null", + "protocol": "stun:", + "username": "", + "password": "", + "host": "test", + "hostname": "test", + "port": "", + "pathname": "/b", + "search": "", + "hash": "" + }, + { + "input": "stun://:443", + "base": null, + "failure": true + }, + { + "input": "stun://test:test", + "base": null, + "failure": true + }, + { + "input": "stun://[:1]", + "base": null, + "failure": true + }, + { + "input": "w://x:0", + "base": null, + "href": "w://x:0", + "origin": "null", + "protocol": "w:", + "username": "", + "password": "", + "host": "x:0", + "hostname": "x", + "port": "0", + "pathname": "", + "search": "", + "hash": "" + }, + { + "input": "west://x:0", + "base": null, + "href": "west://x:0", + "origin": "null", + "protocol": "west:", + "username": "", + "password": "", + "host": "x:0", + "hostname": "x", + "port": "0", + "pathname": "", + "search": "", + "hash": "" } ]