1'use strict'; 2const common = require('../common'); 3const assert = require('assert'); 4const url = require('url'); 5 6if (!common.hasIntl) 7 common.skip('missing Intl'); 8 9// Formatting tests to verify that it'll format slightly wonky content to a 10// valid URL. 11const formatTests = { 12 'http://example.com?': { 13 href: 'http://example.com/?', 14 protocol: 'http:', 15 slashes: true, 16 host: 'example.com', 17 hostname: 'example.com', 18 search: '?', 19 query: {}, 20 pathname: '/' 21 }, 22 'http://example.com?foo=bar#frag': { 23 href: 'http://example.com/?foo=bar#frag', 24 protocol: 'http:', 25 host: 'example.com', 26 hostname: 'example.com', 27 hash: '#frag', 28 search: '?foo=bar', 29 query: 'foo=bar', 30 pathname: '/' 31 }, 32 'http://example.com?foo=@bar#frag': { 33 href: 'http://example.com/?foo=@bar#frag', 34 protocol: 'http:', 35 host: 'example.com', 36 hostname: 'example.com', 37 hash: '#frag', 38 search: '?foo=@bar', 39 query: 'foo=@bar', 40 pathname: '/' 41 }, 42 'http://example.com?foo=/bar/#frag': { 43 href: 'http://example.com/?foo=/bar/#frag', 44 protocol: 'http:', 45 host: 'example.com', 46 hostname: 'example.com', 47 hash: '#frag', 48 search: '?foo=/bar/', 49 query: 'foo=/bar/', 50 pathname: '/' 51 }, 52 'http://example.com?foo=?bar/#frag': { 53 href: 'http://example.com/?foo=?bar/#frag', 54 protocol: 'http:', 55 host: 'example.com', 56 hostname: 'example.com', 57 hash: '#frag', 58 search: '?foo=?bar/', 59 query: 'foo=?bar/', 60 pathname: '/' 61 }, 62 'http://example.com#frag=?bar/#frag': { 63 href: 'http://example.com/#frag=?bar/#frag', 64 protocol: 'http:', 65 host: 'example.com', 66 hostname: 'example.com', 67 hash: '#frag=?bar/#frag', 68 pathname: '/' 69 }, 70 'http://google.com" onload="alert(42)/': { 71 href: 'http://google.com/%22%20onload=%22alert(42)/', 72 protocol: 'http:', 73 host: 'google.com', 74 pathname: '/%22%20onload=%22alert(42)/' 75 }, 76 'http://a.com/a/b/c?s#h': { 77 href: 'http://a.com/a/b/c?s#h', 78 protocol: 'http', 79 host: 'a.com', 80 pathname: 'a/b/c', 81 hash: 'h', 82 search: 's' 83 }, 84 'xmpp:isaacschlueter@jabber.org': { 85 href: 'xmpp:isaacschlueter@jabber.org', 86 protocol: 'xmpp:', 87 host: 'jabber.org', 88 auth: 'isaacschlueter', 89 hostname: 'jabber.org' 90 }, 91 'http://atpass:foo%40bar@127.0.0.1/': { 92 href: 'http://atpass:foo%40bar@127.0.0.1/', 93 auth: 'atpass:foo@bar', 94 hostname: '127.0.0.1', 95 protocol: 'http:', 96 pathname: '/' 97 }, 98 'http://atslash%2F%40:%2F%40@foo/': { 99 href: 'http://atslash%2F%40:%2F%40@foo/', 100 auth: 'atslash/@:/@', 101 hostname: 'foo', 102 protocol: 'http:', 103 pathname: '/' 104 }, 105 'svn+ssh://foo/bar': { 106 href: 'svn+ssh://foo/bar', 107 hostname: 'foo', 108 protocol: 'svn+ssh:', 109 pathname: '/bar', 110 slashes: true 111 }, 112 'dash-test://foo/bar': { 113 href: 'dash-test://foo/bar', 114 hostname: 'foo', 115 protocol: 'dash-test:', 116 pathname: '/bar', 117 slashes: true 118 }, 119 'dash-test:foo/bar': { 120 href: 'dash-test:foo/bar', 121 hostname: 'foo', 122 protocol: 'dash-test:', 123 pathname: '/bar' 124 }, 125 'dot.test://foo/bar': { 126 href: 'dot.test://foo/bar', 127 hostname: 'foo', 128 protocol: 'dot.test:', 129 pathname: '/bar', 130 slashes: true 131 }, 132 'dot.test:foo/bar': { 133 href: 'dot.test:foo/bar', 134 hostname: 'foo', 135 protocol: 'dot.test:', 136 pathname: '/bar' 137 }, 138 // IPv6 support 139 'coap:u:p@[::1]:61616/.well-known/r?n=Temperature': { 140 href: 'coap:u:p@[::1]:61616/.well-known/r?n=Temperature', 141 protocol: 'coap:', 142 auth: 'u:p', 143 hostname: '::1', 144 port: '61616', 145 pathname: '/.well-known/r', 146 search: 'n=Temperature' 147 }, 148 'coap:[fedc:ba98:7654:3210:fedc:ba98:7654:3210]:61616/s/stopButton': { 149 href: 'coap:[fedc:ba98:7654:3210:fedc:ba98:7654:3210]:61616/s/stopButton', 150 protocol: 'coap', 151 host: '[fedc:ba98:7654:3210:fedc:ba98:7654:3210]:61616', 152 pathname: '/s/stopButton' 153 }, 154 'http://[::]/': { 155 href: 'http://[::]/', 156 protocol: 'http:', 157 hostname: '[::]', 158 pathname: '/' 159 }, 160 161 // Encode context-specific delimiters in path and query, but do not touch 162 // other non-delimiter chars like `%`. 163 // <https://github.com/nodejs/node-v0.x-archive/issues/4082> 164 165 // `#`,`?` in path 166 '/path/to/%%23%3F+=&.txt?foo=theA1#bar': { 167 href: '/path/to/%%23%3F+=&.txt?foo=theA1#bar', 168 pathname: '/path/to/%#?+=&.txt', 169 query: { 170 foo: 'theA1' 171 }, 172 hash: '#bar' 173 }, 174 175 // `#`,`?` in path + `#` in query 176 '/path/to/%%23%3F+=&.txt?foo=the%231#bar': { 177 href: '/path/to/%%23%3F+=&.txt?foo=the%231#bar', 178 pathname: '/path/to/%#?+=&.txt', 179 query: { 180 foo: 'the#1' 181 }, 182 hash: '#bar' 183 }, 184 185 // `#` in path end + `#` in query 186 '/path/to/%%23?foo=the%231#bar': { 187 href: '/path/to/%%23?foo=the%231#bar', 188 pathname: '/path/to/%#', 189 query: { 190 foo: 'the#1' 191 }, 192 hash: '#bar' 193 }, 194 195 // `?` and `#` in path and search 196 'http://ex.com/foo%3F100%m%23r?abc=the%231?&foo=bar#frag': { 197 href: 'http://ex.com/foo%3F100%m%23r?abc=the%231?&foo=bar#frag', 198 protocol: 'http:', 199 hostname: 'ex.com', 200 hash: '#frag', 201 search: '?abc=the#1?&foo=bar', 202 pathname: '/foo?100%m#r', 203 }, 204 205 // `?` and `#` in search only 206 'http://ex.com/fooA100%mBr?abc=the%231?&foo=bar#frag': { 207 href: 'http://ex.com/fooA100%mBr?abc=the%231?&foo=bar#frag', 208 protocol: 'http:', 209 hostname: 'ex.com', 210 hash: '#frag', 211 search: '?abc=the#1?&foo=bar', 212 pathname: '/fooA100%mBr', 213 }, 214 215 // Multiple `#` in search 216 'http://example.com/?foo=bar%231%232%233&abc=%234%23%235#frag': { 217 href: 'http://example.com/?foo=bar%231%232%233&abc=%234%23%235#frag', 218 protocol: 'http:', 219 slashes: true, 220 host: 'example.com', 221 hostname: 'example.com', 222 hash: '#frag', 223 search: '?foo=bar#1#2#3&abc=#4##5', 224 query: {}, 225 pathname: '/' 226 }, 227 228 // More than 255 characters in hostname which exceeds the limit 229 [`http://${'a'.repeat(255)}.com/node`]: { 230 href: 'http:///node', 231 protocol: 'http:', 232 slashes: true, 233 host: '', 234 hostname: '', 235 pathname: '/node', 236 path: '/node' 237 }, 238 239 // Greater than or equal to 63 characters after `.` in hostname 240 [`http://www.${'z'.repeat(63)}example.com/node`]: { 241 href: `http://www.${'z'.repeat(63)}example.com/node`, 242 protocol: 'http:', 243 slashes: true, 244 host: `www.${'z'.repeat(63)}example.com`, 245 hostname: `www.${'z'.repeat(63)}example.com`, 246 pathname: '/node', 247 path: '/node' 248 }, 249 250 // https://github.com/nodejs/node/issues/3361 251 'file:///home/user': { 252 href: 'file:///home/user', 253 protocol: 'file', 254 pathname: '/home/user', 255 path: '/home/user' 256 }, 257 258 // surrogate in auth 259 'http://%F0%9F%98%80@www.example.com/': { 260 href: 'http://%F0%9F%98%80@www.example.com/', 261 protocol: 'http:', 262 auth: '\uD83D\uDE00', 263 hostname: 'www.example.com', 264 pathname: '/' 265 } 266}; 267for (const u in formatTests) { 268 const expect = formatTests[u].href; 269 delete formatTests[u].href; 270 const actual = url.format(u); 271 const actualObj = url.format(formatTests[u]); 272 assert.strictEqual(actual, expect, 273 `wonky format(${u}) == ${expect}\nactual:${actual}`); 274 assert.strictEqual(actualObj, expect, 275 `wonky format(${JSON.stringify(formatTests[u])}) == ${ 276 expect}\nactual: ${actualObj}`); 277} 278