|
@ -6,6 +6,7 @@ const { |
|
|
isHexTable |
|
|
isHexTable |
|
|
} = require('internal/querystring'); |
|
|
} = require('internal/querystring'); |
|
|
const { getConstructorOf } = require('internal/util'); |
|
|
const { getConstructorOf } = require('internal/util'); |
|
|
|
|
|
const errors = require('internal/errors'); |
|
|
const binding = process.binding('url'); |
|
|
const binding = process.binding('url'); |
|
|
const context = Symbol('context'); |
|
|
const context = Symbol('context'); |
|
|
const cannotBeBase = Symbol('cannot-be-base'); |
|
|
const cannotBeBase = Symbol('cannot-be-base'); |
|
@ -14,9 +15,9 @@ const cannotHaveUsernamePasswordPort = |
|
|
const special = Symbol('special'); |
|
|
const special = Symbol('special'); |
|
|
const searchParams = Symbol('query'); |
|
|
const searchParams = Symbol('query'); |
|
|
const querystring = require('querystring'); |
|
|
const querystring = require('querystring'); |
|
|
const os = require('os'); |
|
|
|
|
|
|
|
|
|
|
|
const isWindows = process.platform === 'win32'; |
|
|
const { platform } = process; |
|
|
|
|
|
const isWindows = platform === 'win32'; |
|
|
|
|
|
|
|
|
const kFormat = Symbol('format'); |
|
|
const kFormat = Symbol('format'); |
|
|
|
|
|
|
|
@ -88,7 +89,7 @@ function onParseComplete(flags, protocol, username, password, |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function onParseError(flags, input) { |
|
|
function onParseError(flags, input) { |
|
|
const error = new TypeError('Invalid URL: ' + input); |
|
|
const error = new errors.TypeError('ERR_INVALID_URL', input); |
|
|
error.input = input; |
|
|
error.input = input; |
|
|
throw error; |
|
|
throw error; |
|
|
} |
|
|
} |
|
@ -202,7 +203,7 @@ class URL { |
|
|
[util.inspect.custom](depth, opts) { |
|
|
[util.inspect.custom](depth, opts) { |
|
|
if (this == null || |
|
|
if (this == null || |
|
|
Object.getPrototypeOf(this[context]) !== URLContext.prototype) { |
|
|
Object.getPrototypeOf(this[context]) !== URLContext.prototype) { |
|
|
throw new TypeError('Value of `this` is not a URL'); |
|
|
throw new errors.TypeError('ERR_INVALID_THIS', 'URL'); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const ctx = this[context]; |
|
|
const ctx = this[context]; |
|
@ -247,7 +248,7 @@ Object.defineProperties(URL.prototype, { |
|
|
// eslint-disable-next-line func-name-matching
|
|
|
// eslint-disable-next-line func-name-matching
|
|
|
value: function format(options) { |
|
|
value: function format(options) { |
|
|
if (options && typeof options !== 'object') |
|
|
if (options && typeof options !== 'object') |
|
|
throw new TypeError('options must be an object'); |
|
|
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'options', 'object'); |
|
|
options = Object.assign({ |
|
|
options = Object.assign({ |
|
|
fragment: true, |
|
|
fragment: true, |
|
|
unicode: false, |
|
|
unicode: false, |
|
@ -810,7 +811,7 @@ class URLSearchParams { |
|
|
this[searchParams] = childParams.slice(); |
|
|
this[searchParams] = childParams.slice(); |
|
|
} else if (method !== null && method !== undefined) { |
|
|
} else if (method !== null && method !== undefined) { |
|
|
if (typeof method !== 'function') { |
|
|
if (typeof method !== 'function') { |
|
|
throw new TypeError('Query pairs must be iterable'); |
|
|
throw new errors.TypeError('ERR_ARG_NOT_ITERABLE', 'Query pairs'); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// sequence<sequence<USVString>>
|
|
|
// sequence<sequence<USVString>>
|
|
@ -819,7 +820,8 @@ class URLSearchParams { |
|
|
for (const pair of init) { |
|
|
for (const pair of init) { |
|
|
if (typeof pair !== 'object' || |
|
|
if (typeof pair !== 'object' || |
|
|
typeof pair[Symbol.iterator] !== 'function') { |
|
|
typeof pair[Symbol.iterator] !== 'function') { |
|
|
throw new TypeError('Each query pair must be iterable'); |
|
|
throw new errors.TypeError('ERR_INVALID_TUPLE', 'Each query pair', |
|
|
|
|
|
'[name, value]'); |
|
|
} |
|
|
} |
|
|
pairs.push(Array.from(pair)); |
|
|
pairs.push(Array.from(pair)); |
|
|
} |
|
|
} |
|
@ -827,7 +829,8 @@ class URLSearchParams { |
|
|
this[searchParams] = []; |
|
|
this[searchParams] = []; |
|
|
for (const pair of pairs) { |
|
|
for (const pair of pairs) { |
|
|
if (pair.length !== 2) { |
|
|
if (pair.length !== 2) { |
|
|
throw new TypeError('Each query pair must be a name/value tuple'); |
|
|
throw new errors.TypeError('ERR_INVALID_TUPLE', 'Each query pair', |
|
|
|
|
|
'[name, value]'); |
|
|
} |
|
|
} |
|
|
const key = toUSVString(pair[0]); |
|
|
const key = toUSVString(pair[0]); |
|
|
const value = toUSVString(pair[1]); |
|
|
const value = toUSVString(pair[1]); |
|
@ -855,7 +858,7 @@ class URLSearchParams { |
|
|
|
|
|
|
|
|
[util.inspect.custom](recurseTimes, ctx) { |
|
|
[util.inspect.custom](recurseTimes, ctx) { |
|
|
if (!this || !this[searchParams] || this[searchParams][searchParams]) { |
|
|
if (!this || !this[searchParams] || this[searchParams][searchParams]) { |
|
|
throw new TypeError('Value of `this` is not a URLSearchParams'); |
|
|
throw new errors.TypeError('ERR_INVALID_THIS', 'URLSearchParams'); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (typeof recurseTimes === 'number' && recurseTimes < 0) |
|
|
if (typeof recurseTimes === 'number' && recurseTimes < 0) |
|
@ -920,10 +923,10 @@ function merge(out, start, mid, end, lBuffer, rBuffer) { |
|
|
defineIDLClass(URLSearchParams.prototype, 'URLSearchParams', { |
|
|
defineIDLClass(URLSearchParams.prototype, 'URLSearchParams', { |
|
|
append(name, value) { |
|
|
append(name, value) { |
|
|
if (!this || !this[searchParams] || this[searchParams][searchParams]) { |
|
|
if (!this || !this[searchParams] || this[searchParams][searchParams]) { |
|
|
throw new TypeError('Value of `this` is not a URLSearchParams'); |
|
|
throw new errors.TypeError('ERR_INVALID_THIS', 'URLSearchParams'); |
|
|
} |
|
|
} |
|
|
if (arguments.length < 2) { |
|
|
if (arguments.length < 2) { |
|
|
throw new TypeError('"name" and "value" arguments must be specified'); |
|
|
throw new errors.TypeError('ERR_MISSING_ARGS', 'name', 'value'); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
name = toUSVString(name); |
|
|
name = toUSVString(name); |
|
@ -934,10 +937,10 @@ defineIDLClass(URLSearchParams.prototype, 'URLSearchParams', { |
|
|
|
|
|
|
|
|
delete(name) { |
|
|
delete(name) { |
|
|
if (!this || !this[searchParams] || this[searchParams][searchParams]) { |
|
|
if (!this || !this[searchParams] || this[searchParams][searchParams]) { |
|
|
throw new TypeError('Value of `this` is not a URLSearchParams'); |
|
|
throw new errors.TypeError('ERR_INVALID_THIS', 'URLSearchParams'); |
|
|
} |
|
|
} |
|
|
if (arguments.length < 1) { |
|
|
if (arguments.length < 1) { |
|
|
throw new TypeError('"name" argument must be specified'); |
|
|
throw new errors.TypeError('ERR_MISSING_ARGS', 'name'); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const list = this[searchParams]; |
|
|
const list = this[searchParams]; |
|
@ -955,10 +958,10 @@ defineIDLClass(URLSearchParams.prototype, 'URLSearchParams', { |
|
|
|
|
|
|
|
|
get(name) { |
|
|
get(name) { |
|
|
if (!this || !this[searchParams] || this[searchParams][searchParams]) { |
|
|
if (!this || !this[searchParams] || this[searchParams][searchParams]) { |
|
|
throw new TypeError('Value of `this` is not a URLSearchParams'); |
|
|
throw new errors.TypeError('ERR_INVALID_THIS', 'URLSearchParams'); |
|
|
} |
|
|
} |
|
|
if (arguments.length < 1) { |
|
|
if (arguments.length < 1) { |
|
|
throw new TypeError('"name" argument must be specified'); |
|
|
throw new errors.TypeError('ERR_MISSING_ARGS', 'name'); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const list = this[searchParams]; |
|
|
const list = this[searchParams]; |
|
@ -973,10 +976,10 @@ defineIDLClass(URLSearchParams.prototype, 'URLSearchParams', { |
|
|
|
|
|
|
|
|
getAll(name) { |
|
|
getAll(name) { |
|
|
if (!this || !this[searchParams] || this[searchParams][searchParams]) { |
|
|
if (!this || !this[searchParams] || this[searchParams][searchParams]) { |
|
|
throw new TypeError('Value of `this` is not a URLSearchParams'); |
|
|
throw new errors.TypeError('ERR_INVALID_THIS', 'URLSearchParams'); |
|
|
} |
|
|
} |
|
|
if (arguments.length < 1) { |
|
|
if (arguments.length < 1) { |
|
|
throw new TypeError('"name" argument must be specified'); |
|
|
throw new errors.TypeError('ERR_MISSING_ARGS', 'name'); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const list = this[searchParams]; |
|
|
const list = this[searchParams]; |
|
@ -992,10 +995,10 @@ defineIDLClass(URLSearchParams.prototype, 'URLSearchParams', { |
|
|
|
|
|
|
|
|
has(name) { |
|
|
has(name) { |
|
|
if (!this || !this[searchParams] || this[searchParams][searchParams]) { |
|
|
if (!this || !this[searchParams] || this[searchParams][searchParams]) { |
|
|
throw new TypeError('Value of `this` is not a URLSearchParams'); |
|
|
throw new errors.TypeError('ERR_INVALID_THIS', 'URLSearchParams'); |
|
|
} |
|
|
} |
|
|
if (arguments.length < 1) { |
|
|
if (arguments.length < 1) { |
|
|
throw new TypeError('"name" argument must be specified'); |
|
|
throw new errors.TypeError('ERR_MISSING_ARGS', 'name'); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const list = this[searchParams]; |
|
|
const list = this[searchParams]; |
|
@ -1010,10 +1013,10 @@ defineIDLClass(URLSearchParams.prototype, 'URLSearchParams', { |
|
|
|
|
|
|
|
|
set(name, value) { |
|
|
set(name, value) { |
|
|
if (!this || !this[searchParams] || this[searchParams][searchParams]) { |
|
|
if (!this || !this[searchParams] || this[searchParams][searchParams]) { |
|
|
throw new TypeError('Value of `this` is not a URLSearchParams'); |
|
|
throw new errors.TypeError('ERR_INVALID_THIS', 'URLSearchParams'); |
|
|
} |
|
|
} |
|
|
if (arguments.length < 2) { |
|
|
if (arguments.length < 2) { |
|
|
throw new TypeError('"name" and "value" arguments must be specified'); |
|
|
throw new errors.TypeError('ERR_MISSING_ARGS', 'name', 'value'); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const list = this[searchParams]; |
|
|
const list = this[searchParams]; |
|
@ -1098,7 +1101,7 @@ defineIDLClass(URLSearchParams.prototype, 'URLSearchParams', { |
|
|
// must be set to `entries`.
|
|
|
// must be set to `entries`.
|
|
|
entries() { |
|
|
entries() { |
|
|
if (!this || !this[searchParams] || this[searchParams][searchParams]) { |
|
|
if (!this || !this[searchParams] || this[searchParams][searchParams]) { |
|
|
throw new TypeError('Value of `this` is not a URLSearchParams'); |
|
|
throw new errors.TypeError('ERR_INVALID_THIS', 'URLSearchParams'); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return createSearchParamsIterator(this, 'key+value'); |
|
|
return createSearchParamsIterator(this, 'key+value'); |
|
@ -1106,10 +1109,10 @@ defineIDLClass(URLSearchParams.prototype, 'URLSearchParams', { |
|
|
|
|
|
|
|
|
forEach(callback, thisArg = undefined) { |
|
|
forEach(callback, thisArg = undefined) { |
|
|
if (!this || !this[searchParams] || this[searchParams][searchParams]) { |
|
|
if (!this || !this[searchParams] || this[searchParams][searchParams]) { |
|
|
throw new TypeError('Value of `this` is not a URLSearchParams'); |
|
|
throw new errors.TypeError('ERR_INVALID_THIS', 'URLSearchParams'); |
|
|
} |
|
|
} |
|
|
if (typeof callback !== 'function') { |
|
|
if (typeof callback !== 'function') { |
|
|
throw new TypeError('"callback" argument must be a function'); |
|
|
throw new errors.TypeError('ERR_INVALID_CALLBACK'); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
let list = this[searchParams]; |
|
|
let list = this[searchParams]; |
|
@ -1128,7 +1131,7 @@ defineIDLClass(URLSearchParams.prototype, 'URLSearchParams', { |
|
|
// https://heycam.github.io/webidl/#es-iterable
|
|
|
// https://heycam.github.io/webidl/#es-iterable
|
|
|
keys() { |
|
|
keys() { |
|
|
if (!this || !this[searchParams] || this[searchParams][searchParams]) { |
|
|
if (!this || !this[searchParams] || this[searchParams][searchParams]) { |
|
|
throw new TypeError('Value of `this` is not a URLSearchParams'); |
|
|
throw new errors.TypeError('ERR_INVALID_THIS', 'URLSearchParams'); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return createSearchParamsIterator(this, 'key'); |
|
|
return createSearchParamsIterator(this, 'key'); |
|
@ -1136,7 +1139,7 @@ defineIDLClass(URLSearchParams.prototype, 'URLSearchParams', { |
|
|
|
|
|
|
|
|
values() { |
|
|
values() { |
|
|
if (!this || !this[searchParams] || this[searchParams][searchParams]) { |
|
|
if (!this || !this[searchParams] || this[searchParams][searchParams]) { |
|
|
throw new TypeError('Value of `this` is not a URLSearchParams'); |
|
|
throw new errors.TypeError('ERR_INVALID_THIS', 'URLSearchParams'); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return createSearchParamsIterator(this, 'value'); |
|
|
return createSearchParamsIterator(this, 'value'); |
|
@ -1146,7 +1149,7 @@ defineIDLClass(URLSearchParams.prototype, 'URLSearchParams', { |
|
|
// https://url.spec.whatwg.org/#urlsearchparams-stringification-behavior
|
|
|
// https://url.spec.whatwg.org/#urlsearchparams-stringification-behavior
|
|
|
toString() { |
|
|
toString() { |
|
|
if (!this || !this[searchParams] || this[searchParams][searchParams]) { |
|
|
if (!this || !this[searchParams] || this[searchParams][searchParams]) { |
|
|
throw new TypeError('Value of `this` is not a URLSearchParams'); |
|
|
throw new errors.TypeError('ERR_INVALID_THIS', 'URLSearchParams'); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return serializeParams(this[searchParams]); |
|
|
return serializeParams(this[searchParams]); |
|
@ -1178,7 +1181,7 @@ defineIDLClass(URLSearchParamsIteratorPrototype, 'URLSearchParamsIterator', { |
|
|
next() { |
|
|
next() { |
|
|
if (!this || |
|
|
if (!this || |
|
|
Object.getPrototypeOf(this) !== URLSearchParamsIteratorPrototype) { |
|
|
Object.getPrototypeOf(this) !== URLSearchParamsIteratorPrototype) { |
|
|
throw new TypeError('Value of `this` is not a URLSearchParamsIterator'); |
|
|
throw new errors.TypeError('ERR_INVALID_THIS', 'URLSearchParamsIterator'); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const { |
|
|
const { |
|
@ -1215,7 +1218,7 @@ defineIDLClass(URLSearchParamsIteratorPrototype, 'URLSearchParamsIterator', { |
|
|
}, |
|
|
}, |
|
|
[util.inspect.custom](recurseTimes, ctx) { |
|
|
[util.inspect.custom](recurseTimes, ctx) { |
|
|
if (this == null || this[context] == null || this[context].target == null) |
|
|
if (this == null || this[context] == null || this[context].target == null) |
|
|
throw new TypeError('Value of `this` is not a URLSearchParamsIterator'); |
|
|
throw new errors.TypeError('ERR_INVALID_THIS', 'URLSearchParamsIterator'); |
|
|
|
|
|
|
|
|
if (typeof recurseTimes === 'number' && recurseTimes < 0) |
|
|
if (typeof recurseTimes === 'number' && recurseTimes < 0) |
|
|
return ctx.stylize('[Object]', 'special'); |
|
|
return ctx.stylize('[Object]', 'special'); |
|
@ -1254,7 +1257,7 @@ defineIDLClass(URLSearchParamsIteratorPrototype, 'URLSearchParamsIterator', { |
|
|
|
|
|
|
|
|
function domainToASCII(domain) { |
|
|
function domainToASCII(domain) { |
|
|
if (arguments.length < 1) |
|
|
if (arguments.length < 1) |
|
|
throw new TypeError('"domain" argument must be specified'); |
|
|
throw new errors.TypeError('ERR_MISSING_ARGS', 'domain'); |
|
|
|
|
|
|
|
|
// toUSVString is not needed.
|
|
|
// toUSVString is not needed.
|
|
|
return binding.domainToASCII(`${domain}`); |
|
|
return binding.domainToASCII(`${domain}`); |
|
@ -1262,7 +1265,7 @@ function domainToASCII(domain) { |
|
|
|
|
|
|
|
|
function domainToUnicode(domain) { |
|
|
function domainToUnicode(domain) { |
|
|
if (arguments.length < 1) |
|
|
if (arguments.length < 1) |
|
|
throw new TypeError('"domain" argument must be specified'); |
|
|
throw new errors.TypeError('ERR_MISSING_ARGS', 'domain'); |
|
|
|
|
|
|
|
|
// toUSVString is not needed.
|
|
|
// toUSVString is not needed.
|
|
|
return binding.domainToUnicode(`${domain}`); |
|
|
return binding.domainToUnicode(`${domain}`); |
|
@ -1299,8 +1302,9 @@ function getPathFromURLWin32(url) { |
|
|
var third = pathname.codePointAt(n + 2) | 0x20; |
|
|
var third = pathname.codePointAt(n + 2) | 0x20; |
|
|
if ((pathname[n + 1] === '2' && third === 102) || // 2f 2F /
|
|
|
if ((pathname[n + 1] === '2' && third === 102) || // 2f 2F /
|
|
|
(pathname[n + 1] === '5' && third === 99)) { // 5c 5C \
|
|
|
(pathname[n + 1] === '5' && third === 99)) { // 5c 5C \
|
|
|
return new TypeError( |
|
|
return new errors.TypeError( |
|
|
'Path must not include encoded \\ or / characters'); |
|
|
'ERR_INVALID_FILE_URL_PATH', |
|
|
|
|
|
'must not include encoded \\ or / characters'); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
@ -1319,7 +1323,8 @@ function getPathFromURLWin32(url) { |
|
|
var sep = pathname[2]; |
|
|
var sep = pathname[2]; |
|
|
if (letter < 97 || letter > 122 || // a..z A..Z
|
|
|
if (letter < 97 || letter > 122 || // a..z A..Z
|
|
|
(sep !== ':')) { |
|
|
(sep !== ':')) { |
|
|
return new TypeError('File URLs must specify absolute paths'); |
|
|
return new errors.TypeError('ERR_INVALID_FILE_URL_PATH', |
|
|
|
|
|
'must be absolute'); |
|
|
} |
|
|
} |
|
|
return pathname.slice(1); |
|
|
return pathname.slice(1); |
|
|
} |
|
|
} |
|
@ -1327,16 +1332,16 @@ function getPathFromURLWin32(url) { |
|
|
|
|
|
|
|
|
function getPathFromURLPosix(url) { |
|
|
function getPathFromURLPosix(url) { |
|
|
if (url.hostname !== '') { |
|
|
if (url.hostname !== '') { |
|
|
return new TypeError( |
|
|
return new errors.TypeError('ERR_INVALID_FILE_URL_HOST', |
|
|
`File URLs on ${os.platform()} must use hostname 'localhost'` + |
|
|
`must be "localhost" or empty on ${platform}`); |
|
|
' or not specify any hostname'); |
|
|
|
|
|
} |
|
|
} |
|
|
var pathname = url.pathname; |
|
|
var pathname = url.pathname; |
|
|
for (var n = 0; n < pathname.length; n++) { |
|
|
for (var n = 0; n < pathname.length; n++) { |
|
|
if (pathname[n] === '%') { |
|
|
if (pathname[n] === '%') { |
|
|
var third = pathname.codePointAt(n + 2) | 0x20; |
|
|
var third = pathname.codePointAt(n + 2) | 0x20; |
|
|
if (pathname[n + 1] === '2' && third === 102) { |
|
|
if (pathname[n + 1] === '2' && third === 102) { |
|
|
return new TypeError('Path must not include encoded / characters'); |
|
|
return new errors.TypeError('ERR_INVALID_FILE_URL_PATH', |
|
|
|
|
|
'must not include encoded / characters'); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
@ -1349,7 +1354,7 @@ function getPathFromURL(path) { |
|
|
return path; |
|
|
return path; |
|
|
} |
|
|
} |
|
|
if (path.protocol !== 'file:') |
|
|
if (path.protocol !== 'file:') |
|
|
return new TypeError('Only `file:` URLs are supported'); |
|
|
return new errors.TypeError('ERR_INVALID_URL_SCHEME', 'file'); |
|
|
return isWindows ? getPathFromURLWin32(path) : getPathFromURLPosix(path); |
|
|
return isWindows ? getPathFromURLWin32(path) : getPathFromURLPosix(path); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|