import { describe, test } from "bun:test"; import assert from "node:assert"; import { inspect } from "node:util"; import url from "node:url"; describe("url.parse then url.format", () => { // URLs to parse, and expected data // { URL : parsed } const parseTests = { "//some_path": { href: "//some_path", pathname: "//some_path", path: "//some_path", }, "http:\\\\evil-phisher\\foo.html#h\\a\\s\\h": { protocol: "http:", slashes: true, host: "evil-phisher", hostname: "evil-phisher", pathname: "/foo.html", path: "/foo.html", hash: "#h%5Ca%5Cs%5Ch", href: "http://evil-phisher/foo.html#h%5Ca%5Cs%5Ch", }, 'http:\\\\evil-phisher\\foo.html?json="\\"foo\\""#h\\a\\s\\h': { protocol: "http:", slashes: true, host: "evil-phisher", hostname: "evil-phisher", pathname: "/foo.html", search: "?json=%22%5C%22foo%5C%22%22", query: "json=%22%5C%22foo%5C%22%22", path: "/foo.html?json=%22%5C%22foo%5C%22%22", hash: "#h%5Ca%5Cs%5Ch", href: "http://evil-phisher/foo.html?json=%22%5C%22foo%5C%22%22#h%5Ca%5Cs%5Ch", }, "http:\\\\evil-phisher\\foo.html#h\\a\\s\\h?blarg": { protocol: "http:", slashes: true, host: "evil-phisher", hostname: "evil-phisher", pathname: "/foo.html", path: "/foo.html", hash: "#h%5Ca%5Cs%5Ch?blarg", href: "http://evil-phisher/foo.html#h%5Ca%5Cs%5Ch?blarg", }, "http:\\\\evil-phisher\\foo.html": { protocol: "http:", slashes: true, host: "evil-phisher", hostname: "evil-phisher", pathname: "/foo.html", path: "/foo.html", href: "http://evil-phisher/foo.html", }, "HTTP://www.example.com/": { href: "http://www.example.com/", protocol: "http:", slashes: true, host: "www.example.com", hostname: "www.example.com", pathname: "/", path: "/", }, "HTTP://www.example.com": { href: "http://www.example.com/", protocol: "http:", slashes: true, host: "www.example.com", hostname: "www.example.com", pathname: "/", path: "/", }, "http://www.ExAmPlE.com/": { href: "http://www.example.com/", protocol: "http:", slashes: true, host: "www.example.com", hostname: "www.example.com", pathname: "/", path: "/", }, "http://user:pw@www.ExAmPlE.com/": { href: "http://user:pw@www.example.com/", protocol: "http:", slashes: true, auth: "user:pw", host: "www.example.com", hostname: "www.example.com", pathname: "/", path: "/", }, "http://USER:PW@www.ExAmPlE.com/": { href: "http://USER:PW@www.example.com/", protocol: "http:", slashes: true, auth: "USER:PW", host: "www.example.com", hostname: "www.example.com", pathname: "/", path: "/", }, "http://user@www.example.com/": { href: "http://user@www.example.com/", protocol: "http:", slashes: true, auth: "user", host: "www.example.com", hostname: "www.example.com", pathname: "/", path: "/", }, "http://user%3Apw@www.example.com/": { href: "http://user:pw@www.example.com/", protocol: "http:", slashes: true, auth: "user:pw", host: "www.example.com", hostname: "www.example.com", pathname: "/", path: "/", }, "http://x.com/path?that's#all, folks": { href: "http://x.com/path?that%27s#all,%20folks", protocol: "http:", slashes: true, host: "x.com", hostname: "x.com", search: "?that%27s", query: "that%27s", pathname: "/path", hash: "#all,%20folks", path: "/path?that%27s", }, "HTTP://X.COM/Y": { href: "http://x.com/Y", protocol: "http:", slashes: true, host: "x.com", hostname: "x.com", pathname: "/Y", path: "/Y", }, // Whitespace in the front " http://www.example.com/": { href: "http://www.example.com/", protocol: "http:", slashes: true, host: "www.example.com", hostname: "www.example.com", pathname: "/", path: "/", }, // + not an invalid host character // per https://URL.spec.whatwg.org/#host-parsing "http://x.y.com+a/b/c": { href: "http://x.y.com+a/b/c", protocol: "http:", slashes: true, host: "x.y.com+a", hostname: "x.y.com+a", pathname: "/b/c", path: "/b/c", }, // An unexpected invalid char in the hostname. "HtTp://x.y.cOm;a/b/c?d=e#f gi": { href: "http://x.y.com/;a/b/c?d=e#f%20g%3Ch%3Ei", protocol: "http:", slashes: true, host: "x.y.com", hostname: "x.y.com", pathname: ";a/b/c", search: "?d=e", query: "d=e", hash: "#f%20g%3Ch%3Ei", path: ";a/b/c?d=e", }, // Make sure that we don't accidentally lcast the path parts. "HtTp://x.y.cOm;A/b/c?d=e#f gi": { href: "http://x.y.com/;A/b/c?d=e#f%20g%3Ch%3Ei", protocol: "http:", slashes: true, host: "x.y.com", hostname: "x.y.com", pathname: ";A/b/c", search: "?d=e", query: "d=e", hash: "#f%20g%3Ch%3Ei", path: ";A/b/c?d=e", }, "http://x...y...#p": { href: "http://x...y.../#p", protocol: "http:", slashes: true, host: "x...y...", hostname: "x...y...", hash: "#p", pathname: "/", path: "/", }, 'http://x/p/"quoted"': { href: "http://x/p/%22quoted%22", protocol: "http:", slashes: true, host: "x", hostname: "x", pathname: "/p/%22quoted%22", path: "/p/%22quoted%22", }, " Is a URL!": { href: "%3Chttp://goo.corn/bread%3E%20Is%20a%20URL!", pathname: "%3Chttp://goo.corn/bread%3E%20Is%20a%20URL!", path: "%3Chttp://goo.corn/bread%3E%20Is%20a%20URL!", }, "http://www.narwhaljs.org/blog/categories?id=news": { href: "http://www.narwhaljs.org/blog/categories?id=news", protocol: "http:", slashes: true, host: "www.narwhaljs.org", hostname: "www.narwhaljs.org", search: "?id=news", query: "id=news", pathname: "/blog/categories", path: "/blog/categories?id=news", }, "http://mt0.google.com/vt/lyrs=m@114&hl=en&src=api&x=2&y=2&z=3&s=": { href: "http://mt0.google.com/vt/lyrs=m@114&hl=en&src=api&x=2&y=2&z=3&s=", protocol: "http:", slashes: true, host: "mt0.google.com", hostname: "mt0.google.com", pathname: "/vt/lyrs=m@114&hl=en&src=api&x=2&y=2&z=3&s=", path: "/vt/lyrs=m@114&hl=en&src=api&x=2&y=2&z=3&s=", }, "http://mt0.google.com/vt/lyrs=m@114???&hl=en&src=api&x=2&y=2&z=3&s=": { href: "http://mt0.google.com/vt/lyrs=m@114???&hl=en&src=api" + "&x=2&y=2&z=3&s=", protocol: "http:", slashes: true, host: "mt0.google.com", hostname: "mt0.google.com", search: "???&hl=en&src=api&x=2&y=2&z=3&s=", query: "??&hl=en&src=api&x=2&y=2&z=3&s=", pathname: "/vt/lyrs=m@114", path: "/vt/lyrs=m@114???&hl=en&src=api&x=2&y=2&z=3&s=", }, "http://user:pass@mt0.google.com/vt/lyrs=m@114???&hl=en&src=api&x=2&y=2&z=3&s=": { href: "http://user:pass@mt0.google.com/vt/lyrs=m@114???&hl=en&src=api&x=2&y=2&z=3&s=", protocol: "http:", slashes: true, host: "mt0.google.com", auth: "user:pass", hostname: "mt0.google.com", search: "???&hl=en&src=api&x=2&y=2&z=3&s=", query: "??&hl=en&src=api&x=2&y=2&z=3&s=", pathname: "/vt/lyrs=m@114", path: "/vt/lyrs=m@114???&hl=en&src=api&x=2&y=2&z=3&s=", }, "file:///etc/passwd": { href: "file:///etc/passwd", slashes: true, protocol: "file:", pathname: "/etc/passwd", hostname: "", host: "", path: "/etc/passwd", }, "file://localhost/etc/passwd": { href: "file://localhost/etc/passwd", protocol: "file:", slashes: true, pathname: "/etc/passwd", hostname: "localhost", host: "localhost", path: "/etc/passwd", }, "file://foo/etc/passwd": { href: "file://foo/etc/passwd", protocol: "file:", slashes: true, pathname: "/etc/passwd", hostname: "foo", host: "foo", path: "/etc/passwd", }, "file:///etc/node/": { href: "file:///etc/node/", slashes: true, protocol: "file:", pathname: "/etc/node/", hostname: "", host: "", path: "/etc/node/", }, "file://localhost/etc/node/": { href: "file://localhost/etc/node/", protocol: "file:", slashes: true, pathname: "/etc/node/", hostname: "localhost", host: "localhost", path: "/etc/node/", }, "file://foo/etc/node/": { href: "file://foo/etc/node/", protocol: "file:", slashes: true, pathname: "/etc/node/", hostname: "foo", host: "foo", path: "/etc/node/", }, "http:/baz/../foo/bar": { href: "http:/baz/../foo/bar", protocol: "http:", pathname: "/baz/../foo/bar", path: "/baz/../foo/bar", }, "http://user:pass@example.com:8000/foo/bar?baz=quux#frag": { href: "http://user:pass@example.com:8000/foo/bar?baz=quux#frag", protocol: "http:", slashes: true, host: "example.com:8000", auth: "user:pass", port: "8000", hostname: "example.com", hash: "#frag", search: "?baz=quux", query: "baz=quux", pathname: "/foo/bar", path: "/foo/bar?baz=quux", }, "//user:pass@example.com:8000/foo/bar?baz=quux#frag": { href: "//user:pass@example.com:8000/foo/bar?baz=quux#frag", slashes: true, host: "example.com:8000", auth: "user:pass", port: "8000", hostname: "example.com", hash: "#frag", search: "?baz=quux", query: "baz=quux", pathname: "/foo/bar", path: "/foo/bar?baz=quux", }, "/foo/bar?baz=quux#frag": { href: "/foo/bar?baz=quux#frag", hash: "#frag", search: "?baz=quux", query: "baz=quux", pathname: "/foo/bar", path: "/foo/bar?baz=quux", }, "http:/foo/bar?baz=quux#frag": { href: "http:/foo/bar?baz=quux#frag", protocol: "http:", hash: "#frag", search: "?baz=quux", query: "baz=quux", pathname: "/foo/bar", path: "/foo/bar?baz=quux", }, "mailto:foo@bar.com?subject=hello": { href: "mailto:foo@bar.com?subject=hello", protocol: "mailto:", host: "bar.com", auth: "foo", hostname: "bar.com", search: "?subject=hello", query: "subject=hello", path: "?subject=hello", }, "javascript:alert('hello');": { href: "javascript:alert('hello');", protocol: "javascript:", pathname: "alert('hello');", path: "alert('hello');", }, "xmpp:isaacschlueter@jabber.org": { href: "xmpp:isaacschlueter@jabber.org", protocol: "xmpp:", host: "jabber.org", auth: "isaacschlueter", hostname: "jabber.org", }, "http://atpass:foo%40bar@127.0.0.1:8080/path?search=foo#bar": { href: "http://atpass:foo%40bar@127.0.0.1:8080/path?search=foo#bar", protocol: "http:", slashes: true, host: "127.0.0.1:8080", auth: "atpass:foo@bar", hostname: "127.0.0.1", port: "8080", pathname: "/path", search: "?search=foo", query: "search=foo", hash: "#bar", path: "/path?search=foo", }, "svn+ssh://foo/bar": { href: "svn+ssh://foo/bar", host: "foo", hostname: "foo", protocol: "svn+ssh:", pathname: "/bar", path: "/bar", slashes: true, }, "dash-test://foo/bar": { href: "dash-test://foo/bar", host: "foo", hostname: "foo", protocol: "dash-test:", pathname: "/bar", path: "/bar", slashes: true, }, "dash-test:foo/bar": { href: "dash-test:foo/bar", host: "foo", hostname: "foo", protocol: "dash-test:", pathname: "/bar", path: "/bar", }, "dot.test://foo/bar": { href: "dot.test://foo/bar", host: "foo", hostname: "foo", protocol: "dot.test:", pathname: "/bar", path: "/bar", slashes: true, }, "dot.test:foo/bar": { href: "dot.test:foo/bar", host: "foo", hostname: "foo", protocol: "dot.test:", pathname: "/bar", path: "/bar", }, // IDNA tests "http://www.日本語.com/": { href: "http://www.xn--wgv71a119e.com/", protocol: "http:", slashes: true, host: "www.xn--wgv71a119e.com", hostname: "www.xn--wgv71a119e.com", pathname: "/", path: "/", }, "http://example.Bücher.com/": { href: "http://example.xn--bcher-kva.com/", protocol: "http:", slashes: true, host: "example.xn--bcher-kva.com", hostname: "example.xn--bcher-kva.com", pathname: "/", path: "/", }, "http://www.Äffchen.com/": { href: "http://www.xn--ffchen-9ta.com/", protocol: "http:", slashes: true, host: "www.xn--ffchen-9ta.com", hostname: "www.xn--ffchen-9ta.com", pathname: "/", path: "/", }, "http://www.Äffchen.cOm;A/b/c?d=e#f gi": { href: "http://www.xn--ffchen-9ta.com/;A/b/c?d=e#f%20g%3Ch%3Ei", protocol: "http:", slashes: true, host: "www.xn--ffchen-9ta.com", hostname: "www.xn--ffchen-9ta.com", pathname: ";A/b/c", search: "?d=e", query: "d=e", hash: "#f%20g%3Ch%3Ei", path: ";A/b/c?d=e", }, "http://SÉLIER.COM/": { href: "http://xn--slier-bsa.com/", protocol: "http:", slashes: true, host: "xn--slier-bsa.com", hostname: "xn--slier-bsa.com", pathname: "/", path: "/", }, "http://ليهمابتكلموشعربي؟.ي؟/": { href: "http://xn--egbpdaj6bu4bxfgehfvwxn.xn--egb9f/", protocol: "http:", slashes: true, host: "xn--egbpdaj6bu4bxfgehfvwxn.xn--egb9f", hostname: "xn--egbpdaj6bu4bxfgehfvwxn.xn--egb9f", pathname: "/", path: "/", }, "http://➡.ws/➡": { href: "http://xn--hgi.ws/➡", protocol: "http:", slashes: true, host: "xn--hgi.ws", hostname: "xn--hgi.ws", pathname: "/➡", path: "/➡", }, "http://bucket_name.s3.amazonaws.com/image.jpg": { protocol: "http:", slashes: true, host: "bucket_name.s3.amazonaws.com", hostname: "bucket_name.s3.amazonaws.com", pathname: "/image.jpg", href: "http://bucket_name.s3.amazonaws.com/image.jpg", path: "/image.jpg", }, "git+http://github.com/joyent/node.git": { protocol: "git+http:", slashes: true, host: "github.com", hostname: "github.com", pathname: "/joyent/node.git", path: "/joyent/node.git", href: "git+http://github.com/joyent/node.git", }, // If local1@domain1 is uses as a relative URL it may // be parse into auth@hostname, but here there is no // way to make it work in URL.parse, I add the test to be explicit "local1@domain1": { pathname: "local1@domain1", path: "local1@domain1", href: "local1@domain1", }, // While this may seem counter-intuitive, a browser will parse // as a path. "www.example.com": { href: "www.example.com", pathname: "www.example.com", path: "www.example.com", }, // ipv6 support "[fe80::1]": { href: "[fe80::1]", pathname: "[fe80::1]", path: "[fe80::1]", }, "coap://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]": { protocol: "coap:", slashes: true, host: "[fedc:ba98:7654:3210:fedc:ba98:7654:3210]", hostname: "fedc:ba98:7654:3210:fedc:ba98:7654:3210", href: "coap://[fedc:ba98:7654:3210:fedc:ba98:7654:3210]/", pathname: "/", path: "/", }, // TODO: Support parsing this. // // "coap://[1080:0:0:0:8:800:200C:417A]:61616/": { // protocol: "coap:", // slashes: true, // host: "[1080:0:0:0:8:800:200c:417a]:61616", // port: "61616", // hostname: "1080:0:0:0:8:800:200c:417a", // href: "coap://[1080:0:0:0:8:800:200c:417a]:61616/", // pathname: "/", // path: "/", // }, "http://user:password@[3ffe:2a00:100:7031::1]:8080": { protocol: "http:", slashes: true, auth: "user:password", host: "[3ffe:2a00:100:7031::1]:8080", port: "8080", hostname: "3ffe:2a00:100:7031::1", href: "http://user:password@[3ffe:2a00:100:7031::1]:8080/", pathname: "/", path: "/", }, // TODO: Support parsing this. // // "coap://u:p@[::192.9.5.5]:61616/.well-known/r?n=Temperature": { // protocol: "coap:", // slashes: true, // auth: "u:p", // host: "[::192.9.5.5]:61616", // port: "61616", // hostname: "::192.9.5.5", // href: "coap://u:p@[::192.9.5.5]:61616/.well-known/r?n=Temperature", // search: "?n=Temperature", // query: "n=Temperature", // pathname: "/.well-known/r", // path: "/.well-known/r?n=Temperature", // }, // empty port "http://example.com:": { protocol: "http:", slashes: true, host: "example.com", hostname: "example.com", href: "http://example.com/", pathname: "/", path: "/", }, "http://example.com:/a/b.html": { protocol: "http:", slashes: true, host: "example.com", hostname: "example.com", href: "http://example.com/a/b.html", pathname: "/a/b.html", path: "/a/b.html", }, "http://example.com:?a=b": { protocol: "http:", slashes: true, host: "example.com", hostname: "example.com", href: "http://example.com/?a=b", search: "?a=b", query: "a=b", pathname: "/", path: "/?a=b", }, "http://example.com:#abc": { protocol: "http:", slashes: true, host: "example.com", hostname: "example.com", href: "http://example.com/#abc", hash: "#abc", pathname: "/", path: "/", }, "http://[fe80::1]:/a/b?a=b#abc": { protocol: "http:", slashes: true, host: "[fe80::1]", hostname: "fe80::1", href: "http://[fe80::1]/a/b?a=b#abc", search: "?a=b", query: "a=b", hash: "#abc", pathname: "/a/b", path: "/a/b?a=b", }, "http://-lovemonsterz.tumblr.com/rss": { protocol: "http:", slashes: true, host: "-lovemonsterz.tumblr.com", hostname: "-lovemonsterz.tumblr.com", href: "http://-lovemonsterz.tumblr.com/rss", pathname: "/rss", path: "/rss", }, "http://-lovemonsterz.tumblr.com:80/rss": { protocol: "http:", slashes: true, port: "80", host: "-lovemonsterz.tumblr.com:80", hostname: "-lovemonsterz.tumblr.com", href: "http://-lovemonsterz.tumblr.com:80/rss", pathname: "/rss", path: "/rss", }, "http://user:pass@-lovemonsterz.tumblr.com/rss": { protocol: "http:", slashes: true, auth: "user:pass", host: "-lovemonsterz.tumblr.com", hostname: "-lovemonsterz.tumblr.com", href: "http://user:pass@-lovemonsterz.tumblr.com/rss", pathname: "/rss", path: "/rss", }, "http://user:pass@-lovemonsterz.tumblr.com:80/rss": { protocol: "http:", slashes: true, auth: "user:pass", port: "80", host: "-lovemonsterz.tumblr.com:80", hostname: "-lovemonsterz.tumblr.com", href: "http://user:pass@-lovemonsterz.tumblr.com:80/rss", pathname: "/rss", path: "/rss", }, "http://_jabber._tcp.google.com/test": { protocol: "http:", slashes: true, host: "_jabber._tcp.google.com", hostname: "_jabber._tcp.google.com", href: "http://_jabber._tcp.google.com/test", pathname: "/test", path: "/test", }, "http://user:pass@_jabber._tcp.google.com/test": { protocol: "http:", slashes: true, auth: "user:pass", host: "_jabber._tcp.google.com", hostname: "_jabber._tcp.google.com", href: "http://user:pass@_jabber._tcp.google.com/test", pathname: "/test", path: "/test", }, "http://_jabber._tcp.google.com:80/test": { protocol: "http:", slashes: true, port: "80", host: "_jabber._tcp.google.com:80", hostname: "_jabber._tcp.google.com", href: "http://_jabber._tcp.google.com:80/test", pathname: "/test", path: "/test", }, "http://user:pass@_jabber._tcp.google.com:80/test": { protocol: "http:", slashes: true, auth: "user:pass", port: "80", host: "_jabber._tcp.google.com:80", hostname: "_jabber._tcp.google.com", href: "http://user:pass@_jabber._tcp.google.com:80/test", pathname: "/test", path: "/test", }, "http://x:1/' <>\"`/{}|\\^~`/": { protocol: "http:", slashes: true, host: "x:1", port: "1", hostname: "x", pathname: "/%27%20%3C%3E%22%60/%7B%7D%7C/%5E~%60/", path: "/%27%20%3C%3E%22%60/%7B%7D%7C/%5E~%60/", href: "http://x:1/%27%20%3C%3E%22%60/%7B%7D%7C/%5E~%60/", }, "http://a@b@c/": { protocol: "http:", slashes: true, auth: "a@b", host: "c", hostname: "c", href: "http://a%40b@c/", path: "/", pathname: "/", }, "http://a@b?@c": { protocol: "http:", slashes: true, auth: "a", host: "b", hostname: "b", href: "http://a@b/?@c", path: "/?@c", pathname: "/", search: "?@c", query: "@c", }, // TODO: Support parsing these. // // "http://a.b/\tbc\ndr\ref g\"hq'j?mn\\op^q=r`99{st|uv}wz": { // protocol: "http:", // slashes: true, // host: "a.b", // port: null, // hostname: "a.b", // hash: null, // pathname: "/%09bc%0Adr%0Def%20g%22hq%27j%3Ckl%3E", // path: "/%09bc%0Adr%0Def%20g%22hq%27j%3Ckl%3E?mn%5Cop%5Eq=r%6099%7Bst%7Cuv%7Dwz", // search: "?mn%5Cop%5Eq=r%6099%7Bst%7Cuv%7Dwz", // query: "mn%5Cop%5Eq=r%6099%7Bst%7Cuv%7Dwz", // href: "http://a.b/%09bc%0Adr%0Def%20g%22hq%27j%3Ckl%3E?mn%5Cop%5Eq=r%6099%7Bst%7Cuv%7Dwz", // }, // "http://a\r\" \t\n<'b:b@c\r\nd/e?f": { // protocol: "http:", // slashes: true, // auth: "a\" <'b:b", // host: "cd", // port: null, // hostname: "cd", // hash: null, // search: "?f", // query: "f", // pathname: "/e", // path: "/e?f", // href: "http://a%22%20%3C'b:b@cd/e?f", // }, // Git urls used by npm "git+ssh://git@github.com:npm/npm": { protocol: "git+ssh:", slashes: true, auth: "git", host: "github.com", port: null, hostname: "github.com", hash: null, search: null, query: null, pathname: "/:npm/npm", path: "/:npm/npm", href: "git+ssh://git@github.com/:npm/npm", }, // TODO: Support parsing these. // // "https://*": { // protocol: "https:", // slashes: true, // auth: null, // host: "*", // port: null, // hostname: "*", // hash: null, // search: null, // query: null, // pathname: "/", // path: "/", // href: "https://*/", // }, // The following two URLs are the same, but they differ for a capital A. // Verify that the protocol is checked in a case-insensitive manner. // "javascript:alert(1);a=\x27@white-listed.com\x27": { // protocol: "javascript:", // slashes: null, // auth: null, // host: null, // port: null, // hostname: null, // hash: null, // search: null, // query: null, // pathname: "alert(1);a='@white-listed.com'", // path: "alert(1);a='@white-listed.com'", // href: "javascript:alert(1);a='@white-listed.com'", // }, // "javAscript:alert(1);a=\x27@white-listed.com\x27": { // protocol: "javascript:", // slashes: null, // auth: null, // host: null, // port: null, // hostname: null, // hash: null, // search: null, // query: null, // pathname: "alert(1);a='@white-listed.com'", // path: "alert(1);a='@white-listed.com'", // href: "javascript:alert(1);a='@white-listed.com'", // }, // "ws://www.example.com": { // protocol: "ws:", // slashes: true, // hostname: "www.example.com", // host: "www.example.com", // pathname: "/", // path: "/", // href: "ws://www.example.com/", // }, // "wss://www.example.com": { // protocol: "wss:", // slashes: true, // hostname: "www.example.com", // host: "www.example.com", // pathname: "/", // path: "/", // href: "wss://www.example.com/", // }, // "//fhqwhgads@example.com/everybody-to-the-limit": { // protocol: null, // slashes: true, // auth: "fhqwhgads", // host: "example.com", // port: null, // hostname: "example.com", // hash: null, // search: null, // query: null, // pathname: "/everybody-to-the-limit", // path: "/everybody-to-the-limit", // href: "//fhqwhgads@example.com/everybody-to-the-limit", // }, "//fhqwhgads@example.com/everybody#to-the-limit": { protocol: null, slashes: true, auth: "fhqwhgads", host: "example.com", port: null, hostname: "example.com", hash: "#to-the-limit", search: null, query: null, pathname: "/everybody", path: "/everybody", href: "//fhqwhgads@example.com/everybody#to-the-limit", }, // TODO: Support parsing these. // // "\bhttp://example.com/\b": { // protocol: "http:", // slashes: true, // auth: null, // host: "example.com", // port: null, // hostname: "example.com", // hash: null, // search: null, // query: null, // pathname: "/", // path: "/", // href: "http://example.com/", // }, // "https://evil.com$.example.com": { // protocol: "https:", // slashes: true, // auth: null, // host: "evil.com$.example.com", // port: null, // hostname: "evil.com$.example.com", // hash: null, // search: null, // query: null, // pathname: "/", // path: "/", // href: "https://evil.com$.example.com/", // }, // Validate the output of hostname with commas. // "x://0.0,1.1/": { // protocol: "x:", // slashes: true, // auth: null, // host: "0.0,1.1", // port: null, // hostname: "0.0,1.1", // hash: null, // search: null, // query: null, // pathname: "/", // path: "/", // href: "x://0.0,1.1/", // }, }; test("url.parse", () => { for (const u in parseTests) { let actual = url.parse(u); const spaced = url.parse(` \t ${u}\n\t`); let expected = Object.assign(new url.Url(), parseTests[u]); Object.keys(actual).forEach(function (i) { if (expected[i] === undefined && actual[i] === null) { expected[i] = null; } }); assert.deepStrictEqual( actual, expected, `parsing ${u} and expected ${inspect(expected)} but got ${inspect(actual)}`, ); assert.deepStrictEqual(spaced, expected, `expected ${inspect(expected)}, got ${inspect(spaced)}`); } }); test("url.format", () => { for (const u in parseTests) { const expected = parseTests[u].href; const actual = url.format(parseTests[u]); assert.strictEqual(actual, expected, `format(${u}) == ${u}\nactual:${actual}`); } }); // TODO: Support parsing this. test.todo("xss", () => { const parsed = url.parse("http://nodejs.org/").resolveObject("jAvascript:alert(1);a=\x27@white-listed.com\x27"); const expected = Object.assign(new url.Url(), { protocol: "javascript:", slashes: null, auth: null, host: null, port: null, hostname: null, hash: null, search: null, query: null, pathname: "alert(1);a='@white-listed.com'", path: "alert(1);a='@white-listed.com'", href: "javascript:alert(1);a='@white-listed.com'", }); assert.deepStrictEqual(parsed, expected); }); });