'use strict'; require('../common'); const assert = require('assert'); const url = require('url'); // Formatting tests to verify that it'll format slightly wonky content to a // valid URL. const formatTests = { 'http://example.com?': { href: 'http://example.com/?', protocol: 'http:', slashes: true, host: 'example.com', hostname: 'example.com', search: '?', query: {}, pathname: '/' }, 'http://example.com?foo=bar#frag': { href: 'http://example.com/?foo=bar#frag', protocol: 'http:', host: 'example.com', hostname: 'example.com', hash: '#frag', search: '?foo=bar', query: 'foo=bar', pathname: '/' }, 'http://example.com?foo=@bar#frag': { href: 'http://example.com/?foo=@bar#frag', protocol: 'http:', host: 'example.com', hostname: 'example.com', hash: '#frag', search: '?foo=@bar', query: 'foo=@bar', pathname: '/' }, 'http://example.com?foo=/bar/#frag': { href: 'http://example.com/?foo=/bar/#frag', protocol: 'http:', host: 'example.com', hostname: 'example.com', hash: '#frag', search: '?foo=/bar/', query: 'foo=/bar/', pathname: '/' }, 'http://example.com?foo=?bar/#frag': { href: 'http://example.com/?foo=?bar/#frag', protocol: 'http:', host: 'example.com', hostname: 'example.com', hash: '#frag', search: '?foo=?bar/', query: 'foo=?bar/', pathname: '/' }, 'http://example.com#frag=?bar/#frag': { href: 'http://example.com/#frag=?bar/#frag', protocol: 'http:', host: 'example.com', hostname: 'example.com', hash: '#frag=?bar/#frag', pathname: '/' }, 'http://google.com" onload="alert(42)/': { href: 'http://google.com/%22%20onload=%22alert(42)/', protocol: 'http:', host: 'google.com', pathname: '/%22%20onload=%22alert(42)/' }, 'http://a.com/a/b/c?s#h': { href: 'http://a.com/a/b/c?s#h', protocol: 'http', host: 'a.com', pathname: 'a/b/c', hash: 'h', search: 's' }, '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/': { href: 'http://atpass:foo%40bar@127.0.0.1/', auth: 'atpass:foo@bar', hostname: '127.0.0.1', protocol: 'http:', pathname: '/' }, 'http://atslash%2F%40:%2F%40@foo/': { href: 'http://atslash%2F%40:%2F%40@foo/', auth: 'atslash/@:/@', hostname: 'foo', protocol: 'http:', pathname: '/' }, 'svn+ssh://foo/bar': { href: 'svn+ssh://foo/bar', hostname: 'foo', protocol: 'svn+ssh:', pathname: '/bar', slashes: true }, 'dash-test://foo/bar': { href: 'dash-test://foo/bar', hostname: 'foo', protocol: 'dash-test:', pathname: '/bar', slashes: true }, 'dash-test:foo/bar': { href: 'dash-test:foo/bar', hostname: 'foo', protocol: 'dash-test:', pathname: '/bar' }, 'dot.test://foo/bar': { href: 'dot.test://foo/bar', hostname: 'foo', protocol: 'dot.test:', pathname: '/bar', slashes: true }, 'dot.test:foo/bar': { href: 'dot.test:foo/bar', hostname: 'foo', protocol: 'dot.test:', pathname: '/bar' }, // IPv6 support 'coap:u:p@[::1]:61616/.well-known/r?n=Temperature': { href: 'coap:u:p@[::1]:61616/.well-known/r?n=Temperature', protocol: 'coap:', auth: 'u:p', hostname: '::1', port: '61616', pathname: '/.well-known/r', search: 'n=Temperature' }, 'coap:[fedc:ba98:7654:3210:fedc:ba98:7654:3210]:61616/s/stopButton': { href: 'coap:[fedc:ba98:7654:3210:fedc:ba98:7654:3210]:61616/s/stopButton', protocol: 'coap', host: '[fedc:ba98:7654:3210:fedc:ba98:7654:3210]:61616', pathname: '/s/stopButton' }, // Encode context-specific delimiters in path and query, but do not touch // other non-delimiter chars like `%`. // // `#`,`?` in path '/path/to/%%23%3F+=&.txt?foo=theA1#bar': { href: '/path/to/%%23%3F+=&.txt?foo=theA1#bar', pathname: '/path/to/%#?+=&.txt', query: { foo: 'theA1' }, hash: '#bar' }, // `#`,`?` in path + `#` in query '/path/to/%%23%3F+=&.txt?foo=the%231#bar': { href: '/path/to/%%23%3F+=&.txt?foo=the%231#bar', pathname: '/path/to/%#?+=&.txt', query: { foo: 'the#1' }, hash: '#bar' }, // `#` in path end + `#` in query '/path/to/%%23?foo=the%231#bar': { href: '/path/to/%%23?foo=the%231#bar', pathname: '/path/to/%#', query: { foo: 'the#1' }, hash: '#bar' }, // `?` and `#` in path and search 'http://ex.com/foo%3F100%m%23r?abc=the%231?&foo=bar#frag': { href: 'http://ex.com/foo%3F100%m%23r?abc=the%231?&foo=bar#frag', protocol: 'http:', hostname: 'ex.com', hash: '#frag', search: '?abc=the#1?&foo=bar', pathname: '/foo?100%m#r', }, // `?` and `#` in search only 'http://ex.com/fooA100%mBr?abc=the%231?&foo=bar#frag': { href: 'http://ex.com/fooA100%mBr?abc=the%231?&foo=bar#frag', protocol: 'http:', hostname: 'ex.com', hash: '#frag', search: '?abc=the#1?&foo=bar', pathname: '/fooA100%mBr', }, // multiple `#` in search 'http://example.com/?foo=bar%231%232%233&abc=%234%23%235#frag': { href: 'http://example.com/?foo=bar%231%232%233&abc=%234%23%235#frag', protocol: 'http:', slashes: true, host: 'example.com', hostname: 'example.com', hash: '#frag', search: '?foo=bar#1#2#3&abc=#4##5', query: {}, pathname: '/' }, // More than 255 characters in hostname which exceeds the limit [`http://${'a'.repeat(255)}.com/node`]: { href: 'http:///node', protocol: 'http:', slashes: true, host: '', hostname: '', pathname: '/node', path: '/node' }, // Greater than or equal to 63 characters after `.` in hostname [`http://www.${'z'.repeat(63)}example.com/node`]: { href: `http://www.${'z'.repeat(63)}example.com/node`, protocol: 'http:', slashes: true, host: `www.${'z'.repeat(63)}example.com`, hostname: `www.${'z'.repeat(63)}example.com`, pathname: '/node', path: '/node' }, // https://github.com/nodejs/node/issues/3361 'file:///home/user': { href: 'file:///home/user', protocol: 'file', pathname: '/home/user', path: '/home/user' }, // surrogate in auth 'http://%F0%9F%98%80@www.example.com/': { href: 'http://%F0%9F%98%80@www.example.com/', protocol: 'http:', auth: '\uD83D\uDE00', hostname: 'www.example.com', pathname: '/' } }; for (const u in formatTests) { const expect = formatTests[u].href; delete formatTests[u].href; const actual = url.format(u); const actualObj = url.format(formatTests[u]); assert.strictEqual(actual, expect, `wonky format(${u}) == ${expect}\nactual:${actual}`); assert.strictEqual(actualObj, expect, `wonky format(${JSON.stringify(formatTests[u])}) == ${ expect}\nactual: ${actualObj}`); }