// Copyright (c) 2023 Cloudflare, Inc. // Licensed under the Apache 2.0 license found in the LICENSE file or at: // https://opensource.org/licenses/Apache-2.0 import { deepStrictEqual, strictEqual, ok, fail, throws } from 'node:assert'; export const constructAndGet = { test() { const cases = [ { input: 'https://capnproto.org', pathname: '/', comment: 'special URL, 0-component path', }, { input: 'https://capnproto.org/', pathname: '/', comment: 'special URL, 1-component path with empty terminal component', }, { input: 'https://capnproto.org/foo', pathname: '/foo', comment: 'special URL, 1-component path', }, { input: 'https://capnproto.org/foo/', pathname: '/foo/', comment: 'special URL, 2-component path with empty terminal component', }, { input: 'https://capnproto.org/%2F', pathname: '/%2F', comment: 'encoded slash can be a path component', }, { input: 'https://capnproto.org//', pathname: '//', comment: '// in path is not collapsed', }, { input: 'https://capnproto.org/./', pathname: '/', comment: '/./ in path is collapsed', }, { input: 'https://capnproto.org/?<>', search: '?%3C%3E', comment: 'angle brackets in search get percent-encoded', }, { input: 'https://capnproto.org/??', search: '??', comment: 'question mark in search does not get percent-encoded', }, { input: 'https://capnproto.org/?foo', search: '?foo', href: 'https://capnproto.org/?foo', comment: 'No-valued/empty-valued query parameters are preserved round-trip', }, { input: 'https://capnproto.org/?foo=', search: '?foo=', href: 'https://capnproto.org/?foo=', comment: 'No-valued/empty-valued query parameters are preserved round-trip', }, { input: 'https://capnproto.org/?foo=&bar', search: '?foo=&bar', href: 'https://capnproto.org/?foo=&bar', comment: 'No-valued/empty-valued query parameters are preserved round-trip', }, { input: 'https://capnproto.org/?foo&bar=', search: '?foo&bar=', href: 'https://capnproto.org/?foo&bar=', comment: 'No-valued/empty-valued query parameters are preserved round-trip', }, { input: 'https://capnproto.org/?foo+bar=baz+qux', search: '?foo+bar=baz+qux', comment: 'pluses in search do not get percent-encoded', }, { input: 'https://capnproto.org/?😺', search: '?%F0%9F%98%BA', comment: 'cat emoji in search gets percent-encoded', }, { input: 'https://capnproto.org/#😺', hash: '#%F0%9F%98%BA', comment: 'cat emoji in hash gets percent-encoded', }, { input: 'https://capnproto.org:443/', href: 'https://capnproto.org/', comment: 'Parsing a URL with an explicit scheme-default port ignores the port', }, { input: 'https://capnproto.org:/', href: 'https://capnproto.org/', comment: 'Parsing a URL with a ":" but no port ignores port', }, { input: 'http://foo/bar;baz@qux', href: 'http://foo/bar;baz@qux', comment: 'URL path components are encoded with the path percent encode set', }, { input: 'https://jam_com.helpusersvote.net/', href: 'https://jam_com.helpusersvote.net/', comment: 'Underscores are allowed in hostnames', }, { input: 'https://foo%25bar:baz%25qux@capnproto.org/foo%25bar?foo%25bar=baz%25qux#foo%25bar', href: 'https://foo%25bar:baz%25qux@capnproto.org/foo%25bar?foo%25bar=baz%25qux#foo%25bar', comment: 'Encoded percent signs in userinfo, path, query, and fragment get round-tripped', }, ]; cases.forEach((test) => { ['pathname', 'search', 'hash', 'href'].forEach((attribute) => { const url = new URL(test.input); if (test[attribute] !== undefined) { strictEqual( url[attribute], test[attribute], `${test.input}: ${test.comment}` ); } }); }); }, }; export const constructSetAndGet = { test() { const cases = { protocol: [ { href: 'https://example.com/', new_value: 'http', expected: { href: 'http://example.com/', }, comment: 'Setting scheme on URL with null port does not change port', }, { href: 'https://example.com:80/', new_value: 'http', expected: { href: 'http://example.com/', }, comment: 'Setting scheme on URL with port that is the new scheme-default port nulls out port', }, { href: 'https://example.com:1234/', new_value: 'http', expected: { href: 'http://example.com:1234/', }, comment: 'Setting scheme on URL with non-scheme-default port preserves port', }, ], search: [ { href: 'https://capnproto.org/', new_value: '#', expected: { href: 'https://capnproto.org/?%23', search: '?%23', }, }, { href: 'https://capnproto.org/', new_value: '#=#', expected: { href: 'https://capnproto.org/?%23=%23', search: '?%23=%23', }, }, ], host: [ { href: 'https://example.com/', new_value: 'foo.example.com:', expected: { href: 'https://foo.example.com/', }, comment: 'Setting host with ":" but no port ignores port', }, { href: 'https://example.com/', new_value: 'foo.example.com:80', expected: { href: 'https://foo.example.com:80/', }, comment: 'Setting host with non-scheme-default port sets port', }, { href: 'https://example.com:1234/', new_value: 'foo.example.com:443', expected: { href: 'https://foo.example.com/', }, comment: 'Setting host with scheme-default port nulls out port', }, { href: 'https://example.com/', new_value: 'foo.example.com:443', expected: { href: 'https://foo.example.com/', }, comment: 'Setting host with scheme-default port nulls out port', }, ], port: [ { href: 'https://example.com/', new_value: '443', expected: { href: 'https://example.com/', }, comment: 'Setting port to scheme-default port is a no-op', }, { href: 'https://example.com:1234/', new_value: '443', expected: { href: 'https://example.com/', }, comment: 'Setting port to scheme-default port nulls out port', }, { href: 'https://example.com/', new_value: '1234', expected: { href: 'https://example.com:1234/', }, comment: 'Setting port to non-scheme-default port adopts port', }, { href: 'https://example.com:80/', new_value: '1234', expected: { href: 'https://example.com:1234/', }, comment: 'Setting port to non-scheme-default port adopts port', }, { href: 'https://example.com:1234/', new_value: '', expected: { href: 'https://example.com/', }, comment: 'Setting port to the empty string nulls out port', }, ], hostname: [ { href: 'http://example.com/path/to/something?query=foo#hash', new_value: 'newexample.com', expected: { href: 'http://newexample.com/path/to/something?query=foo#hash', }, }, ], }; for (const attribute in cases) { cases[attribute].forEach((test) => { const url = new URL(test.href); url[attribute] = test.new_value; for (const a in test.expected) { strictEqual( url[a], test.expected[a], `${test.href}: ${test.comment}` ); } }); } }, }; export const urlSearchParamsStringifyBehavior = { test() { const url = new URL('https://example.com/?foo&bar=&baz=qux'); strictEqual(url.href, 'https://example.com/?foo&bar=&baz=qux'); strictEqual(url.search, '?foo&bar=&baz=qux'); strictEqual(url.searchParams.toString(), 'foo=&bar=&baz=qux'); }, }; export const urlSearchParamsForEach = { test() { let searchParams = new URLSearchParams(''); searchParams.forEach(() => { fail('Should not have been called'); }); const foreachOutput = []; searchParams = new URLSearchParams('key1=value1&key2=value2'); strictEqual(searchParams.size, 2); let pushed = false; searchParams.forEach((val, key) => { foreachOutput.push([key, val]); if (!pushed) { // We can add params within this loop but it's not really safe // because it will cause the loop to run forever if we're not // careful. pushed = true; searchParams.set('key3', 'value3'); } }); deepStrictEqual(foreachOutput, [ ['key1', 'value1'], ['key2', 'value2'], ['key3', 'value3'], ]); strictEqual(searchParams.size, 3); // Calling forEach with no argument throws throws(() => searchParams.forEach()); // Calling forEach with wrong arguments throws throws(() => searchParams.forEach(1)); // This can be overridden by the second argument searchParams.forEach(function () { strictEqual(this, 1); }, 1); // Propagates errors throws(() => searchParams.forEach(() => { throw new Error('boom'); }) ); }, }; export const urlSearchParamsInit1 = { test() { const search1 = new URLSearchParams('a=b'); const search2 = new URLSearchParams(search1); strictEqual(search1.toString(), search2.toString()); }, }; export const urlSearchParamsInit2 = { test() { const search1 = new URLSearchParams('a=b'); search1[Symbol.iterator] = function* () { yield ['y', 'z']; }; const search2 = new URLSearchParams(search1); ok(!search2.has('a')); ok(search2.has('y')); strictEqual(search2.get('y'), 'z'); }, }; export const urlSearchParamsInit3 = { test() { // If the initializer has a deleted iterator, then its // contents are ignored but can still be interpreted as // a dictionary. const search1 = new URLSearchParams('a=b'); search1[Symbol.iterator] = undefined; search1.y = 'z'; const search2 = new URLSearchParams(search1); ok(!search2.has('a')); ok(search2.has('y')); strictEqual(search2.get('y'), 'z'); }, }; export const urlSearchParamsInit4 = { test() { const formdata = new FormData(); formdata.append('a', 'b'); ok(formdata.has('a')); const search2 = new URLSearchParams(formdata); ok(search2.has('a')); strictEqual(search2.get('a'), 'b'); }, }; export const urlSearchParamsInit5 = { test() { const formdata = new FormData(); formdata.append('a', 'b'); formdata[Symbol.iterator] = undefined; const search2 = new URLSearchParams(formdata); ok(!search2.has('a')); }, }; export const urlToJson = { test() { const url = new URL('https://example.com'); strictEqual(JSON.stringify(url), '"https://example.com/"'); }, }; export const urlSearchParamsSet = { test() { const url = new URL('https://example.com?c=d'); url.searchParams.set('a', 'b'); strictEqual(url.searchParams.size, 2); url.searchParams.delete('c'); strictEqual(url.searchParams.size, 1); ok(url.searchParams.has('a')); ok(!url.searchParams.has('c')); ok(url.searchParams.has('a', 'b')); ok(!url.searchParams.has('a', 'c')); url.searchParams.delete('a', 'c'); ok(url.searchParams.has('a')); }, }; export const urlConstructorTests = { test() { const cases = [ '# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/script-tests/segments.js', { input: 'http://example\t.\norg', base: 'http://example.org/foo/bar', href: 'http://example.org/', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/', search: '', hash: '', }, { input: 'C|/', base: 'file://host/dir/file', href: 'file://host/C:/', protocol: 'file:', username: '', password: '', host: 'host', hostname: 'host', port: '', pathname: '/C:/', search: '', hash: '', }, { input: 'C|\n/', base: 'file://host/dir/file', href: 'file://host/C:/', protocol: 'file:', username: '', password: '', host: 'host', hostname: 'host', port: '', pathname: '/C:/', search: '', hash: '', }, { input: 'https://:@test', base: 'about:blank', href: 'https://test/', origin: 'https://test', protocol: 'https:', username: '', password: '', host: 'test', hostname: 'test', port: '', pathname: '/', search: '', hash: '', }, { input: 'non-special://test:@test/x', base: 'about:blank', href: 'non-special://test@test/x', origin: 'null', protocol: 'non-special:', username: 'test', password: '', host: 'test', hostname: 'test', port: '', pathname: '/x', search: '', hash: '', }, { input: 'non-special://:@test/x', base: 'about:blank', href: 'non-special://test/x', origin: 'null', protocol: 'non-special:', username: '', password: '', host: 'test', hostname: 'test', port: '', pathname: '/x', search: '', hash: '', }, { input: 'http:foo.com', base: 'http://example.org/foo/bar', href: 'http://example.org/foo/foo.com', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/foo/foo.com', search: '', hash: '', }, { input: '\t :foo.com \n', base: 'http://example.org/foo/bar', href: 'http://example.org/foo/:foo.com', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/foo/:foo.com', search: '', hash: '', }, { input: ' foo.com ', base: 'http://example.org/foo/bar', href: 'http://example.org/foo/foo.com', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/foo/foo.com', search: '', hash: '', }, { input: 'a:\t foo.com', base: 'http://example.org/foo/bar', href: 'a: foo.com', origin: 'null', protocol: 'a:', username: '', password: '', host: '', hostname: '', port: '', pathname: ' foo.com', search: '', hash: '', }, { input: 'http://f:21/ b ? d # e ', base: 'http://example.org/foo/bar', href: 'http://f:21/%20b%20?%20d%20#%20e', origin: 'http://f:21', protocol: 'http:', username: '', password: '', host: 'f:21', hostname: 'f', port: '21', pathname: '/%20b%20', search: '?%20d%20', hash: '#%20e', }, { input: 'lolscheme:x x#x x', base: 'about:blank', href: 'lolscheme:x x#x%20x', protocol: 'lolscheme:', username: '', password: '', host: '', hostname: '', port: '', pathname: 'x x', search: '', hash: '#x%20x', }, { input: 'http://f:/c', base: 'http://example.org/foo/bar', href: 'http://f/c', origin: 'http://f', protocol: 'http:', username: '', password: '', host: 'f', hostname: 'f', port: '', pathname: '/c', search: '', hash: '', }, { input: 'http://f:0/c', base: 'http://example.org/foo/bar', href: 'http://f:0/c', origin: 'http://f:0', protocol: 'http:', username: '', password: '', host: 'f:0', hostname: 'f', port: '0', pathname: '/c', search: '', hash: '', }, { input: 'http://f:00000000000000/c', base: 'http://example.org/foo/bar', href: 'http://f:0/c', origin: 'http://f:0', protocol: 'http:', username: '', password: '', host: 'f:0', hostname: 'f', port: '0', pathname: '/c', search: '', hash: '', }, { input: 'http://f:00000000000000000000080/c', base: 'http://example.org/foo/bar', href: 'http://f/c', origin: 'http://f', protocol: 'http:', username: '', password: '', host: 'f', hostname: 'f', port: '', pathname: '/c', search: '', hash: '', }, { input: 'http://f:b/c', base: 'http://example.org/foo/bar', failure: true, }, { input: 'http://f: /c', base: 'http://example.org/foo/bar', failure: true, }, { input: 'http://f:\n/c', base: 'http://example.org/foo/bar', href: 'http://f/c', origin: 'http://f', protocol: 'http:', username: '', password: '', host: 'f', hostname: 'f', port: '', pathname: '/c', search: '', hash: '', }, { input: 'http://f:fifty-two/c', base: 'http://example.org/foo/bar', failure: true, }, { input: 'http://f:999999/c', base: 'http://example.org/foo/bar', failure: true, }, { input: 'non-special://f:999999/c', base: 'http://example.org/foo/bar', failure: true, }, { input: 'http://f: 21 / b ? d # e ', base: 'http://example.org/foo/bar', failure: true, }, { input: '', base: 'http://example.org/foo/bar', href: 'http://example.org/foo/bar', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/foo/bar', search: '', hash: '', }, { input: ' \t', base: 'http://example.org/foo/bar', href: 'http://example.org/foo/bar', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/foo/bar', search: '', hash: '', }, { input: ':foo.com/', base: 'http://example.org/foo/bar', href: 'http://example.org/foo/:foo.com/', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/foo/:foo.com/', search: '', hash: '', }, { input: ':foo.com\\', base: 'http://example.org/foo/bar', href: 'http://example.org/foo/:foo.com/', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/foo/:foo.com/', search: '', hash: '', }, { input: ':', base: 'http://example.org/foo/bar', href: 'http://example.org/foo/:', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/foo/:', search: '', hash: '', }, { input: ':a', base: 'http://example.org/foo/bar', href: 'http://example.org/foo/:a', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/foo/:a', search: '', hash: '', }, { input: ':/', base: 'http://example.org/foo/bar', href: 'http://example.org/foo/:/', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/foo/:/', search: '', hash: '', }, { input: ':\\', base: 'http://example.org/foo/bar', href: 'http://example.org/foo/:/', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/foo/:/', search: '', hash: '', }, { input: ':#', base: 'http://example.org/foo/bar', href: 'http://example.org/foo/:#', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/foo/:', search: '', hash: '', }, { input: '#', base: 'http://example.org/foo/bar', href: 'http://example.org/foo/bar#', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/foo/bar', search: '', hash: '', }, { input: '#/', base: 'http://example.org/foo/bar', href: 'http://example.org/foo/bar#/', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/foo/bar', search: '', hash: '#/', }, { input: '#\\', base: 'http://example.org/foo/bar', href: 'http://example.org/foo/bar#\\', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/foo/bar', search: '', hash: '#\\', }, { input: '#;?', base: 'http://example.org/foo/bar', href: 'http://example.org/foo/bar#;?', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/foo/bar', search: '', hash: '#;?', }, { input: '?', base: 'http://example.org/foo/bar', href: 'http://example.org/foo/bar?', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/foo/bar', search: '', hash: '', }, { input: '/', base: 'http://example.org/foo/bar', href: 'http://example.org/', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/', search: '', hash: '', }, { input: ':23', base: 'http://example.org/foo/bar', href: 'http://example.org/foo/:23', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/foo/:23', search: '', hash: '', }, { input: '/:23', base: 'http://example.org/foo/bar', href: 'http://example.org/:23', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/:23', search: '', hash: '', }, { input: '::', base: 'http://example.org/foo/bar', href: 'http://example.org/foo/::', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/foo/::', search: '', hash: '', }, { input: '::23', base: 'http://example.org/foo/bar', href: 'http://example.org/foo/::23', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/foo/::23', search: '', hash: '', }, { input: 'foo://', base: 'http://example.org/foo/bar', href: 'foo://', origin: 'null', protocol: 'foo:', username: '', password: '', host: '', hostname: '', port: '', pathname: '', search: '', hash: '', }, { input: 'http://a:b@c:29/d', base: 'http://example.org/foo/bar', href: 'http://a:b@c:29/d', origin: 'http://c:29', protocol: 'http:', username: 'a', password: 'b', host: 'c:29', hostname: 'c', port: '29', pathname: '/d', search: '', hash: '', }, { input: 'http::@c:29', base: 'http://example.org/foo/bar', href: 'http://example.org/foo/:@c:29', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/foo/:@c:29', search: '', hash: '', }, { input: 'http://&a:foo(b]c@d:2/', base: 'http://example.org/foo/bar', href: 'http://&a:foo(b%5Dc@d:2/', origin: 'http://d:2', protocol: 'http:', username: '&a', password: 'foo(b%5Dc', host: 'd:2', hostname: 'd', port: '2', pathname: '/', search: '', hash: '', }, { input: 'http://::@c@d:2', base: 'http://example.org/foo/bar', href: 'http://:%3A%40c@d:2/', origin: 'http://d:2', protocol: 'http:', username: '', password: '%3A%40c', host: 'd:2', hostname: 'd', port: '2', pathname: '/', search: '', hash: '', }, { input: 'http://foo.com:b@d/', base: 'http://example.org/foo/bar', href: 'http://foo.com:b@d/', origin: 'http://d', protocol: 'http:', username: 'foo.com', password: 'b', host: 'd', hostname: 'd', port: '', pathname: '/', search: '', hash: '', }, { input: 'http://foo.com/\\@', base: 'http://example.org/foo/bar', href: 'http://foo.com//@', origin: 'http://foo.com', protocol: 'http:', username: '', password: '', host: 'foo.com', hostname: 'foo.com', port: '', pathname: '//@', search: '', hash: '', }, { input: 'http:\\\\foo.com\\', base: 'http://example.org/foo/bar', href: 'http://foo.com/', origin: 'http://foo.com', protocol: 'http:', username: '', password: '', host: 'foo.com', hostname: 'foo.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'http:\\\\a\\b:c\\d@foo.com\\', base: 'http://example.org/foo/bar', href: 'http://a/b:c/d@foo.com/', origin: 'http://a', protocol: 'http:', username: '', password: '', host: 'a', hostname: 'a', port: '', pathname: '/b:c/d@foo.com/', search: '', hash: '', }, { input: 'foo:/', base: 'http://example.org/foo/bar', href: 'foo:/', origin: 'null', protocol: 'foo:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/', search: '', hash: '', }, { input: 'foo:/bar.com/', base: 'http://example.org/foo/bar', href: 'foo:/bar.com/', origin: 'null', protocol: 'foo:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/bar.com/', search: '', hash: '', }, { input: 'foo://///////', base: 'http://example.org/foo/bar', href: 'foo://///////', origin: 'null', protocol: 'foo:', username: '', password: '', host: '', hostname: '', port: '', pathname: '///////', search: '', hash: '', }, { input: 'foo://///////bar.com/', base: 'http://example.org/foo/bar', href: 'foo://///////bar.com/', origin: 'null', protocol: 'foo:', username: '', password: '', host: '', hostname: '', port: '', pathname: '///////bar.com/', search: '', hash: '', }, { input: 'foo:////://///', base: 'http://example.org/foo/bar', href: 'foo:////://///', origin: 'null', protocol: 'foo:', username: '', password: '', host: '', hostname: '', port: '', pathname: '//://///', search: '', hash: '', }, { input: 'c:/foo', base: 'http://example.org/foo/bar', href: 'c:/foo', origin: 'null', protocol: 'c:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/foo', search: '', hash: '', }, { input: '//foo/bar', base: 'http://example.org/foo/bar', href: 'http://foo/bar', origin: 'http://foo', protocol: 'http:', username: '', password: '', host: 'foo', hostname: 'foo', port: '', pathname: '/bar', search: '', hash: '', }, { input: 'http://foo/path;a??e#f#g', base: 'http://example.org/foo/bar', href: 'http://foo/path;a??e#f#g', origin: 'http://foo', protocol: 'http:', username: '', password: '', host: 'foo', hostname: 'foo', port: '', pathname: '/path;a', search: '??e', hash: '#f#g', }, { input: 'http://foo/abcd?efgh?ijkl', base: 'http://example.org/foo/bar', href: 'http://foo/abcd?efgh?ijkl', origin: 'http://foo', protocol: 'http:', username: '', password: '', host: 'foo', hostname: 'foo', port: '', pathname: '/abcd', search: '?efgh?ijkl', hash: '', }, { input: 'http://foo/abcd#foo?bar', base: 'http://example.org/foo/bar', href: 'http://foo/abcd#foo?bar', origin: 'http://foo', protocol: 'http:', username: '', password: '', host: 'foo', hostname: 'foo', port: '', pathname: '/abcd', search: '', hash: '#foo?bar', }, { input: '[61:24:74]:98', base: 'http://example.org/foo/bar', href: 'http://example.org/foo/[61:24:74]:98', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/foo/[61:24:74]:98', search: '', hash: '', }, { input: 'http:[61:27]/:foo', base: 'http://example.org/foo/bar', href: 'http://example.org/foo/[61:27]/:foo', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/foo/[61:27]/:foo', search: '', hash: '', }, { input: 'http://[1::2]:3:4', base: 'http://example.org/foo/bar', failure: true, }, { input: 'http://2001::1', base: 'http://example.org/foo/bar', failure: true, }, { input: 'http://2001::1]', base: 'http://example.org/foo/bar', failure: true, }, { input: 'http://2001::1]:80', base: 'http://example.org/foo/bar', failure: true, }, { input: 'http://[2001::1]', base: 'http://example.org/foo/bar', href: 'http://[2001::1]/', origin: 'http://[2001::1]', protocol: 'http:', username: '', password: '', host: '[2001::1]', hostname: '[2001::1]', port: '', pathname: '/', search: '', hash: '', }, { input: 'http://[::127.0.0.1]', base: 'http://example.org/foo/bar', href: 'http://[::7f00:1]/', origin: 'http://[::7f00:1]', protocol: 'http:', username: '', password: '', host: '[::7f00:1]', hostname: '[::7f00:1]', port: '', pathname: '/', search: '', hash: '', }, { input: 'http://[0:0:0:0:0:0:13.1.68.3]', base: 'http://example.org/foo/bar', href: 'http://[::d01:4403]/', origin: 'http://[::d01:4403]', protocol: 'http:', username: '', password: '', host: '[::d01:4403]', hostname: '[::d01:4403]', port: '', pathname: '/', search: '', hash: '', }, { input: 'http://[2001::1]:80', base: 'http://example.org/foo/bar', href: 'http://[2001::1]/', origin: 'http://[2001::1]', protocol: 'http:', username: '', password: '', host: '[2001::1]', hostname: '[2001::1]', port: '', pathname: '/', search: '', hash: '', }, { input: 'http:/example.com/', base: 'http://example.org/foo/bar', href: 'http://example.org/example.com/', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/example.com/', search: '', hash: '', }, { input: 'ftp:/example.com/', base: 'http://example.org/foo/bar', href: 'ftp://example.com/', origin: 'ftp://example.com', protocol: 'ftp:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'https:/example.com/', base: 'http://example.org/foo/bar', href: 'https://example.com/', origin: 'https://example.com', protocol: 'https:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'madeupscheme:/example.com/', base: 'http://example.org/foo/bar', href: 'madeupscheme:/example.com/', origin: 'null', protocol: 'madeupscheme:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/example.com/', search: '', hash: '', }, { input: 'file:/example.com/', base: 'http://example.org/foo/bar', href: 'file:///example.com/', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/example.com/', search: '', hash: '', }, { input: 'file://example:1/', base: 'about:blank', failure: true, }, { input: 'file://example:test/', base: 'about:blank', failure: true, }, { input: 'file://example%/', base: 'about:blank', failure: true, }, { input: 'file://[example]/', base: 'about:blank', failure: true, }, { input: 'ftps:/example.com/', base: 'http://example.org/foo/bar', href: 'ftps:/example.com/', origin: 'null', protocol: 'ftps:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/example.com/', search: '', hash: '', }, { input: 'gopher:/example.com/', base: 'http://example.org/foo/bar', href: 'gopher:/example.com/', protocol: 'gopher:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/example.com/', search: '', hash: '', }, { input: 'ws:/example.com/', base: 'http://example.org/foo/bar', href: 'ws://example.com/', origin: 'ws://example.com', protocol: 'ws:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'wss:/example.com/', base: 'http://example.org/foo/bar', href: 'wss://example.com/', origin: 'wss://example.com', protocol: 'wss:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'data:/example.com/', base: 'http://example.org/foo/bar', href: 'data:/example.com/', origin: 'null', protocol: 'data:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/example.com/', search: '', hash: '', }, { input: 'javascript:/example.com/', base: 'http://example.org/foo/bar', href: 'javascript:/example.com/', origin: 'null', protocol: 'javascript:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/example.com/', search: '', hash: '', }, { input: 'mailto:/example.com/', base: 'http://example.org/foo/bar', href: 'mailto:/example.com/', origin: 'null', protocol: 'mailto:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/example.com/', search: '', hash: '', }, { input: 'http:example.com/', base: 'http://example.org/foo/bar', href: 'http://example.org/foo/example.com/', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/foo/example.com/', search: '', hash: '', }, { input: 'ftp:example.com/', base: 'http://example.org/foo/bar', href: 'ftp://example.com/', origin: 'ftp://example.com', protocol: 'ftp:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'https:example.com/', base: 'http://example.org/foo/bar', href: 'https://example.com/', origin: 'https://example.com', protocol: 'https:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'madeupscheme:example.com/', base: 'http://example.org/foo/bar', href: 'madeupscheme:example.com/', origin: 'null', protocol: 'madeupscheme:', username: '', password: '', host: '', hostname: '', port: '', pathname: 'example.com/', search: '', hash: '', }, { input: 'ftps:example.com/', base: 'http://example.org/foo/bar', href: 'ftps:example.com/', origin: 'null', protocol: 'ftps:', username: '', password: '', host: '', hostname: '', port: '', pathname: 'example.com/', search: '', hash: '', }, { input: 'gopher:example.com/', base: 'http://example.org/foo/bar', href: 'gopher:example.com/', protocol: 'gopher:', username: '', password: '', host: '', hostname: '', port: '', pathname: 'example.com/', search: '', hash: '', }, { input: 'ws:example.com/', base: 'http://example.org/foo/bar', href: 'ws://example.com/', origin: 'ws://example.com', protocol: 'ws:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'wss:example.com/', base: 'http://example.org/foo/bar', href: 'wss://example.com/', origin: 'wss://example.com', protocol: 'wss:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'data:example.com/', base: 'http://example.org/foo/bar', href: 'data:example.com/', origin: 'null', protocol: 'data:', username: '', password: '', host: '', hostname: '', port: '', pathname: 'example.com/', search: '', hash: '', }, { input: 'javascript:example.com/', base: 'http://example.org/foo/bar', href: 'javascript:example.com/', origin: 'null', protocol: 'javascript:', username: '', password: '', host: '', hostname: '', port: '', pathname: 'example.com/', search: '', hash: '', }, { input: 'mailto:example.com/', base: 'http://example.org/foo/bar', href: 'mailto:example.com/', origin: 'null', protocol: 'mailto:', username: '', password: '', host: '', hostname: '', port: '', pathname: 'example.com/', search: '', hash: '', }, { input: '/a/b/c', base: 'http://example.org/foo/bar', href: 'http://example.org/a/b/c', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/a/b/c', search: '', hash: '', }, { input: '/a/ /c', base: 'http://example.org/foo/bar', href: 'http://example.org/a/%20/c', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/a/%20/c', search: '', hash: '', }, { input: '/a%2fc', base: 'http://example.org/foo/bar', href: 'http://example.org/a%2fc', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/a%2fc', search: '', hash: '', }, { input: '/a/%2f/c', base: 'http://example.org/foo/bar', href: 'http://example.org/a/%2f/c', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/a/%2f/c', search: '', hash: '', }, { input: '#β', base: 'http://example.org/foo/bar', href: 'http://example.org/foo/bar#%CE%B2', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/foo/bar', search: '', hash: '#%CE%B2', }, { input: 'data:text/html,test#test', base: 'http://example.org/foo/bar', href: 'data:text/html,test#test', origin: 'null', protocol: 'data:', username: '', password: '', host: '', hostname: '', port: '', pathname: 'text/html,test', search: '', hash: '#test', }, { input: 'tel:1234567890', base: 'http://example.org/foo/bar', href: 'tel:1234567890', origin: 'null', protocol: 'tel:', username: '', password: '', host: '', hostname: '', port: '', pathname: '1234567890', search: '', hash: '', }, '# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/file.html', { input: 'file:c:\\foo\\bar.html', base: 'file:///tmp/mock/path', href: 'file:///c:/foo/bar.html', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/c:/foo/bar.html', search: '', hash: '', }, { input: ' File:c|////foo\\bar.html', base: 'file:///tmp/mock/path', href: 'file:///c:////foo/bar.html', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/c:////foo/bar.html', search: '', hash: '', }, { input: 'C|/foo/bar', base: 'file:///tmp/mock/path', href: 'file:///C:/foo/bar', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/C:/foo/bar', search: '', hash: '', }, { input: '/C|\\foo\\bar', base: 'file:///tmp/mock/path', href: 'file:///C:/foo/bar', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/C:/foo/bar', search: '', hash: '', }, { input: '//C|/foo/bar', base: 'file:///tmp/mock/path', href: 'file:///C:/foo/bar', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/C:/foo/bar', search: '', hash: '', }, { input: '//server/file', base: 'file:///tmp/mock/path', href: 'file://server/file', protocol: 'file:', username: '', password: '', host: 'server', hostname: 'server', port: '', pathname: '/file', search: '', hash: '', }, { input: '\\\\server\\file', base: 'file:///tmp/mock/path', href: 'file://server/file', protocol: 'file:', username: '', password: '', host: 'server', hostname: 'server', port: '', pathname: '/file', search: '', hash: '', }, { input: '/\\server/file', base: 'file:///tmp/mock/path', href: 'file://server/file', protocol: 'file:', username: '', password: '', host: 'server', hostname: 'server', port: '', pathname: '/file', search: '', hash: '', }, { input: 'file:///foo/bar.txt', base: 'file:///tmp/mock/path', href: 'file:///foo/bar.txt', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/foo/bar.txt', search: '', hash: '', }, { input: 'file:///home/me', base: 'file:///tmp/mock/path', href: 'file:///home/me', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/home/me', search: '', hash: '', }, { input: '//', base: 'file:///tmp/mock/path', href: 'file:///', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/', search: '', hash: '', }, { input: '///', base: 'file:///tmp/mock/path', href: 'file:///', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/', search: '', hash: '', }, { input: '///test', base: 'file:///tmp/mock/path', href: 'file:///test', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/test', search: '', hash: '', }, { input: 'file://test', base: 'file:///tmp/mock/path', href: 'file://test/', protocol: 'file:', username: '', password: '', host: 'test', hostname: 'test', port: '', pathname: '/', search: '', hash: '', }, { input: 'file://localhost', base: 'file:///tmp/mock/path', href: 'file:///', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/', search: '', hash: '', }, { input: 'file://localhost/', base: 'file:///tmp/mock/path', href: 'file:///', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/', search: '', hash: '', }, { input: 'file://localhost/test', base: 'file:///tmp/mock/path', href: 'file:///test', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/test', search: '', hash: '', }, { input: 'test', base: 'file:///tmp/mock/path', href: 'file:///tmp/mock/test', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/tmp/mock/test', search: '', hash: '', }, { input: 'file:test', base: 'file:///tmp/mock/path', href: 'file:///tmp/mock/test', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/tmp/mock/test', search: '', hash: '', }, '# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/script-tests/path.js', { input: 'http://example.com/././foo', base: 'about:blank', href: 'http://example.com/foo', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/foo', search: '', hash: '', }, { input: 'http://example.com/./.foo', base: 'about:blank', href: 'http://example.com/.foo', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/.foo', search: '', hash: '', }, { input: 'http://example.com/foo/.', base: 'about:blank', href: 'http://example.com/foo/', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/foo/', search: '', hash: '', }, { input: 'http://example.com/foo/./', base: 'about:blank', href: 'http://example.com/foo/', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/foo/', search: '', hash: '', }, { input: 'http://example.com/foo/bar/..', base: 'about:blank', href: 'http://example.com/foo/', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/foo/', search: '', hash: '', }, { input: 'http://example.com/foo/bar/../', base: 'about:blank', href: 'http://example.com/foo/', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/foo/', search: '', hash: '', }, { input: 'http://example.com/foo/..bar', base: 'about:blank', href: 'http://example.com/foo/..bar', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/foo/..bar', search: '', hash: '', }, { input: 'http://example.com/foo/bar/../ton', base: 'about:blank', href: 'http://example.com/foo/ton', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/foo/ton', search: '', hash: '', }, { input: 'http://example.com/foo/bar/../ton/../../a', base: 'about:blank', href: 'http://example.com/a', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/a', search: '', hash: '', }, { input: 'http://example.com/foo/../../..', base: 'about:blank', href: 'http://example.com/', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'http://example.com/foo/../../../ton', base: 'about:blank', href: 'http://example.com/ton', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/ton', search: '', hash: '', }, { input: 'http://example.com/foo/%2e', base: 'about:blank', href: 'http://example.com/foo/', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/foo/', search: '', hash: '', }, { input: 'http://example.com/foo/%2e%2', base: 'about:blank', href: 'http://example.com/foo/%2e%2', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/foo/%2e%2', search: '', hash: '', }, { input: 'http://example.com/foo/%2e./%2e%2e/.%2e/%2e.bar', base: 'about:blank', href: 'http://example.com/%2e.bar', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/%2e.bar', search: '', hash: '', }, { input: 'http://example.com////../..', base: 'about:blank', href: 'http://example.com//', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '//', search: '', hash: '', }, { input: 'http://example.com/foo/bar//../..', base: 'about:blank', href: 'http://example.com/foo/', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/foo/', search: '', hash: '', }, { input: 'http://example.com/foo/bar//..', base: 'about:blank', href: 'http://example.com/foo/bar/', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/foo/bar/', search: '', hash: '', }, { input: 'http://example.com/foo', base: 'about:blank', href: 'http://example.com/foo', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/foo', search: '', hash: '', }, { input: 'http://example.com/%20foo', base: 'about:blank', href: 'http://example.com/%20foo', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/%20foo', search: '', hash: '', }, { input: 'http://example.com/foo%', base: 'about:blank', href: 'http://example.com/foo%', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/foo%', search: '', hash: '', }, { input: 'http://example.com/foo%2', base: 'about:blank', href: 'http://example.com/foo%2', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/foo%2', search: '', hash: '', }, { input: 'http://example.com/foo%2zbar', base: 'about:blank', href: 'http://example.com/foo%2zbar', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/foo%2zbar', search: '', hash: '', }, { input: 'http://example.com/foo%2©zbar', base: 'about:blank', href: 'http://example.com/foo%2%C3%82%C2%A9zbar', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/foo%2%C3%82%C2%A9zbar', search: '', hash: '', }, { input: 'http://example.com/foo%41%7a', base: 'about:blank', href: 'http://example.com/foo%41%7a', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/foo%41%7a', search: '', hash: '', }, { input: 'http://example.com/foo\t\u0091%91', base: 'about:blank', href: 'http://example.com/foo%C2%91%91', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/foo%C2%91%91', search: '', hash: '', }, { input: 'http://example.com/foo%00%51', base: 'about:blank', href: 'http://example.com/foo%00%51', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/foo%00%51', search: '', hash: '', }, { input: 'http://example.com/(%28:%3A%29)', base: 'about:blank', href: 'http://example.com/(%28:%3A%29)', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/(%28:%3A%29)', search: '', hash: '', }, { input: 'http://example.com/%3A%3a%3C%3c', base: 'about:blank', href: 'http://example.com/%3A%3a%3C%3c', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/%3A%3a%3C%3c', search: '', hash: '', }, { input: 'http://example.com/foo\tbar', base: 'about:blank', href: 'http://example.com/foobar', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/foobar', search: '', hash: '', }, { input: 'http://example.com\\\\foo\\\\bar', base: 'about:blank', href: 'http://example.com//foo//bar', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '//foo//bar', search: '', hash: '', }, { input: 'http://example.com/%7Ffp3%3Eju%3Dduvgw%3Dd', base: 'about:blank', href: 'http://example.com/%7Ffp3%3Eju%3Dduvgw%3Dd', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/%7Ffp3%3Eju%3Dduvgw%3Dd', search: '', hash: '', }, { input: 'http://example.com/@asdf%40', base: 'about:blank', href: 'http://example.com/@asdf%40', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/@asdf%40', search: '', hash: '', }, { input: 'http://example.com/你好你好', base: 'about:blank', href: 'http://example.com/%E4%BD%A0%E5%A5%BD%E4%BD%A0%E5%A5%BD', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/%E4%BD%A0%E5%A5%BD%E4%BD%A0%E5%A5%BD', search: '', hash: '', }, { input: 'http://example.com/‥/foo', base: 'about:blank', href: 'http://example.com/%E2%80%A5/foo', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/%E2%80%A5/foo', search: '', hash: '', }, { input: 'http://example.com//foo', base: 'about:blank', href: 'http://example.com/%EF%BB%BF/foo', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/%EF%BB%BF/foo', search: '', hash: '', }, { input: 'http://example.com/‮/foo/‭/bar', base: 'about:blank', href: 'http://example.com/%E2%80%AE/foo/%E2%80%AD/bar', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/%E2%80%AE/foo/%E2%80%AD/bar', search: '', hash: '', }, '# 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', href: 'http://www.google.com/foo?bar=baz#', origin: 'http://www.google.com', protocol: 'http:', username: '', password: '', host: 'www.google.com', hostname: 'www.google.com', port: '', pathname: '/foo', search: '?bar=baz', hash: '', }, { input: 'http://www.google.com/foo?bar=baz# »', base: 'about:blank', href: 'http://www.google.com/foo?bar=baz#%20%C2%BB', origin: 'http://www.google.com', protocol: 'http:', username: '', password: '', host: 'www.google.com', hostname: 'www.google.com', port: '', pathname: '/foo', search: '?bar=baz', hash: '#%20%C2%BB', }, { input: 'data:test# »', base: 'about:blank', href: 'data:test#%20%C2%BB', origin: 'null', protocol: 'data:', username: '', password: '', host: '', hostname: '', port: '', pathname: 'test', search: '', hash: '#%20%C2%BB', }, { input: 'http://www.google.com', base: 'about:blank', href: 'http://www.google.com/', origin: 'http://www.google.com', protocol: 'http:', username: '', password: '', host: 'www.google.com', hostname: 'www.google.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'http://192.0x00A80001', base: 'about:blank', href: 'http://192.168.0.1/', origin: 'http://192.168.0.1', protocol: 'http:', username: '', password: '', host: '192.168.0.1', hostname: '192.168.0.1', port: '', pathname: '/', search: '', hash: '', }, { input: 'http://www/foo%2Ehtml', base: 'about:blank', href: 'http://www/foo%2Ehtml', origin: 'http://www', protocol: 'http:', username: '', password: '', host: 'www', hostname: 'www', port: '', pathname: '/foo%2Ehtml', search: '', hash: '', }, { input: 'http://www/foo/%2E/html', base: 'about:blank', href: 'http://www/foo/html', origin: 'http://www', protocol: 'http:', username: '', password: '', host: 'www', hostname: 'www', port: '', pathname: '/foo/html', search: '', hash: '', }, { input: 'http://user:pass@/', base: 'about:blank', failure: true, }, { input: 'http://%25DOMAIN:foobar@foodomain.com/', base: 'about:blank', href: 'http://%25DOMAIN:foobar@foodomain.com/', origin: 'http://foodomain.com', protocol: 'http:', username: '%25DOMAIN', password: 'foobar', host: 'foodomain.com', hostname: 'foodomain.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'http:\\\\www.google.com\\foo', base: 'about:blank', href: 'http://www.google.com/foo', origin: 'http://www.google.com', protocol: 'http:', username: '', password: '', host: 'www.google.com', hostname: 'www.google.com', port: '', pathname: '/foo', search: '', hash: '', }, { input: 'http://foo:80/', base: 'about:blank', href: 'http://foo/', origin: 'http://foo', protocol: 'http:', username: '', password: '', host: 'foo', hostname: 'foo', port: '', pathname: '/', search: '', hash: '', }, { input: 'http://foo:81/', base: 'about:blank', href: 'http://foo:81/', origin: 'http://foo:81', protocol: 'http:', username: '', password: '', host: 'foo:81', hostname: 'foo', port: '81', pathname: '/', search: '', hash: '', }, { input: 'httpa://foo:80/', base: 'about:blank', href: 'httpa://foo:80/', origin: 'null', protocol: 'httpa:', username: '', password: '', host: 'foo:80', hostname: 'foo', port: '80', pathname: '/', search: '', hash: '', }, { input: 'http://foo:-80/', base: 'about:blank', failure: true, }, { input: 'https://foo:443/', base: 'about:blank', href: 'https://foo/', origin: 'https://foo', protocol: 'https:', username: '', password: '', host: 'foo', hostname: 'foo', port: '', pathname: '/', search: '', hash: '', }, { input: 'https://foo:80/', base: 'about:blank', href: 'https://foo:80/', origin: 'https://foo:80', protocol: 'https:', username: '', password: '', host: 'foo:80', hostname: 'foo', port: '80', pathname: '/', search: '', hash: '', }, { input: 'ftp://foo:21/', base: 'about:blank', href: 'ftp://foo/', origin: 'ftp://foo', protocol: 'ftp:', username: '', password: '', host: 'foo', hostname: 'foo', port: '', pathname: '/', search: '', hash: '', }, { input: 'ftp://foo:80/', base: 'about:blank', href: 'ftp://foo:80/', origin: 'ftp://foo:80', protocol: 'ftp:', username: '', password: '', host: 'foo:80', hostname: 'foo', port: '80', pathname: '/', search: '', hash: '', }, { input: 'gopher://foo:70/', base: 'about:blank', href: 'gopher://foo:70/', protocol: 'gopher:', username: '', password: '', host: 'foo:70', hostname: 'foo', port: '70', pathname: '/', search: '', hash: '', }, { input: 'gopher://foo:443/', base: 'about:blank', href: 'gopher://foo:443/', protocol: 'gopher:', username: '', password: '', host: 'foo:443', hostname: 'foo', port: '443', pathname: '/', search: '', hash: '', }, { input: 'ws://foo:80/', base: 'about:blank', href: 'ws://foo/', origin: 'ws://foo', protocol: 'ws:', username: '', password: '', host: 'foo', hostname: 'foo', port: '', pathname: '/', search: '', hash: '', }, { input: 'ws://foo:81/', base: 'about:blank', href: 'ws://foo:81/', origin: 'ws://foo:81', protocol: 'ws:', username: '', password: '', host: 'foo:81', hostname: 'foo', port: '81', pathname: '/', search: '', hash: '', }, { input: 'ws://foo:443/', base: 'about:blank', href: 'ws://foo:443/', origin: 'ws://foo:443', protocol: 'ws:', username: '', password: '', host: 'foo:443', hostname: 'foo', port: '443', pathname: '/', search: '', hash: '', }, { input: 'ws://foo:815/', base: 'about:blank', href: 'ws://foo:815/', origin: 'ws://foo:815', protocol: 'ws:', username: '', password: '', host: 'foo:815', hostname: 'foo', port: '815', pathname: '/', search: '', hash: '', }, { input: 'wss://foo:80/', base: 'about:blank', href: 'wss://foo:80/', origin: 'wss://foo:80', protocol: 'wss:', username: '', password: '', host: 'foo:80', hostname: 'foo', port: '80', pathname: '/', search: '', hash: '', }, { input: 'wss://foo:81/', base: 'about:blank', href: 'wss://foo:81/', origin: 'wss://foo:81', protocol: 'wss:', username: '', password: '', host: 'foo:81', hostname: 'foo', port: '81', pathname: '/', search: '', hash: '', }, { input: 'wss://foo:443/', base: 'about:blank', href: 'wss://foo/', origin: 'wss://foo', protocol: 'wss:', username: '', password: '', host: 'foo', hostname: 'foo', port: '', pathname: '/', search: '', hash: '', }, { input: 'wss://foo:815/', base: 'about:blank', href: 'wss://foo:815/', origin: 'wss://foo:815', protocol: 'wss:', username: '', password: '', host: 'foo:815', hostname: 'foo', port: '815', pathname: '/', search: '', hash: '', }, { input: 'http:/example.com/', base: 'about:blank', href: 'http://example.com/', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'ftp:/example.com/', base: 'about:blank', href: 'ftp://example.com/', origin: 'ftp://example.com', protocol: 'ftp:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'https:/example.com/', base: 'about:blank', href: 'https://example.com/', origin: 'https://example.com', protocol: 'https:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'madeupscheme:/example.com/', base: 'about:blank', href: 'madeupscheme:/example.com/', origin: 'null', protocol: 'madeupscheme:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/example.com/', search: '', hash: '', }, { input: 'file:/example.com/', base: 'about:blank', href: 'file:///example.com/', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/example.com/', search: '', hash: '', }, { input: 'ftps:/example.com/', base: 'about:blank', href: 'ftps:/example.com/', origin: 'null', protocol: 'ftps:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/example.com/', search: '', hash: '', }, { input: 'gopher:/example.com/', base: 'about:blank', href: 'gopher:/example.com/', protocol: 'gopher:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/example.com/', search: '', hash: '', }, { input: 'ws:/example.com/', base: 'about:blank', href: 'ws://example.com/', origin: 'ws://example.com', protocol: 'ws:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'wss:/example.com/', base: 'about:blank', href: 'wss://example.com/', origin: 'wss://example.com', protocol: 'wss:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'data:/example.com/', base: 'about:blank', href: 'data:/example.com/', origin: 'null', protocol: 'data:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/example.com/', search: '', hash: '', }, { input: 'javascript:/example.com/', base: 'about:blank', href: 'javascript:/example.com/', origin: 'null', protocol: 'javascript:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/example.com/', search: '', hash: '', }, { input: 'mailto:/example.com/', base: 'about:blank', href: 'mailto:/example.com/', origin: 'null', protocol: 'mailto:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/example.com/', search: '', hash: '', }, { input: 'http:example.com/', base: 'about:blank', href: 'http://example.com/', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'ftp:example.com/', base: 'about:blank', href: 'ftp://example.com/', origin: 'ftp://example.com', protocol: 'ftp:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'https:example.com/', base: 'about:blank', href: 'https://example.com/', origin: 'https://example.com', protocol: 'https:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'madeupscheme:example.com/', base: 'about:blank', href: 'madeupscheme:example.com/', origin: 'null', protocol: 'madeupscheme:', username: '', password: '', host: '', hostname: '', port: '', pathname: 'example.com/', search: '', hash: '', }, { input: 'ftps:example.com/', base: 'about:blank', href: 'ftps:example.com/', origin: 'null', protocol: 'ftps:', username: '', password: '', host: '', hostname: '', port: '', pathname: 'example.com/', search: '', hash: '', }, { input: 'gopher:example.com/', base: 'about:blank', href: 'gopher:example.com/', protocol: 'gopher:', username: '', password: '', host: '', hostname: '', port: '', pathname: 'example.com/', search: '', hash: '', }, { input: 'ws:example.com/', base: 'about:blank', href: 'ws://example.com/', origin: 'ws://example.com', protocol: 'ws:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'wss:example.com/', base: 'about:blank', href: 'wss://example.com/', origin: 'wss://example.com', protocol: 'wss:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'data:example.com/', base: 'about:blank', href: 'data:example.com/', origin: 'null', protocol: 'data:', username: '', password: '', host: '', hostname: '', port: '', pathname: 'example.com/', search: '', hash: '', }, { input: 'javascript:example.com/', base: 'about:blank', href: 'javascript:example.com/', origin: 'null', protocol: 'javascript:', username: '', password: '', host: '', hostname: '', port: '', pathname: 'example.com/', search: '', hash: '', }, { input: 'mailto:example.com/', base: 'about:blank', href: 'mailto:example.com/', origin: 'null', protocol: 'mailto:', username: '', password: '', host: '', hostname: '', port: '', pathname: 'example.com/', search: '', hash: '', }, '# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/segments-userinfo-vs-host.html', { input: 'http:@www.example.com', base: 'about:blank', href: 'http://www.example.com/', origin: 'http://www.example.com', protocol: 'http:', username: '', password: '', host: 'www.example.com', hostname: 'www.example.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'http:/@www.example.com', base: 'about:blank', href: 'http://www.example.com/', origin: 'http://www.example.com', protocol: 'http:', username: '', password: '', host: 'www.example.com', hostname: 'www.example.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'http://@www.example.com', base: 'about:blank', href: 'http://www.example.com/', origin: 'http://www.example.com', protocol: 'http:', username: '', password: '', host: 'www.example.com', hostname: 'www.example.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'http:a:b@www.example.com', base: 'about:blank', href: 'http://a:b@www.example.com/', origin: 'http://www.example.com', protocol: 'http:', username: 'a', password: 'b', host: 'www.example.com', hostname: 'www.example.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'http:/a:b@www.example.com', base: 'about:blank', href: 'http://a:b@www.example.com/', origin: 'http://www.example.com', protocol: 'http:', username: 'a', password: 'b', host: 'www.example.com', hostname: 'www.example.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'http://a:b@www.example.com', base: 'about:blank', href: 'http://a:b@www.example.com/', origin: 'http://www.example.com', protocol: 'http:', username: 'a', password: 'b', host: 'www.example.com', hostname: 'www.example.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'http://@pple.com', base: 'about:blank', href: 'http://pple.com/', origin: 'http://pple.com', protocol: 'http:', username: '', password: '', host: 'pple.com', hostname: 'pple.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'http::b@www.example.com', base: 'about:blank', href: 'http://:b@www.example.com/', origin: 'http://www.example.com', protocol: 'http:', username: '', password: 'b', host: 'www.example.com', hostname: 'www.example.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'http:/:b@www.example.com', base: 'about:blank', href: 'http://:b@www.example.com/', origin: 'http://www.example.com', protocol: 'http:', username: '', password: 'b', host: 'www.example.com', hostname: 'www.example.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'http://:b@www.example.com', base: 'about:blank', href: 'http://:b@www.example.com/', origin: 'http://www.example.com', protocol: 'http:', username: '', password: 'b', host: 'www.example.com', hostname: 'www.example.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'http:/:@/www.example.com', base: 'about:blank', failure: true, }, { input: 'http://user@/www.example.com', base: 'about:blank', failure: true, }, { input: 'http:@/www.example.com', base: 'about:blank', failure: true, }, { input: 'http:/@/www.example.com', base: 'about:blank', failure: true, }, { input: 'http://@/www.example.com', base: 'about:blank', failure: true, }, { input: 'https:@/www.example.com', base: 'about:blank', failure: true, }, { input: 'http:a:b@/www.example.com', base: 'about:blank', failure: true, }, { input: 'http:/a:b@/www.example.com', base: 'about:blank', failure: true, }, { input: 'http://a:b@/www.example.com', base: 'about:blank', failure: true, }, { input: 'http::@/www.example.com', base: 'about:blank', failure: true, }, { input: 'http:a:@www.example.com', base: 'about:blank', href: 'http://a@www.example.com/', origin: 'http://www.example.com', protocol: 'http:', username: 'a', password: '', host: 'www.example.com', hostname: 'www.example.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'http:/a:@www.example.com', base: 'about:blank', href: 'http://a@www.example.com/', origin: 'http://www.example.com', protocol: 'http:', username: 'a', password: '', host: 'www.example.com', hostname: 'www.example.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'http://a:@www.example.com', base: 'about:blank', href: 'http://a@www.example.com/', origin: 'http://www.example.com', protocol: 'http:', username: 'a', password: '', host: 'www.example.com', hostname: 'www.example.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'http://www.@pple.com', base: 'about:blank', href: 'http://www.@pple.com/', origin: 'http://pple.com', protocol: 'http:', username: 'www.', password: '', host: 'pple.com', hostname: 'pple.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'http:@:www.example.com', base: 'about:blank', failure: true, }, { input: 'http:/@:www.example.com', base: 'about:blank', failure: true, }, { input: 'http://@:www.example.com', base: 'about:blank', failure: true, }, { input: 'http://:@www.example.com', base: 'about:blank', href: 'http://www.example.com/', origin: 'http://www.example.com', protocol: 'http:', username: '', password: '', host: 'www.example.com', hostname: 'www.example.com', port: '', pathname: '/', search: '', hash: '', }, '# Others', { input: '/', base: 'http://www.example.com/test', href: 'http://www.example.com/', origin: 'http://www.example.com', protocol: 'http:', username: '', password: '', host: 'www.example.com', hostname: 'www.example.com', port: '', pathname: '/', search: '', hash: '', }, { input: '/test.txt', base: 'http://www.example.com/test', href: 'http://www.example.com/test.txt', origin: 'http://www.example.com', protocol: 'http:', username: '', password: '', host: 'www.example.com', hostname: 'www.example.com', port: '', pathname: '/test.txt', search: '', hash: '', }, { input: '.', base: 'http://www.example.com/test', href: 'http://www.example.com/', origin: 'http://www.example.com', protocol: 'http:', username: '', password: '', host: 'www.example.com', hostname: 'www.example.com', port: '', pathname: '/', search: '', hash: '', }, { input: '..', base: 'http://www.example.com/test', href: 'http://www.example.com/', origin: 'http://www.example.com', protocol: 'http:', username: '', password: '', host: 'www.example.com', hostname: 'www.example.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'test.txt', base: 'http://www.example.com/test', href: 'http://www.example.com/test.txt', origin: 'http://www.example.com', protocol: 'http:', username: '', password: '', host: 'www.example.com', hostname: 'www.example.com', port: '', pathname: '/test.txt', search: '', hash: '', }, { input: './test.txt', base: 'http://www.example.com/test', href: 'http://www.example.com/test.txt', origin: 'http://www.example.com', protocol: 'http:', username: '', password: '', host: 'www.example.com', hostname: 'www.example.com', port: '', pathname: '/test.txt', search: '', hash: '', }, { input: '../test.txt', base: 'http://www.example.com/test', href: 'http://www.example.com/test.txt', origin: 'http://www.example.com', protocol: 'http:', username: '', password: '', host: 'www.example.com', hostname: 'www.example.com', port: '', pathname: '/test.txt', search: '', hash: '', }, { input: '../aaa/test.txt', base: 'http://www.example.com/test', href: 'http://www.example.com/aaa/test.txt', origin: 'http://www.example.com', protocol: 'http:', username: '', password: '', host: 'www.example.com', hostname: 'www.example.com', port: '', pathname: '/aaa/test.txt', search: '', hash: '', }, { input: '../../test.txt', base: 'http://www.example.com/test', href: 'http://www.example.com/test.txt', origin: 'http://www.example.com', protocol: 'http:', username: '', password: '', host: 'www.example.com', hostname: 'www.example.com', port: '', pathname: '/test.txt', search: '', hash: '', }, { input: '中/test.txt', base: 'http://www.example.com/test', href: 'http://www.example.com/%E4%B8%AD/test.txt', origin: 'http://www.example.com', protocol: 'http:', username: '', password: '', host: 'www.example.com', hostname: 'www.example.com', port: '', pathname: '/%E4%B8%AD/test.txt', search: '', hash: '', }, { input: 'http://www.example2.com', base: 'http://www.example.com/test', href: 'http://www.example2.com/', origin: 'http://www.example2.com', protocol: 'http:', username: '', password: '', host: 'www.example2.com', hostname: 'www.example2.com', port: '', pathname: '/', search: '', hash: '', }, { input: '//www.example2.com', base: 'http://www.example.com/test', href: 'http://www.example2.com/', origin: 'http://www.example2.com', protocol: 'http:', username: '', password: '', host: 'www.example2.com', hostname: 'www.example2.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'file:...', base: 'http://www.example.com/test', href: 'file:///...', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/...', search: '', hash: '', }, { input: 'file:..', base: 'http://www.example.com/test', href: 'file:///', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/', search: '', hash: '', }, { input: 'file:a', base: 'http://www.example.com/test', href: 'file:///a', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/a', search: '', hash: '', }, '# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/host.html', 'Basic canonicalization, uppercase should be converted to lowercase', { input: 'http://ExAmPlE.CoM', base: 'http://other.com/', href: 'http://example.com/', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'http://example example.com', base: 'http://other.com/', failure: true, }, { input: 'http://Goo%20 goo%7C|.com', base: 'http://other.com/', failure: true, }, { input: 'http://[]', base: 'http://other.com/', failure: true, }, { input: 'http://[:]', base: 'http://other.com/', failure: true, }, 'U+3000 is mapped to U+0020 (space) which is disallowed', { input: 'http://GOO\u00a0\u3000goo.com', base: 'http://other.com/', failure: true, }, 'Other types of space (no-break, zero-width, zero-width-no-break) are name-prepped away to nothing. U+200B, U+2060, and U+FEFF, are ignored', { input: 'http://GOO\u200b\u2060\ufeffgoo.com', base: 'http://other.com/', href: 'http://googoo.com/', origin: 'http://googoo.com', protocol: 'http:', username: '', password: '', host: 'googoo.com', hostname: 'googoo.com', port: '', pathname: '/', search: '', hash: '', }, 'Leading and trailing C0 control or space', { input: '\u0000\u001b\u0004\u0012 http://example.com/\u001f \u000d ', base: 'about:blank', href: 'http://example.com/', origin: 'http://example.com', protocol: 'http:', username: '', password: '', host: 'example.com', hostname: 'example.com', port: '', pathname: '/', search: '', hash: '', }, 'Ideographic full stop (full-width period for Chinese, etc.) should be treated as a dot. U+3002 is mapped to U+002E (dot)', { input: 'http://www.foo。bar.com', base: 'http://other.com/', href: 'http://www.foo.bar.com/', origin: 'http://www.foo.bar.com', protocol: 'http:', username: '', password: '', host: 'www.foo.bar.com', hostname: 'www.foo.bar.com', port: '', pathname: '/', search: '', hash: '', }, 'Invalid Unicode characters should fail... U+FDD0 is disallowed; %ef%b7%90 is U+FDD0', { input: 'http://\ufdd0zyx.com', base: 'http://other.com/', failure: true, }, 'This is the same as previous but escaped', { input: 'http://%ef%b7%90zyx.com', base: 'http://other.com/', failure: true, }, 'U+FFFD', { input: 'https://\ufffd', base: 'about:blank', failure: true, }, { input: 'https://%EF%BF%BD', base: 'about:blank', failure: true, }, { input: 'https://x/\ufffd?\ufffd#\ufffd', base: 'about:blank', href: 'https://x/%EF%BF%BD?%EF%BF%BD#%EF%BF%BD', origin: 'https://x', protocol: 'https:', username: '', password: '', host: 'x', hostname: 'x', port: '', pathname: '/%EF%BF%BD', search: '?%EF%BF%BD', hash: '#%EF%BF%BD', }, "Test name prepping, fullwidth input should be converted to ASCII and NOT IDN-ized. This is 'Go' in fullwidth UTF-8/UTF-16.", { input: 'http://Go.com', base: 'http://other.com/', href: 'http://go.com/', origin: 'http://go.com', protocol: 'http:', username: '', password: '', host: 'go.com', hostname: 'go.com', port: '', pathname: '/', search: '', hash: '', }, 'URL spec forbids the following. https://www.w3.org/Bugs/Public/show_bug.cgi?id=24257', { input: 'http://%41.com', base: 'http://other.com/', failure: true, }, { input: 'http://%ef%bc%85%ef%bc%94%ef%bc%91.com', base: 'http://other.com/', failure: true, }, '...%00 in fullwidth should fail (also as escaped UTF-8 input)', { input: 'http://%00.com', base: 'http://other.com/', failure: true, }, { input: 'http://%ef%bc%85%ef%bc%90%ef%bc%90.com', base: 'http://other.com/', failure: true, }, 'Basic IDN support, UTF-8 and UTF-16 input should be converted to IDN', { input: 'http://你好你好', base: 'http://other.com/', href: 'http://xn--6qqa088eba/', origin: 'http://xn--6qqa088eba', protocol: 'http:', username: '', password: '', host: 'xn--6qqa088eba', hostname: 'xn--6qqa088eba', port: '', pathname: '/', search: '', hash: '', }, { input: 'https://faß.ExAmPlE/', base: 'about:blank', href: 'https://xn--fa-hia.example/', origin: 'https://xn--fa-hia.example', protocol: 'https:', username: '', password: '', host: 'xn--fa-hia.example', hostname: 'xn--fa-hia.example', port: '', pathname: '/', search: '', hash: '', }, { input: 'sc://faß.ExAmPlE/', base: 'about:blank', href: 'sc://fa%C3%9F.ExAmPlE/', origin: 'null', protocol: 'sc:', username: '', password: '', host: 'fa%C3%9F.ExAmPlE', hostname: 'fa%C3%9F.ExAmPlE', port: '', pathname: '/', search: '', hash: '', }, 'Invalid escaped characters should fail and the percents should be escaped. https://www.w3.org/Bugs/Public/show_bug.cgi?id=24191', { input: 'http://%zz%66%a.com', base: 'http://other.com/', failure: true, }, 'If we get an invalid character that has been escaped.', { input: 'http://%25', base: 'http://other.com/', failure: true, }, { input: 'http://hello%00', base: 'http://other.com/', failure: true, }, 'Escaped numbers should be treated like IP addresses if they are.', { input: 'http://%30%78%63%30%2e%30%32%35%30.01', base: 'http://other.com/', href: 'http://192.168.0.1/', origin: 'http://192.168.0.1', protocol: 'http:', username: '', password: '', host: '192.168.0.1', hostname: '192.168.0.1', port: '', pathname: '/', search: '', hash: '', }, { input: 'http://%30%78%63%30%2e%30%32%35%30.01%2e', base: 'http://other.com/', href: 'http://192.168.0.1/', origin: 'http://192.168.0.1', protocol: 'http:', username: '', password: '', host: '192.168.0.1', hostname: '192.168.0.1', port: '', pathname: '/', search: '', hash: '', }, { input: 'http://192.168.0.257', base: 'http://other.com/', failure: true, }, 'Invalid escaping in hosts causes failure', { input: 'http://%3g%78%63%30%2e%30%32%35%30%2E.01', base: 'http://other.com/', failure: true, }, 'A space in a host causes failure', { input: 'http://192.168.0.1 hello', base: 'http://other.com/', failure: true, }, { input: 'https://x x:12', base: 'about:blank', failure: true, }, 'Fullwidth and escaped UTF-8 fullwidth should still be treated as IP', { input: 'http://0Xc0.0250.01', base: 'http://other.com/', href: 'http://192.168.0.1/', origin: 'http://192.168.0.1', protocol: 'http:', username: '', password: '', host: '192.168.0.1', hostname: '192.168.0.1', port: '', pathname: '/', search: '', hash: '', }, 'Domains with empty labels', { input: 'http://./', base: 'about:blank', href: 'http://./', origin: 'http://.', protocol: 'http:', username: '', password: '', host: '.', hostname: '.', port: '', pathname: '/', search: '', hash: '', }, { input: 'http://../', base: 'about:blank', href: 'http://../', origin: 'http://..', protocol: 'http:', username: '', password: '', host: '..', hostname: '..', port: '', pathname: '/', search: '', hash: '', }, 'Broken IPv6', { input: 'http://[www.google.com]/', base: 'about:blank', failure: true, }, { input: 'http://[google.com]', base: 'http://other.com/', failure: true, }, { input: 'http://[::1.2.3.4x]', base: 'http://other.com/', failure: true, }, { input: 'http://[::1.2.3.]', base: 'http://other.com/', failure: true, }, { input: 'http://[::1.2.]', base: 'http://other.com/', failure: true, }, { input: 'http://[::1.]', base: 'http://other.com/', failure: true, }, 'Misc Unicode', { input: 'http://foo:💩@example.com/bar', base: 'http://other.com/', href: 'http://foo:%F0%9F%92%A9@example.com/bar', origin: 'http://example.com', protocol: 'http:', username: 'foo', password: '%F0%9F%92%A9', host: 'example.com', hostname: 'example.com', port: '', pathname: '/bar', search: '', hash: '', }, '# resolving a fragment against any scheme succeeds', { input: '#', base: 'test:test', href: 'test:test#', origin: 'null', protocol: 'test:', username: '', password: '', host: '', hostname: '', port: '', pathname: 'test', search: '', hash: '', }, { input: '#x', base: 'mailto:x@x.com', href: 'mailto:x@x.com#x', origin: 'null', protocol: 'mailto:', username: '', password: '', host: '', hostname: '', port: '', pathname: 'x@x.com', search: '', hash: '#x', }, { input: '#x', base: 'data:,', href: 'data:,#x', origin: 'null', protocol: 'data:', username: '', password: '', host: '', hostname: '', port: '', pathname: ',', search: '', hash: '#x', }, { input: '#x', base: 'about:blank', href: 'about:blank#x', origin: 'null', protocol: 'about:', username: '', password: '', host: '', hostname: '', port: '', pathname: 'blank', search: '', hash: '#x', }, { input: '#', base: 'test:test?test', href: 'test:test?test#', origin: 'null', protocol: 'test:', username: '', password: '', host: '', hostname: '', port: '', pathname: 'test', search: '?test', hash: '', }, '# multiple @ in authority state', { input: 'https://@test@test@example:800/', base: 'http://doesnotmatter/', href: 'https://%40test%40test@example:800/', origin: 'https://example:800', protocol: 'https:', username: '%40test%40test', password: '', host: 'example:800', hostname: 'example', port: '800', pathname: '/', search: '', hash: '', }, { input: 'https://@@@example', base: 'http://doesnotmatter/', href: 'https://%40%40@example/', origin: 'https://example', protocol: 'https:', username: '%40%40', password: '', host: 'example', hostname: 'example', port: '', pathname: '/', search: '', hash: '', }, 'non-az-09 characters', { input: 'http://`{}:`{}@h/`{}?`{}', base: 'http://doesnotmatter/', href: 'http://%60%7B%7D:%60%7B%7D@h/%60%7B%7D?`{}', origin: 'http://h', protocol: 'http:', username: '%60%7B%7D', password: '%60%7B%7D', host: 'h', hostname: 'h', port: '', pathname: '/%60%7B%7D', search: '?`{}', hash: '', }, '# Credentials in base', { input: '/some/path', base: 'http://user@example.org/smth', href: 'http://user@example.org/some/path', origin: 'http://example.org', protocol: 'http:', username: 'user', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/some/path', search: '', hash: '', }, { input: '', base: 'http://user:pass@example.org:21/smth', href: 'http://user:pass@example.org:21/smth', origin: 'http://example.org:21', protocol: 'http:', username: 'user', password: 'pass', host: 'example.org:21', hostname: 'example.org', port: '21', pathname: '/smth', search: '', hash: '', }, { input: '/some/path', base: 'http://user:pass@example.org:21/smth', href: 'http://user:pass@example.org:21/some/path', origin: 'http://example.org:21', protocol: 'http:', username: 'user', password: 'pass', host: 'example.org:21', hostname: 'example.org', port: '21', pathname: '/some/path', search: '', hash: '', }, '# a set of tests designed by zcorpan for relative URLs with unknown schemes', { input: 'i', base: 'sc:sd', failure: true, }, { input: 'i', base: 'sc:sd/sd', failure: true, }, { input: 'i', base: 'sc:/pa/pa', href: 'sc:/pa/i', origin: 'null', protocol: 'sc:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/pa/i', search: '', hash: '', }, { input: 'i', base: 'sc://ho/pa', href: 'sc://ho/i', origin: 'null', protocol: 'sc:', username: '', password: '', host: 'ho', hostname: 'ho', port: '', pathname: '/i', search: '', hash: '', }, { input: 'i', base: 'sc:///pa/pa', href: 'sc:///pa/i', origin: 'null', protocol: 'sc:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/pa/i', search: '', hash: '', }, { input: '../i', base: 'sc:sd', failure: true, }, { input: '../i', base: 'sc:sd/sd', failure: true, }, { input: '../i', base: 'sc:/pa/pa', href: 'sc:/i', origin: 'null', protocol: 'sc:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/i', search: '', hash: '', }, { input: '../i', base: 'sc://ho/pa', href: 'sc://ho/i', origin: 'null', protocol: 'sc:', username: '', password: '', host: 'ho', hostname: 'ho', port: '', pathname: '/i', search: '', hash: '', }, { input: '../i', base: 'sc:///pa/pa', href: 'sc:///i', origin: 'null', protocol: 'sc:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/i', search: '', hash: '', }, { input: '/i', base: 'sc:sd', failure: true, }, { input: '/i', base: 'sc:sd/sd', failure: true, }, { input: '/i', base: 'sc:/pa/pa', href: 'sc:/i', origin: 'null', protocol: 'sc:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/i', search: '', hash: '', }, { input: '/i', base: 'sc://ho/pa', href: 'sc://ho/i', origin: 'null', protocol: 'sc:', username: '', password: '', host: 'ho', hostname: 'ho', port: '', pathname: '/i', search: '', hash: '', }, { input: '/i', base: 'sc:///pa/pa', href: 'sc:///i', origin: 'null', protocol: 'sc:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/i', search: '', hash: '', }, { input: '?i', base: 'sc:sd', failure: true, }, { input: '?i', base: 'sc:sd/sd', failure: true, }, { input: '?i', base: 'sc:/pa/pa', href: 'sc:/pa/pa?i', origin: 'null', protocol: 'sc:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/pa/pa', search: '?i', hash: '', }, { input: '?i', base: 'sc://ho/pa', href: 'sc://ho/pa?i', origin: 'null', protocol: 'sc:', username: '', password: '', host: 'ho', hostname: 'ho', port: '', pathname: '/pa', search: '?i', hash: '', }, { input: '?i', base: 'sc:///pa/pa', href: 'sc:///pa/pa?i', origin: 'null', protocol: 'sc:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/pa/pa', search: '?i', hash: '', }, { input: '#i', base: 'sc:sd', href: 'sc:sd#i', origin: 'null', protocol: 'sc:', username: '', password: '', host: '', hostname: '', port: '', pathname: 'sd', search: '', hash: '#i', }, { input: '#i', base: 'sc:sd/sd', href: 'sc:sd/sd#i', origin: 'null', protocol: 'sc:', username: '', password: '', host: '', hostname: '', port: '', pathname: 'sd/sd', search: '', hash: '#i', }, { input: '#i', base: 'sc:/pa/pa', href: 'sc:/pa/pa#i', origin: 'null', protocol: 'sc:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/pa/pa', search: '', hash: '#i', }, { input: '#i', base: 'sc://ho/pa', href: 'sc://ho/pa#i', origin: 'null', protocol: 'sc:', username: '', password: '', host: 'ho', hostname: 'ho', port: '', pathname: '/pa', search: '', hash: '#i', }, { input: '#i', base: 'sc:///pa/pa', href: 'sc:///pa/pa#i', origin: 'null', protocol: 'sc:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/pa/pa', search: '', hash: '#i', }, '# make sure that relative URL logic works on known typically non-relative schemes too', { input: 'about:/../', base: 'about:blank', href: 'about:/', origin: 'null', protocol: 'about:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/', search: '', hash: '', }, { input: 'data:/../', base: 'about:blank', href: 'data:/', origin: 'null', protocol: 'data:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/', search: '', hash: '', }, { input: 'javascript:/../', base: 'about:blank', href: 'javascript:/', origin: 'null', protocol: 'javascript:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/', search: '', hash: '', }, { input: 'mailto:/../', base: 'about:blank', href: 'mailto:/', origin: 'null', protocol: 'mailto:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/', search: '', hash: '', }, '# unknown schemes and their hosts', { input: 'sc://ñ.test/', base: 'about:blank', href: 'sc://%C3%B1.test/', origin: 'null', protocol: 'sc:', username: '', password: '', host: '%C3%B1.test', hostname: '%C3%B1.test', port: '', pathname: '/', search: '', hash: '', }, { input: 'sc://\u0000/', base: 'about:blank', failure: true, }, { input: 'sc:// /', base: 'about:blank', failure: true, }, { input: 'sc://%/', base: 'about:blank', href: 'sc://%/', protocol: 'sc:', username: '', password: '', host: '%', hostname: '%', port: '', pathname: '/', search: '', hash: '', }, { input: 'sc://@/', base: 'about:blank', failure: true, }, { input: 'sc://te@s:t@/', base: 'about:blank', failure: true, }, { input: 'sc://:/', base: 'about:blank', failure: true, }, { input: 'sc://:12/', base: 'about:blank', failure: true, }, { input: 'sc://[/', base: 'about:blank', failure: true, }, { input: 'sc://\\/', base: 'about:blank', failure: true, }, { input: 'sc://]/', base: 'about:blank', failure: true, }, { input: 'x', base: 'sc://ñ', href: 'sc://%C3%B1/x', origin: 'null', protocol: 'sc:', username: '', password: '', host: '%C3%B1', hostname: '%C3%B1', port: '', pathname: '/x', search: '', hash: '', }, '# unknown schemes and backslashes', { input: 'sc:\\../', base: 'about:blank', href: 'sc:\\../', origin: 'null', protocol: 'sc:', username: '', password: '', host: '', hostname: '', port: '', pathname: '\\../', search: '', hash: '', }, '# unknown scheme with path looking like a password', { input: 'sc::a@example.net', base: 'about:blank', href: 'sc::a@example.net', origin: 'null', protocol: 'sc:', username: '', password: '', host: '', hostname: '', port: '', pathname: ':a@example.net', search: '', hash: '', }, '# unknown scheme with bogus percent-encoding', { input: 'wow:%NBD', base: 'about:blank', href: 'wow:%NBD', origin: 'null', protocol: 'wow:', username: '', password: '', host: '', hostname: '', port: '', pathname: '%NBD', search: '', hash: '', }, { input: 'wow:%1G', base: 'about:blank', href: 'wow:%1G', origin: 'null', protocol: 'wow:', username: '', password: '', host: '', hostname: '', port: '', pathname: '%1G', search: '', hash: '', }, '# Hosts and percent-encoding', { input: 'ftp://example.com%80/', base: 'about:blank', failure: true, }, { input: 'ftp://example.com%A0/', base: 'about:blank', failure: true, }, { input: 'https://example.com%80/', base: 'about:blank', failure: true, }, { input: 'https://example.com%A0/', base: 'about:blank', failure: true, }, { input: 'ftp://%e2%98%83', base: 'about:blank', href: 'ftp://xn--n3h/', origin: 'ftp://xn--n3h', protocol: 'ftp:', username: '', password: '', host: 'xn--n3h', hostname: 'xn--n3h', port: '', pathname: '/', search: '', hash: '', }, { input: 'https://%e2%98%83', base: 'about:blank', href: 'https://xn--n3h/', origin: 'https://xn--n3h', protocol: 'https:', username: '', password: '', host: 'xn--n3h', hostname: 'xn--n3h', port: '', pathname: '/', search: '', hash: '', }, '# tests from jsdom/whatwg-url designed for code coverage', { input: 'http://127.0.0.1:10100/relative_import.html', base: 'about:blank', href: 'http://127.0.0.1:10100/relative_import.html', origin: 'http://127.0.0.1:10100', protocol: 'http:', username: '', password: '', host: '127.0.0.1:10100', hostname: '127.0.0.1', port: '10100', pathname: '/relative_import.html', search: '', hash: '', }, { input: 'http://facebook.com/?foo=%7B%22abc%22', base: 'about:blank', href: 'http://facebook.com/?foo=%7B%22abc%22', origin: 'http://facebook.com', protocol: 'http:', username: '', password: '', host: 'facebook.com', hostname: 'facebook.com', port: '', pathname: '/', search: '?foo=%7B%22abc%22', hash: '', }, { input: 'https://localhost:3000/jqueryui@1.2.3', base: 'about:blank', href: 'https://localhost:3000/jqueryui@1.2.3', origin: 'https://localhost:3000', protocol: 'https:', username: '', password: '', host: 'localhost:3000', hostname: 'localhost', port: '3000', pathname: '/jqueryui@1.2.3', search: '', hash: '', }, '# 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', href: 'http://host:9000/path?query#frag', origin: 'http://host:9000', protocol: 'http:', username: '', password: '', host: 'host:9000', hostname: 'host', port: '9000', pathname: '/path', search: '?query', hash: '#frag', }, '# Stringification of URL.searchParams', { input: '?a=b&c=d', base: 'http://example.org/foo/bar', href: 'http://example.org/foo/bar?a=b&c=d', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/foo/bar', search: '?a=b&c=d', searchParams: 'a=b&c=d', hash: '', }, { input: '??a=b&c=d', base: 'http://example.org/foo/bar', href: 'http://example.org/foo/bar??a=b&c=d', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/foo/bar', search: '??a=b&c=d', searchParams: '%3Fa=b&c=d', hash: '', }, '# Scheme only', { input: 'http:', base: 'http://example.org/foo/bar', href: 'http://example.org/foo/bar', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/foo/bar', search: '', searchParams: '', hash: '', }, { input: 'http:', base: 'https://example.org/foo/bar', failure: true, }, { input: 'sc:', base: 'https://example.org/foo/bar', href: 'sc:', origin: 'null', protocol: 'sc:', username: '', password: '', host: '', hostname: '', port: '', pathname: '', search: '', searchParams: '', hash: '', }, '# Percent encoding of fragments', { input: 'http://foo.bar/baz?qux#foo\bbar', base: 'about:blank', href: 'http://foo.bar/baz?qux#foo%08bar', origin: 'http://foo.bar', protocol: 'http:', username: '', password: '', host: 'foo.bar', hostname: 'foo.bar', port: '', pathname: '/baz', search: '?qux', searchParams: 'qux=', hash: '#foo%08bar', }, '# IPv4 parsing (via https://github.com/nodejs/node/pull/10317)', { input: 'http://192.168.257', base: 'http://other.com/', href: 'http://192.168.1.1/', origin: 'http://192.168.1.1', protocol: 'http:', username: '', password: '', host: '192.168.1.1', hostname: '192.168.1.1', port: '', pathname: '/', search: '', hash: '', }, { input: 'http://192.168.257.com', base: 'http://other.com/', href: 'http://192.168.257.com/', origin: 'http://192.168.257.com', protocol: 'http:', username: '', password: '', host: '192.168.257.com', hostname: '192.168.257.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'http://256', base: 'http://other.com/', href: 'http://0.0.1.0/', origin: 'http://0.0.1.0', protocol: 'http:', username: '', password: '', host: '0.0.1.0', hostname: '0.0.1.0', port: '', pathname: '/', search: '', hash: '', }, { input: 'http://256.com', base: 'http://other.com/', href: 'http://256.com/', origin: 'http://256.com', protocol: 'http:', username: '', password: '', host: '256.com', hostname: '256.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'http://999999999', base: 'http://other.com/', href: 'http://59.154.201.255/', origin: 'http://59.154.201.255', protocol: 'http:', username: '', password: '', host: '59.154.201.255', hostname: '59.154.201.255', port: '', pathname: '/', search: '', hash: '', }, { input: 'http://999999999.com', base: 'http://other.com/', href: 'http://999999999.com/', origin: 'http://999999999.com', protocol: 'http:', username: '', password: '', host: '999999999.com', hostname: '999999999.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'http://10000000000', base: 'http://other.com/', failure: true, }, { input: 'http://10000000000.com', base: 'http://other.com/', href: 'http://10000000000.com/', origin: 'http://10000000000.com', protocol: 'http:', username: '', password: '', host: '10000000000.com', hostname: '10000000000.com', port: '', pathname: '/', search: '', hash: '', }, { input: 'http://4294967295', base: 'http://other.com/', href: 'http://255.255.255.255/', origin: 'http://255.255.255.255', protocol: 'http:', username: '', password: '', host: '255.255.255.255', hostname: '255.255.255.255', port: '', pathname: '/', search: '', hash: '', }, { input: 'http://4294967296', base: 'http://other.com/', failure: true, }, { input: 'http://0xffffffff', base: 'http://other.com/', href: 'http://255.255.255.255/', origin: 'http://255.255.255.255', protocol: 'http:', username: '', password: '', host: '255.255.255.255', hostname: '255.255.255.255', port: '', pathname: '/', search: '', hash: '', }, { input: 'http://0xffffffff1', base: 'http://other.com/', failure: true, }, { input: 'http://256.256.256.256', base: 'http://other.com/', failure: true, }, { input: 'https://0x.0x.0', base: 'about:blank', href: 'https://0.0.0.0/', origin: 'https://0.0.0.0', protocol: 'https:', username: '', password: '', host: '0.0.0.0', hostname: '0.0.0.0', port: '', pathname: '/', search: '', hash: '', }, 'More IPv4 parsing (via https://github.com/jsdom/whatwg-url/issues/92)', { input: 'https://0x100000000/test', base: 'about:blank', failure: true, }, { input: 'https://256.0.0.1/test', base: 'about:blank', failure: true, }, "# file URLs containing percent-encoded Windows drive letters (shouldn't work)", { input: 'file:///C%3A/', base: 'about:blank', href: 'file:///C%3A/', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/C%3A/', search: '', hash: '', }, { input: 'file:///C%7C/', base: 'about:blank', href: 'file:///C%7C/', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/C%7C/', search: '', hash: '', }, '# file URLs relative to other file URLs (via https://github.com/jsdom/whatwg-url/pull/60)', { input: 'pix/submit.gif', base: 'file:///C:/Users/Domenic/Dropbox/GitHub/tmpvar/jsdom/test/level2/html/files/anchor.html', href: 'file:///C:/Users/Domenic/Dropbox/GitHub/tmpvar/jsdom/test/level2/html/files/pix/submit.gif', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/C:/Users/Domenic/Dropbox/GitHub/tmpvar/jsdom/test/level2/html/files/pix/submit.gif', search: '', hash: '', }, { input: '..', base: 'file:///C:/', href: 'file:///C:/', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/C:/', search: '', hash: '', }, { input: '..', base: 'file:///', href: 'file:///', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/', search: '', hash: '', }, '# More file URL tests by zcorpan and annevk', { input: '/', base: 'file:///C:/a/b', href: 'file:///C:/', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/C:/', search: '', hash: '', }, { input: '//d:', base: 'file:///C:/a/b', href: 'file:///d:', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/d:', search: '', hash: '', }, { input: '//d:/..', base: 'file:///C:/a/b', href: 'file:///d:/', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/d:/', search: '', hash: '', }, { input: '..', base: 'file:///ab:/', href: 'file:///', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/', search: '', hash: '', }, { input: '..', base: 'file:///1:/', href: 'file:///', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/', search: '', hash: '', }, { input: '', base: 'file:///test?test#test', href: 'file:///test?test', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/test', search: '?test', hash: '', }, { input: 'file:', base: 'file:///test?test#test', href: 'file:///test?test', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/test', search: '?test', hash: '', }, { input: '?x', base: 'file:///test?test#test', href: 'file:///test?x', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/test', search: '?x', hash: '', }, { input: 'file:?x', base: 'file:///test?test#test', href: 'file:///test?x', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/test', search: '?x', hash: '', }, { input: '#x', base: 'file:///test?test#test', href: 'file:///test?test#x', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/test', search: '?test', hash: '#x', }, { input: 'file:#x', base: 'file:///test?test#test', href: 'file:///test?test#x', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/test', search: '?test', hash: '#x', }, '# File URLs and many (back)slashes', { input: 'file:\\\\//', base: 'about:blank', href: 'file:////', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '//', search: '', hash: '', }, { input: 'file:\\\\\\\\', base: 'about:blank', href: 'file:////', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '//', search: '', hash: '', }, { input: 'file:\\\\\\\\?fox', base: 'about:blank', href: 'file:////?fox', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '//', search: '?fox', hash: '', }, { input: 'file:\\\\\\\\#guppy', base: 'about:blank', href: 'file:////#guppy', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '//', search: '', hash: '#guppy', }, { input: 'file://spider///', base: 'about:blank', href: 'file://spider///', protocol: 'file:', username: '', password: '', host: 'spider', hostname: 'spider', port: '', pathname: '///', search: '', hash: '', }, { input: 'file:\\\\localhost//', base: 'about:blank', href: 'file:////', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '//', search: '', hash: '', }, { input: 'file:///localhost//cat', base: 'about:blank', href: 'file:///localhost//cat', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/localhost//cat', search: '', hash: '', }, { input: 'file://\\/localhost//cat', base: 'about:blank', href: 'file:////localhost//cat', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '//localhost//cat', search: '', hash: '', }, { input: 'file://localhost//a//../..//', base: 'about:blank', href: 'file://///', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '///', search: '', hash: '', }, { input: '/////mouse', base: 'file:///elephant', href: 'file://///mouse', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '///mouse', search: '', hash: '', }, { input: '\\//pig', base: 'file://lion/', href: 'file:///pig', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/pig', search: '', hash: '', }, { input: '\\/localhost//pig', base: 'file://lion/', href: 'file:////pig', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '//pig', search: '', hash: '', }, { input: '//localhost//pig', base: 'file://lion/', href: 'file:////pig', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '//pig', search: '', hash: '', }, { input: '/..//localhost//pig', base: 'file://lion/', href: 'file://lion//localhost//pig', protocol: 'file:', username: '', password: '', host: 'lion', hostname: 'lion', port: '', pathname: '//localhost//pig', search: '', hash: '', }, { input: 'file://', base: 'file://ape/', href: 'file:///', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/', search: '', hash: '', }, '# File URLs with non-empty hosts', { input: '/rooibos', base: 'file://tea/', href: 'file://tea/rooibos', protocol: 'file:', username: '', password: '', host: 'tea', hostname: 'tea', port: '', pathname: '/rooibos', search: '', hash: '', }, { input: '/?chai', base: 'file://tea/', href: 'file://tea/?chai', protocol: 'file:', username: '', password: '', host: 'tea', hostname: 'tea', port: '', pathname: '/', search: '?chai', hash: '', }, "# Windows drive letter handling with the 'file:' base URL", { input: 'C|', base: 'file://host/dir/file', href: 'file://host/C:', protocol: 'file:', username: '', password: '', host: 'host', hostname: 'host', port: '', pathname: '/C:', search: '', hash: '', }, { input: 'C|#', base: 'file://host/dir/file', href: 'file://host/C:#', protocol: 'file:', username: '', password: '', host: 'host', hostname: 'host', port: '', pathname: '/C:', search: '', hash: '', }, { input: 'C|?', base: 'file://host/dir/file', href: 'file://host/C:?', protocol: 'file:', username: '', password: '', host: 'host', hostname: 'host', port: '', pathname: '/C:', search: '', hash: '', }, { input: 'C|/', base: 'file://host/dir/file', href: 'file://host/C:/', protocol: 'file:', username: '', password: '', host: 'host', hostname: 'host', port: '', pathname: '/C:/', search: '', hash: '', }, { input: 'C|\n/', base: 'file://host/dir/file', href: 'file://host/C:/', protocol: 'file:', username: '', password: '', host: 'host', hostname: 'host', port: '', pathname: '/C:/', search: '', hash: '', }, { input: 'C|\\', base: 'file://host/dir/file', href: 'file://host/C:/', protocol: 'file:', username: '', password: '', host: 'host', hostname: 'host', port: '', pathname: '/C:/', search: '', hash: '', }, { input: 'C', base: 'file://host/dir/file', href: 'file://host/dir/C', protocol: 'file:', username: '', password: '', host: 'host', hostname: 'host', port: '', pathname: '/dir/C', search: '', hash: '', }, { input: 'C|a', base: 'file://host/dir/file', href: 'file://host/dir/C|a', protocol: 'file:', username: '', password: '', host: 'host', hostname: 'host', port: '', pathname: '/dir/C|a', search: '', hash: '', }, '# Windows drive letter quirk with not empty host', { input: 'file://example.net/C:/', base: 'about:blank', href: 'file://example.net/C:/', protocol: 'file:', username: '', password: '', host: 'example.net', hostname: 'example.net', port: '', pathname: '/C:/', search: '', hash: '', }, { input: 'file://1.2.3.4/C:/', base: 'about:blank', href: 'file://1.2.3.4/C:/', protocol: 'file:', username: '', password: '', host: '1.2.3.4', hostname: '1.2.3.4', port: '', pathname: '/C:/', search: '', hash: '', }, { input: 'file://[1::8]/C:/', base: 'about:blank', href: 'file://[1::8]/C:/', protocol: 'file:', username: '', password: '', host: '[1::8]', hostname: '[1::8]', port: '', pathname: '/C:/', search: '', hash: '', }, '# Windows drive letter quirk (no host)', { input: 'file:/C|/', base: 'about:blank', href: 'file:///C:/', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/C:/', search: '', hash: '', }, { input: 'file://C|/', base: 'about:blank', href: 'file:///C:/', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/C:/', search: '', hash: '', }, '# file URLs without base URL by Rimas Misevičius', { input: 'file:', base: 'about:blank', href: 'file:///', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/', search: '', hash: '', }, { input: 'file:?q=v', base: 'about:blank', href: 'file:///?q=v', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/', search: '?q=v', hash: '', }, { input: 'file:#frag', base: 'about:blank', href: 'file:///#frag', protocol: 'file:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/', search: '', hash: '#frag', }, '# IPv6 tests', { input: 'http://[1:0::]', base: 'http://example.net/', href: 'http://[1::]/', origin: 'http://[1::]', protocol: 'http:', username: '', password: '', host: '[1::]', hostname: '[1::]', port: '', pathname: '/', search: '', hash: '', }, { input: 'http://[0:1:2:3:4:5:6:7:8]', base: 'http://example.net/', failure: true, }, { input: 'https://[0::0::0]', base: 'about:blank', failure: true, }, { input: 'https://[0:.0]', base: 'about:blank', failure: true, }, { input: 'https://[0:0:]', base: 'about:blank', failure: true, }, { input: 'https://[0:1:2:3:4:5:6:7.0.0.0.1]', base: 'about:blank', failure: true, }, { input: 'https://[0:1.00.0.0.0]', base: 'about:blank', failure: true, }, { input: 'https://[0:1.290.0.0.0]', base: 'about:blank', failure: true, }, { input: 'https://[0:1.23.23]', base: 'about:blank', failure: true, }, '# Empty host', { input: 'http://?', base: 'about:blank', failure: true, }, { input: 'http://#', base: 'about:blank', failure: true, }, '# Non-special-URL path tests', { input: 'sc://ñ', base: 'about:blank', href: 'sc://%C3%B1', origin: 'null', protocol: 'sc:', username: '', password: '', host: '%C3%B1', hostname: '%C3%B1', port: '', pathname: '', search: '', hash: '', }, { input: 'sc://ñ?x', base: 'about:blank', href: 'sc://%C3%B1?x', origin: 'null', protocol: 'sc:', username: '', password: '', host: '%C3%B1', hostname: '%C3%B1', port: '', pathname: '', search: '?x', hash: '', }, { input: 'sc://ñ#x', base: 'about:blank', href: 'sc://%C3%B1#x', origin: 'null', protocol: 'sc:', username: '', password: '', host: '%C3%B1', hostname: '%C3%B1', port: '', pathname: '', search: '', hash: '#x', }, { input: '#x', base: 'sc://ñ', href: 'sc://%C3%B1#x', origin: 'null', protocol: 'sc:', username: '', password: '', host: '%C3%B1', hostname: '%C3%B1', port: '', pathname: '', search: '', hash: '#x', }, { input: '?x', base: 'sc://ñ', href: 'sc://%C3%B1?x', origin: 'null', protocol: 'sc:', username: '', password: '', host: '%C3%B1', hostname: '%C3%B1', port: '', pathname: '', search: '?x', hash: '', }, { input: 'sc://?', base: 'about:blank', href: 'sc://?', protocol: 'sc:', username: '', password: '', host: '', hostname: '', port: '', pathname: '', search: '', hash: '', }, { input: 'sc://#', base: 'about:blank', href: 'sc://#', protocol: 'sc:', username: '', password: '', host: '', hostname: '', port: '', pathname: '', search: '', hash: '', }, { input: '///', base: 'sc://x/', href: 'sc:///', protocol: 'sc:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/', search: '', hash: '', }, { input: '////', base: 'sc://x/', href: 'sc:////', protocol: 'sc:', username: '', password: '', host: '', hostname: '', port: '', pathname: '//', search: '', hash: '', }, { input: '////x/', base: 'sc://x/', href: 'sc:////x/', protocol: 'sc:', username: '', password: '', host: '', hostname: '', port: '', pathname: '//x/', search: '', hash: '', }, { input: 'tftp://foobar.com/someconfig;mode=netascii', base: 'about:blank', href: 'tftp://foobar.com/someconfig;mode=netascii', origin: 'null', protocol: 'tftp:', username: '', password: '', host: 'foobar.com', hostname: 'foobar.com', port: '', pathname: '/someconfig;mode=netascii', search: '', hash: '', }, { input: 'telnet://user:pass@foobar.com:23/', base: 'about:blank', href: 'telnet://user:pass@foobar.com:23/', origin: 'null', protocol: 'telnet:', username: 'user', password: 'pass', host: 'foobar.com:23', hostname: 'foobar.com', port: '23', pathname: '/', search: '', hash: '', }, { input: 'ut2004://10.10.10.10:7777/Index.ut2', base: 'about:blank', href: 'ut2004://10.10.10.10:7777/Index.ut2', origin: 'null', protocol: 'ut2004:', username: '', password: '', host: '10.10.10.10:7777', hostname: '10.10.10.10', port: '7777', pathname: '/Index.ut2', search: '', hash: '', }, { input: 'redis://foo:bar@somehost:6379/0?baz=bam&qux=baz', base: 'about:blank', href: 'redis://foo:bar@somehost:6379/0?baz=bam&qux=baz', origin: 'null', protocol: 'redis:', username: 'foo', password: 'bar', host: 'somehost:6379', hostname: 'somehost', port: '6379', pathname: '/0', search: '?baz=bam&qux=baz', hash: '', }, { input: 'rsync://foo@host:911/sup', base: 'about:blank', href: 'rsync://foo@host:911/sup', origin: 'null', protocol: 'rsync:', username: 'foo', password: '', host: 'host:911', hostname: 'host', port: '911', pathname: '/sup', search: '', hash: '', }, { input: 'git://github.com/foo/bar.git', base: 'about:blank', href: 'git://github.com/foo/bar.git', origin: 'null', protocol: 'git:', username: '', password: '', host: 'github.com', hostname: 'github.com', port: '', pathname: '/foo/bar.git', search: '', hash: '', }, { input: 'irc://myserver.com:6999/channel?passwd', base: 'about:blank', href: 'irc://myserver.com:6999/channel?passwd', origin: 'null', protocol: 'irc:', username: '', password: '', host: 'myserver.com:6999', hostname: 'myserver.com', port: '6999', pathname: '/channel', search: '?passwd', hash: '', }, { input: 'dns://fw.example.org:9999/foo.bar.org?type=TXT', base: 'about:blank', href: 'dns://fw.example.org:9999/foo.bar.org?type=TXT', origin: 'null', protocol: 'dns:', username: '', password: '', host: 'fw.example.org:9999', hostname: 'fw.example.org', port: '9999', pathname: '/foo.bar.org', search: '?type=TXT', hash: '', }, { input: 'ldap://localhost:389/ou=People,o=JNDITutorial', base: 'about:blank', href: 'ldap://localhost:389/ou=People,o=JNDITutorial', origin: 'null', protocol: 'ldap:', username: '', password: '', host: 'localhost:389', hostname: 'localhost', port: '389', pathname: '/ou=People,o=JNDITutorial', search: '', hash: '', }, { input: 'git+https://github.com/foo/bar', base: 'about:blank', href: 'git+https://github.com/foo/bar', origin: 'null', protocol: 'git+https:', username: '', password: '', host: 'github.com', hostname: 'github.com', port: '', pathname: '/foo/bar', search: '', hash: '', }, { input: 'urn:ietf:rfc:2648', base: 'about:blank', href: 'urn:ietf:rfc:2648', origin: 'null', protocol: 'urn:', username: '', password: '', host: '', hostname: '', port: '', pathname: 'ietf:rfc:2648', search: '', hash: '', }, { input: 'tag:joe@example.org,2001:foo/bar', base: 'about:blank', href: 'tag:joe@example.org,2001:foo/bar', origin: 'null', protocol: 'tag:', username: '', password: '', host: '', hostname: '', port: '', pathname: 'joe@example.org,2001:foo/bar', search: '', hash: '', }, '# percent encoded hosts in non-special-URLs', { input: 'non-special://%E2%80%A0/', base: 'about:blank', href: 'non-special://%E2%80%A0/', protocol: 'non-special:', username: '', password: '', host: '%E2%80%A0', hostname: '%E2%80%A0', port: '', pathname: '/', search: '', hash: '', }, { input: 'non-special://H%4fSt/path', base: 'about:blank', href: 'non-special://H%4fSt/path', protocol: 'non-special:', username: '', password: '', host: 'H%4fSt', hostname: 'H%4fSt', port: '', pathname: '/path', search: '', hash: '', }, '# IPv6 in non-special-URLs', { input: 'non-special://[1:2:0:0:5:0:0:0]/', base: 'about:blank', href: 'non-special://[1:2:0:0:5::]/', protocol: 'non-special:', username: '', password: '', host: '[1:2:0:0:5::]', hostname: '[1:2:0:0:5::]', port: '', pathname: '/', search: '', hash: '', }, { input: 'non-special://[1:2:0:0:0:0:0:3]/', base: 'about:blank', href: 'non-special://[1:2::3]/', protocol: 'non-special:', username: '', password: '', host: '[1:2::3]', hostname: '[1:2::3]', port: '', pathname: '/', search: '', hash: '', }, { input: 'non-special://[1:2::3]:80/', base: 'about:blank', href: 'non-special://[1:2::3]:80/', protocol: 'non-special:', username: '', password: '', host: '[1:2::3]:80', hostname: '[1:2::3]', port: '80', pathname: '/', search: '', hash: '', }, { input: 'non-special://[:80/', base: 'about:blank', failure: true, }, { input: 'blob:https://example.com:443/', base: 'about:blank', href: 'blob:https://example.com:443/', origin: 'https://example.com', protocol: 'blob:', username: '', password: '', host: '', hostname: '', port: '', pathname: 'https://example.com:443/', search: '', hash: '', }, { input: 'blob:d3958f5c-0777-0845-9dcf-2cb28783acaf', base: 'about:blank', href: 'blob:d3958f5c-0777-0845-9dcf-2cb28783acaf', protocol: 'blob:', username: '', password: '', host: '', hostname: '', port: '', pathname: 'd3958f5c-0777-0845-9dcf-2cb28783acaf', search: '', hash: '', }, 'Invalid IPv4 radix digits', { input: 'http://0x7f.0.0.0x7g', base: 'about:blank', href: 'http://0x7f.0.0.0x7g/', origin: '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: 'about:blank', href: 'http://0x7f.0.0.0x7g/', origin: 'http://0x7f.0.0.0x7g', protocol: 'http:', username: '', password: '', host: '0x7f.0.0.0x7g', hostname: '0x7f.0.0.0x7g', port: '', pathname: '/', search: '', hash: '', }, 'Invalid IPv4 portion of IPv6 address', { input: 'http://[::127.0.0.0.1]', base: 'about:blank', failure: true, }, 'Uncompressed IPv6 addresses with 0', { input: 'http://[0:1:0:1:0:1:0:1]', base: 'about:blank', href: 'http://[0:1:0:1:0:1:0:1]/', origin: 'http://[0:1:0:1:0:1:0:1]', protocol: 'http:', username: '', password: '', host: '[0:1:0:1:0:1:0:1]', hostname: '[0:1:0:1:0:1:0:1]', port: '', pathname: '/', search: '', hash: '', }, { input: 'http://[1:0:1:0:1:0:1:0]', base: 'about:blank', href: 'http://[1:0:1:0:1:0:1:0]/', origin: 'http://[1:0:1:0:1:0:1:0]', protocol: 'http:', username: '', password: '', host: '[1:0:1:0:1:0:1:0]', hostname: '[1:0:1:0:1:0:1:0]', port: '', pathname: '/', search: '', hash: '', }, 'Percent-encoded query and fragment', { input: 'http://example.org/test?\u0022', base: 'about:blank', href: 'http://example.org/test?%22', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/test', search: '?%22', hash: '', }, { input: 'http://example.org/test?\u0023', base: 'about:blank', href: 'http://example.org/test?#', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/test', search: '', hash: '', }, { input: 'http://example.org/test?\u003C', base: 'about:blank', href: 'http://example.org/test?%3C', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/test', search: '?%3C', hash: '', }, { input: 'http://example.org/test?\u003E', base: 'about:blank', href: 'http://example.org/test?%3E', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/test', search: '?%3E', hash: '', }, { input: 'http://example.org/test?\u2323', base: 'about:blank', href: 'http://example.org/test?%E2%8C%A3', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/test', search: '?%E2%8C%A3', hash: '', }, { input: 'http://example.org/test?%23%23', base: 'about:blank', href: 'http://example.org/test?%23%23', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/test', search: '?%23%23', hash: '', }, { input: 'http://example.org/test?%GH', base: 'about:blank', href: 'http://example.org/test?%GH', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/test', search: '?%GH', hash: '', }, { input: 'http://example.org/test?a#%EF', base: 'about:blank', href: 'http://example.org/test?a#%EF', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/test', search: '?a', hash: '#%EF', }, { input: 'http://example.org/test?a#%GH', base: 'about:blank', href: 'http://example.org/test?a#%GH', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/test', search: '?a', hash: '#%GH', }, 'Bad bases', { input: 'test-a.html', base: 'a', failure: true, }, { input: 'test-a-slash.html', base: 'a/', failure: true, }, { input: 'test-a-slash-slash.html', base: 'a//', failure: true, }, { input: 'test-a-colon.html', base: 'a:', failure: true, }, { input: 'test-a-colon-slash.html', base: 'a:/', href: 'a:/test-a-colon-slash.html', protocol: 'a:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/test-a-colon-slash.html', search: '', hash: '', }, { input: 'test-a-colon-slash-slash.html', base: 'a://', href: 'a:///test-a-colon-slash-slash.html', protocol: 'a:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/test-a-colon-slash-slash.html', search: '', hash: '', }, { input: 'test-a-colon-b.html', base: 'a:b', failure: true, }, { input: 'test-a-colon-slash-b.html', base: 'a:/b', href: 'a:/test-a-colon-slash-b.html', protocol: 'a:', username: '', password: '', host: '', hostname: '', port: '', pathname: '/test-a-colon-slash-b.html', search: '', hash: '', }, { input: 'test-a-colon-slash-slash-b.html', base: 'a://b', href: 'a://b/test-a-colon-slash-slash-b.html', protocol: 'a:', username: '', password: '', host: 'b', hostname: 'b', port: '', pathname: '/test-a-colon-slash-slash-b.html', search: '', hash: '', }, 'Null code point in fragment', { input: 'http://example.org/test?a#b\u0000c', base: 'about:blank', href: 'http://example.org/test?a#b%00c', origin: 'http://example.org', protocol: 'http:', username: '', password: '', host: 'example.org', hostname: 'example.org', port: '', pathname: '/test', search: '?a', hash: '#b%00c', }, ]; cases.forEach((test) => { if (typeof test === 'string') return; if (test.failure) { throws(() => { new URL(test.input, test.base || 'about:blank'); }); return; } const url = new URL(test.input, test.base || 'about:blank'); strictEqual(url.href, test.href); strictEqual(url.protocol, test.protocol); strictEqual(url.username, test.username); strictEqual(url.password, test.password); strictEqual(url.host, test.host); strictEqual(url.hostname, test.hostname); strictEqual(url.port, test.port); strictEqual(url.pathname, test.pathname); strictEqual(url.search, test.search); if ('searchParams' in test) { strictEqual(url.searchParams.toString(), test.searchParams); } strictEqual(url.hash, test.hash); if (test.origin == null) { strictEqual(url.origin, 'null'); } else { strictEqual(url.origin, test.origin); } }); }, }; export const wptTestURLSearchParamsConstructor = { test() { let params = new URLSearchParams(); strictEqual(params + '', ''); params = new URLSearchParams(''); strictEqual(params + '', ''); params = new URLSearchParams('a=b'); strictEqual(params + '', 'a=b'); params = new URLSearchParams(params); strictEqual(params + '', 'a=b'); { const params = new URLSearchParams(); strictEqual(params.toString(), ''); } { const params = new URLSearchParams(DOMException); strictEqual( params.toString(), 'INDEX_SIZE_ERR=1&DOMSTRING_SIZE_ERR=2&HIERARCHY_REQUEST_ERR=3&WRONG_DOCUMENT_ERR=4&INVALID_CHARACTER_ERR=5&NO_DATA_ALLOWED_ERR=6&NO_MODIFICATION_ALLOWED_ERR=7&NOT_FOUND_ERR=8&NOT_SUPPORTED_ERR=9&INUSE_ATTRIBUTE_ERR=10&INVALID_STATE_ERR=11&SYNTAX_ERR=12&INVALID_MODIFICATION_ERR=13&NAMESPACE_ERR=14&INVALID_ACCESS_ERR=15&VALIDATION_ERR=16&TYPE_MISMATCH_ERR=17&SECURITY_ERR=18&NETWORK_ERR=19&ABORT_ERR=20&URL_MISMATCH_ERR=21"A_EXCEEDED_ERR=22&TIMEOUT_ERR=23&INVALID_NODE_TYPE_ERR=24&DATA_CLONE_ERR=25' ); } { const params = new URLSearchParams(''); strictEqual(params.__proto__, URLSearchParams.prototype); } { const params = new URLSearchParams({}); strictEqual(params + '', ''); } { let params = new URLSearchParams('a=b'); ok(params.has('a')); ok(!params.has('b')); params = new URLSearchParams('a=b&c'); ok(params.has('a')); ok(params.has('c')); params = new URLSearchParams('&a&&& &&&&&a+b=& c&m%c3%b8%c3%b8'); ok(params.has('a')); ok(params.has('a b')); ok(params.has(' ')); ok(!params.has('c')); ok(params.has(' c')); ok(params.has('møø')); } { const seed = new URLSearchParams('a=b&c=d'); const params = new URLSearchParams(seed); strictEqual(params.get('a'), 'b'); strictEqual(params.get('c'), 'd'); ok(!params.has('d')); // The name-value pairs are copied when created; later updates // should not be observable. seed.append('e', 'f'); ok(!params.has('e')); params.append('g', 'h'); ok(!seed.has('g')); } { let params = new URLSearchParams('a=b+c'); strictEqual(params.get('a'), 'b c'); params = new URLSearchParams('a+b=c'); strictEqual(params.get('a b'), 'c'); } { const testValue = '+15555555555'; const params = new URLSearchParams(); params.set('query', testValue); const newParams = new URLSearchParams(params.toString()); strictEqual(params.toString(), 'query=%2B15555555555'); strictEqual(params.get('query'), testValue); strictEqual(newParams.get('query'), testValue); } { let params = new URLSearchParams('a=b c'); strictEqual(params.get('a'), 'b c'); params = new URLSearchParams('a b=c'); strictEqual(params.get('a b'), 'c'); } { let params = new URLSearchParams('a=b%20c'); strictEqual(params.get('a'), 'b c'); params = new URLSearchParams('a%20b=c'); strictEqual(params.get('a b'), 'c'); } { let params = new URLSearchParams('a=b\0c'); strictEqual(params.get('a'), 'b\0c'); params = new URLSearchParams('a\0b=c'); strictEqual(params.get('a\0b'), 'c'); } { let params = new URLSearchParams('a=b%00c'); strictEqual(params.get('a'), 'b\0c'); params = new URLSearchParams('a%00b=c'); strictEqual(params.get('a\0b'), 'c'); } { let params = new URLSearchParams('a=b\u2384'); strictEqual(params.get('a'), 'b\u2384'); params = new URLSearchParams('a\u2384b=c'); strictEqual(params.get('a\u2384b'), 'c'); } { let params = new URLSearchParams('a=b%e2%8e%84'); strictEqual(params.get('a'), 'b\u2384'); params = new URLSearchParams('a%e2%8e%84b=c'); strictEqual(params.get('a\u2384b'), 'c'); } { let params = new URLSearchParams('a=b\uD83D\uDCA9c'); strictEqual(params.get('a'), 'b\uD83D\uDCA9c'); params = new URLSearchParams('a\uD83D\uDCA9b=c'); strictEqual(params.get('a\uD83D\uDCA9b'), 'c'); } { let params = new URLSearchParams('a=b%f0%9f%92%a9c'); strictEqual(params.get('a'), 'b\uD83D\uDCA9c'); params = new URLSearchParams('a%f0%9f%92%a9b=c'); strictEqual(params.get('a\uD83D\uDCA9b'), 'c'); } { let params = new URLSearchParams([]); params = new URLSearchParams([ ['a', 'b'], ['c', 'd'], ]); strictEqual(params.get('a'), 'b'); strictEqual(params.get('c'), 'd'); throws(() => new URLSearchParams([[1]])); throws(() => new URLSearchParams([[1, 2, 3]])); } { let params = new URLSearchParams('a=a/b~'); strictEqual(params.toString(), 'a=a%2Fb%7E'); let url = new URL('https://example.org?a=a/b~'); strictEqual(url.search, '?a=a/b~'); strictEqual(url.searchParams.toString(), 'a=a%2Fb%7E'); } [ { input: { '+': '%C2' }, output: [['+', '%C2']], name: 'object with +' }, { input: { c: 'x', a: '?' }, output: [ ['c', 'x'], ['a', '?'], ], name: 'object with two keys', }, { input: [ ['c', 'x'], ['a', '?'], ], output: [ ['c', 'x'], ['a', '?'], ], name: 'array with two keys', }, ].forEach((val) => { let params = new URLSearchParams(val.input); let i = 0; for (let param of params) { deepStrictEqual(param, val.output[i]); i++; } }); { const params = new URLSearchParams(); params[Symbol.iterator] = function* () { yield ['a', 'b']; }; let params2 = new URLSearchParams(params); strictEqual(params2.get('a'), 'b'); } }, }; export const urlSetSearch = { test() { const url = new URL('http://example.com?foo=bar&baz=qux'); url.search = '?quux=corge&grault=garply'; const result = []; for (let param of url.searchParams) { result.push(param.join(':')); } deepStrictEqual(result, ['quux:corge', 'grault:garply']); }, }; export const urlSegfaultRegression = { test() { let url = new URL('http://example.org/?foo=bar&baz=qux'); // Setting certain properties would once zero out an internal reference count, causing a // nondeterministic crash during URL/URLSearchParams destruction. It triggered an assertion // under debug mode when the `searchParams` property was accessed, which this test is designed // to express. url.protocol = 'http:'; strictEqual(url.searchParams.toString(), 'foo=bar&baz=qux'); }, }; // ====================================================================================== export const urlPatternBasics = { test() { const urlPattern = new URLPattern(); // The standard attributes exist as they should and are readonly strictEqual(urlPattern.protocol, '*'); strictEqual(urlPattern.username, '*'); strictEqual(urlPattern.password, '*'); strictEqual(urlPattern.hostname, '*'); strictEqual(urlPattern.port, '*'); strictEqual(urlPattern.pathname, '*'); strictEqual(urlPattern.search, '*'); strictEqual(urlPattern.hash, '*'); strictEqual(typeof urlPattern.exec, 'function'); strictEqual(typeof urlPattern.test, 'function'); { // URLPattern can be correctly subclassed. let count = 0; class MyURLPattern extends URLPattern { get protocol() { count++; return super.protocol; } get username() { count++; return super.username; } get password() { count++; return super.password; } get hostname() { count++; return super.hostname; } get port() { count++; return super.port; } get pathname() { count++; return super.pathname; } get search() { count++; return super.search; } get hash() { count++; return super.hash; } test() { return true; } exec() { return true; } } const myPattern = new MyURLPattern(); strictEqual(myPattern.protocol, '*'); strictEqual(myPattern.username, '*'); strictEqual(myPattern.password, '*'); strictEqual(myPattern.hostname, '*'); strictEqual(myPattern.port, '*'); strictEqual(myPattern.pathname, '*'); strictEqual(myPattern.search, '*'); strictEqual(myPattern.hash, '*'); strictEqual(myPattern.exec(), true); strictEqual(myPattern.test(), true); strictEqual(count, 8); } }, }; export const urlParseStatic = { test() { const url = URL.parse('http://example.org'); strictEqual(url.protocol, 'http:'); strictEqual(url.host, 'example.org'); const url2 = URL.parse('foo', 'http://example.org'); strictEqual(url2.protocol, 'http:'); strictEqual(url2.host, 'example.org'); strictEqual(url2.pathname, '/foo'); // Unlike `new URL(...)` the `URL.parse(...)` function does not throw on invalid URLs // (which is the key point) strictEqual(URL.parse('not valid'), null); }, }; export const urlSearchParamsPipe = { test() { const url = new URL('http://example.com/?a=b%7Cc'); strictEqual(url.search, '?a=b%7Cc'); strictEqual(url.searchParams.toString(), 'a=b%7Cc'); }, }; export const urlPatternFun = { test() { const v3 = new Uint16Array(57578); const v4 = {}; v4.username = v3; new URLPattern(v4); }, }; export const urlPatternExecWithNestedRegexGroups = { test() { // Regression test: a pattern whose value contains its own capturing groups // (e.g. a named group like (?x)) would cause an out-of-bounds access // in execRegex because the regex match array is larger than the nameList. // The unnamed regex group gets auto-named "0" by the URLPattern parser. const pattern = new URLPattern({ pathname: '/:a/((?x))' }); const result = pattern.exec({ pathname: '/1/x' }); strictEqual(result !== null, true); const groups = result.pathname.groups; strictEqual(groups.a, '1'); strictEqual(groups['0'], 'x'); // Should only have the two named parts from the URL pattern (not regex named groups). deepStrictEqual(Object.keys(groups), ['0', 'a']); }, };