|
|
@ -5,20 +5,44 @@ const { |
|
|
|
hexTable, |
|
|
|
isHexTable |
|
|
|
} = require('internal/querystring'); |
|
|
|
|
|
|
|
const { getConstructorOf } = require('internal/util'); |
|
|
|
const errors = require('internal/errors'); |
|
|
|
const binding = process.binding('url'); |
|
|
|
const querystring = require('querystring'); |
|
|
|
|
|
|
|
const { platform } = process; |
|
|
|
const isWindows = platform === 'win32'; |
|
|
|
|
|
|
|
const { |
|
|
|
domainToASCII: _domainToASCII, |
|
|
|
domainToUnicode: _domainToUnicode, |
|
|
|
encodeAuth, |
|
|
|
toUSVString: _toUSVString, |
|
|
|
parse: _parse, |
|
|
|
setURLConstructor, |
|
|
|
URL_FLAGS_CANNOT_BE_BASE, |
|
|
|
URL_FLAGS_HAS_FRAGMENT, |
|
|
|
URL_FLAGS_HAS_HOST, |
|
|
|
URL_FLAGS_HAS_PASSWORD, |
|
|
|
URL_FLAGS_HAS_PATH, |
|
|
|
URL_FLAGS_HAS_QUERY, |
|
|
|
URL_FLAGS_HAS_USERNAME, |
|
|
|
URL_FLAGS_SPECIAL, |
|
|
|
kFragment, |
|
|
|
kHost, |
|
|
|
kHostname, |
|
|
|
kPathStart, |
|
|
|
kPort, |
|
|
|
kQuery, |
|
|
|
kSchemeStart |
|
|
|
} = process.binding('url'); |
|
|
|
|
|
|
|
const context = Symbol('context'); |
|
|
|
const cannotBeBase = Symbol('cannot-be-base'); |
|
|
|
const cannotHaveUsernamePasswordPort = |
|
|
|
Symbol('cannot-have-username-password-port'); |
|
|
|
const special = Symbol('special'); |
|
|
|
const searchParams = Symbol('query'); |
|
|
|
const querystring = require('querystring'); |
|
|
|
|
|
|
|
const { platform } = process; |
|
|
|
const isWindows = platform === 'win32'; |
|
|
|
|
|
|
|
const kFormat = Symbol('format'); |
|
|
|
|
|
|
|
// https://tc39.github.io/ecma262/#sec-%iteratorprototype%-object
|
|
|
@ -35,7 +59,7 @@ function toUSVString(val) { |
|
|
|
const match = unpairedSurrogateRe.exec(str); |
|
|
|
if (!match) |
|
|
|
return str; |
|
|
|
return binding.toUSVString(str, match.index); |
|
|
|
return _toUSVString(str, match.index); |
|
|
|
} |
|
|
|
|
|
|
|
// Refs: https://html.spec.whatwg.org/multipage/browsers.html#concept-origin-opaque
|
|
|
@ -74,10 +98,10 @@ function onParseComplete(flags, protocol, username, password, |
|
|
|
var ctx = this[context]; |
|
|
|
ctx.flags = flags; |
|
|
|
ctx.scheme = protocol; |
|
|
|
ctx.username = (flags & binding.URL_FLAGS_HAS_USERNAME) !== 0 ? username : ''; |
|
|
|
ctx.password = (flags & binding.URL_FLAGS_HAS_PASSWORD) !== 0 ? password : ''; |
|
|
|
ctx.username = (flags & URL_FLAGS_HAS_USERNAME) !== 0 ? username : ''; |
|
|
|
ctx.password = (flags & URL_FLAGS_HAS_PASSWORD) !== 0 ? password : ''; |
|
|
|
ctx.port = port; |
|
|
|
ctx.path = (flags & binding.URL_FLAGS_HAS_PATH) !== 0 ? path : []; |
|
|
|
ctx.path = (flags & URL_FLAGS_HAS_PATH) !== 0 ? path : []; |
|
|
|
ctx.query = query; |
|
|
|
ctx.fragment = fragment; |
|
|
|
ctx.host = host; |
|
|
@ -98,18 +122,17 @@ function onParseError(flags, input) { |
|
|
|
function parse(url, input, base) { |
|
|
|
const base_context = base ? base[context] : undefined; |
|
|
|
url[context] = new URLContext(); |
|
|
|
binding.parse(input.trim(), -1, |
|
|
|
base_context, undefined, |
|
|
|
onParseComplete.bind(url), onParseError); |
|
|
|
_parse(input.trim(), -1, base_context, undefined, |
|
|
|
onParseComplete.bind(url), onParseError); |
|
|
|
} |
|
|
|
|
|
|
|
function onParseProtocolComplete(flags, protocol, username, password, |
|
|
|
host, port, path, query, fragment) { |
|
|
|
const ctx = this[context]; |
|
|
|
if ((flags & binding.URL_FLAGS_SPECIAL) !== 0) { |
|
|
|
ctx.flags |= binding.URL_FLAGS_SPECIAL; |
|
|
|
if ((flags & URL_FLAGS_SPECIAL) !== 0) { |
|
|
|
ctx.flags |= URL_FLAGS_SPECIAL; |
|
|
|
} else { |
|
|
|
ctx.flags &= ~binding.URL_FLAGS_SPECIAL; |
|
|
|
ctx.flags &= ~URL_FLAGS_SPECIAL; |
|
|
|
} |
|
|
|
ctx.scheme = protocol; |
|
|
|
} |
|
|
@ -117,12 +140,12 @@ function onParseProtocolComplete(flags, protocol, username, password, |
|
|
|
function onParseHostComplete(flags, protocol, username, password, |
|
|
|
host, port, path, query, fragment) { |
|
|
|
const ctx = this[context]; |
|
|
|
if ((flags & binding.URL_FLAGS_HAS_HOST) !== 0) { |
|
|
|
if ((flags & URL_FLAGS_HAS_HOST) !== 0) { |
|
|
|
ctx.host = host; |
|
|
|
ctx.flags |= binding.URL_FLAGS_HAS_HOST; |
|
|
|
ctx.flags |= URL_FLAGS_HAS_HOST; |
|
|
|
} else { |
|
|
|
ctx.host = null; |
|
|
|
ctx.flags &= ~binding.URL_FLAGS_HAS_HOST; |
|
|
|
ctx.flags &= ~URL_FLAGS_HAS_HOST; |
|
|
|
} |
|
|
|
if (port !== null) |
|
|
|
ctx.port = port; |
|
|
@ -131,12 +154,12 @@ function onParseHostComplete(flags, protocol, username, password, |
|
|
|
function onParseHostnameComplete(flags, protocol, username, password, |
|
|
|
host, port, path, query, fragment) { |
|
|
|
const ctx = this[context]; |
|
|
|
if ((flags & binding.URL_FLAGS_HAS_HOST) !== 0) { |
|
|
|
if ((flags & URL_FLAGS_HAS_HOST) !== 0) { |
|
|
|
ctx.host = host; |
|
|
|
ctx.flags |= binding.URL_FLAGS_HAS_HOST; |
|
|
|
ctx.flags |= URL_FLAGS_HAS_HOST; |
|
|
|
} else { |
|
|
|
ctx.host = null; |
|
|
|
ctx.flags &= ~binding.URL_FLAGS_HAS_HOST; |
|
|
|
ctx.flags &= ~URL_FLAGS_HAS_HOST; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -148,18 +171,18 @@ function onParsePortComplete(flags, protocol, username, password, |
|
|
|
function onParsePathComplete(flags, protocol, username, password, |
|
|
|
host, port, path, query, fragment) { |
|
|
|
const ctx = this[context]; |
|
|
|
if ((flags & binding.URL_FLAGS_HAS_PATH) !== 0) { |
|
|
|
if ((flags & URL_FLAGS_HAS_PATH) !== 0) { |
|
|
|
ctx.path = path; |
|
|
|
ctx.flags |= binding.URL_FLAGS_HAS_PATH; |
|
|
|
ctx.flags |= URL_FLAGS_HAS_PATH; |
|
|
|
} else { |
|
|
|
ctx.path = []; |
|
|
|
ctx.flags &= ~binding.URL_FLAGS_HAS_PATH; |
|
|
|
ctx.flags &= ~URL_FLAGS_HAS_PATH; |
|
|
|
} |
|
|
|
|
|
|
|
// The C++ binding may set host to empty string.
|
|
|
|
if ((flags & binding.URL_FLAGS_HAS_HOST) !== 0) { |
|
|
|
if ((flags & URL_FLAGS_HAS_HOST) !== 0) { |
|
|
|
ctx.host = host; |
|
|
|
ctx.flags |= binding.URL_FLAGS_HAS_HOST; |
|
|
|
ctx.flags |= URL_FLAGS_HAS_HOST; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -185,11 +208,11 @@ class URL { |
|
|
|
} |
|
|
|
|
|
|
|
get [special]() { |
|
|
|
return (this[context].flags & binding.URL_FLAGS_SPECIAL) !== 0; |
|
|
|
return (this[context].flags & URL_FLAGS_SPECIAL) !== 0; |
|
|
|
} |
|
|
|
|
|
|
|
get [cannotBeBase]() { |
|
|
|
return (this[context].flags & binding.URL_FLAGS_CANNOT_BE_BASE) !== 0; |
|
|
|
return (this[context].flags & URL_FLAGS_CANNOT_BE_BASE) !== 0; |
|
|
|
} |
|
|
|
|
|
|
|
// https://url.spec.whatwg.org/#cannot-have-a-username-password-port
|
|
|
@ -348,8 +371,8 @@ Object.defineProperties(URL.prototype, { |
|
|
|
(ctx.host === '' || ctx.host === null)) { |
|
|
|
return; |
|
|
|
} |
|
|
|
binding.parse(scheme, binding.kSchemeStart, null, ctx, |
|
|
|
onParseProtocolComplete.bind(this)); |
|
|
|
_parse(scheme, kSchemeStart, null, ctx, |
|
|
|
onParseProtocolComplete.bind(this)); |
|
|
|
} |
|
|
|
}, |
|
|
|
username: { |
|
|
@ -366,11 +389,11 @@ Object.defineProperties(URL.prototype, { |
|
|
|
const ctx = this[context]; |
|
|
|
if (username === '') { |
|
|
|
ctx.username = ''; |
|
|
|
ctx.flags &= ~binding.URL_FLAGS_HAS_USERNAME; |
|
|
|
ctx.flags &= ~URL_FLAGS_HAS_USERNAME; |
|
|
|
return; |
|
|
|
} |
|
|
|
ctx.username = binding.encodeAuth(username); |
|
|
|
ctx.flags |= binding.URL_FLAGS_HAS_USERNAME; |
|
|
|
ctx.username = encodeAuth(username); |
|
|
|
ctx.flags |= URL_FLAGS_HAS_USERNAME; |
|
|
|
} |
|
|
|
}, |
|
|
|
password: { |
|
|
@ -387,11 +410,11 @@ Object.defineProperties(URL.prototype, { |
|
|
|
const ctx = this[context]; |
|
|
|
if (password === '') { |
|
|
|
ctx.password = ''; |
|
|
|
ctx.flags &= ~binding.URL_FLAGS_HAS_PASSWORD; |
|
|
|
ctx.flags &= ~URL_FLAGS_HAS_PASSWORD; |
|
|
|
return; |
|
|
|
} |
|
|
|
ctx.password = binding.encodeAuth(password); |
|
|
|
ctx.flags |= binding.URL_FLAGS_HAS_PASSWORD; |
|
|
|
ctx.password = encodeAuth(password); |
|
|
|
ctx.flags |= URL_FLAGS_HAS_PASSWORD; |
|
|
|
} |
|
|
|
}, |
|
|
|
host: { |
|
|
@ -412,8 +435,7 @@ Object.defineProperties(URL.prototype, { |
|
|
|
// Cannot set the host if cannot-be-base is set
|
|
|
|
return; |
|
|
|
} |
|
|
|
binding.parse(host, binding.kHost, null, ctx, |
|
|
|
onParseHostComplete.bind(this)); |
|
|
|
_parse(host, kHost, null, ctx, onParseHostComplete.bind(this)); |
|
|
|
} |
|
|
|
}, |
|
|
|
hostname: { |
|
|
@ -430,8 +452,7 @@ Object.defineProperties(URL.prototype, { |
|
|
|
// Cannot set the host if cannot-be-base is set
|
|
|
|
return; |
|
|
|
} |
|
|
|
binding.parse(host, binding.kHostname, null, ctx, |
|
|
|
onParseHostnameComplete.bind(this)); |
|
|
|
_parse(host, kHostname, null, ctx, onParseHostnameComplete.bind(this)); |
|
|
|
} |
|
|
|
}, |
|
|
|
port: { |
|
|
@ -451,8 +472,7 @@ Object.defineProperties(URL.prototype, { |
|
|
|
ctx.port = null; |
|
|
|
return; |
|
|
|
} |
|
|
|
binding.parse(port, binding.kPort, null, ctx, |
|
|
|
onParsePortComplete.bind(this)); |
|
|
|
_parse(port, kPort, null, ctx, onParsePortComplete.bind(this)); |
|
|
|
} |
|
|
|
}, |
|
|
|
pathname: { |
|
|
@ -471,8 +491,8 @@ Object.defineProperties(URL.prototype, { |
|
|
|
path = `${path}`; |
|
|
|
if (this[cannotBeBase]) |
|
|
|
return; |
|
|
|
binding.parse(path, binding.kPathStart, null, this[context], |
|
|
|
onParsePathComplete.bind(this)); |
|
|
|
_parse(path, kPathStart, null, this[context], |
|
|
|
onParsePathComplete.bind(this)); |
|
|
|
} |
|
|
|
}, |
|
|
|
search: { |
|
|
@ -489,14 +509,13 @@ Object.defineProperties(URL.prototype, { |
|
|
|
search = toUSVString(search); |
|
|
|
if (search === '') { |
|
|
|
ctx.query = null; |
|
|
|
ctx.flags &= ~binding.URL_FLAGS_HAS_QUERY; |
|
|
|
ctx.flags &= ~URL_FLAGS_HAS_QUERY; |
|
|
|
} else { |
|
|
|
if (search[0] === '?') search = search.slice(1); |
|
|
|
ctx.query = ''; |
|
|
|
ctx.flags |= binding.URL_FLAGS_HAS_QUERY; |
|
|
|
ctx.flags |= URL_FLAGS_HAS_QUERY; |
|
|
|
if (search) { |
|
|
|
binding.parse(search, binding.kQuery, null, ctx, |
|
|
|
onParseSearchComplete.bind(this)); |
|
|
|
_parse(search, kQuery, null, ctx, onParseSearchComplete.bind(this)); |
|
|
|
} |
|
|
|
} |
|
|
|
initSearchParams(this[searchParams], search); |
|
|
@ -524,14 +543,13 @@ Object.defineProperties(URL.prototype, { |
|
|
|
hash = `${hash}`; |
|
|
|
if (!hash) { |
|
|
|
ctx.fragment = null; |
|
|
|
ctx.flags &= ~binding.URL_FLAGS_HAS_FRAGMENT; |
|
|
|
ctx.flags &= ~URL_FLAGS_HAS_FRAGMENT; |
|
|
|
return; |
|
|
|
} |
|
|
|
if (hash[0] === '#') hash = hash.slice(1); |
|
|
|
ctx.fragment = ''; |
|
|
|
ctx.flags |= binding.URL_FLAGS_HAS_FRAGMENT; |
|
|
|
binding.parse(hash, binding.kFragment, null, ctx, |
|
|
|
onParseHashComplete.bind(this)); |
|
|
|
ctx.flags |= URL_FLAGS_HAS_FRAGMENT; |
|
|
|
_parse(hash, kFragment, null, ctx, onParseHashComplete.bind(this)); |
|
|
|
} |
|
|
|
}, |
|
|
|
toJSON: { |
|
|
@ -553,10 +571,10 @@ function update(url, params) { |
|
|
|
const serializedParams = params.toString(); |
|
|
|
if (serializedParams) { |
|
|
|
ctx.query = serializedParams; |
|
|
|
ctx.flags |= binding.URL_FLAGS_HAS_QUERY; |
|
|
|
ctx.flags |= URL_FLAGS_HAS_QUERY; |
|
|
|
} else { |
|
|
|
ctx.query = null; |
|
|
|
ctx.flags &= ~binding.URL_FLAGS_HAS_QUERY; |
|
|
|
ctx.flags &= ~URL_FLAGS_HAS_QUERY; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -1257,7 +1275,7 @@ function domainToASCII(domain) { |
|
|
|
throw new errors.TypeError('ERR_MISSING_ARGS', 'domain'); |
|
|
|
|
|
|
|
// toUSVString is not needed.
|
|
|
|
return binding.domainToASCII(`${domain}`); |
|
|
|
return _domainToASCII(`${domain}`); |
|
|
|
} |
|
|
|
|
|
|
|
function domainToUnicode(domain) { |
|
|
@ -1265,7 +1283,7 @@ function domainToUnicode(domain) { |
|
|
|
throw new errors.TypeError('ERR_MISSING_ARGS', 'domain'); |
|
|
|
|
|
|
|
// toUSVString is not needed.
|
|
|
|
return binding.domainToUnicode(`${domain}`); |
|
|
|
return _domainToUnicode(`${domain}`); |
|
|
|
} |
|
|
|
|
|
|
|
// Utility function that converts a URL object into an ordinary
|
|
|
@ -1365,10 +1383,10 @@ function constructUrl(flags, protocol, username, password, |
|
|
|
var ctx = new URLContext(); |
|
|
|
ctx.flags = flags; |
|
|
|
ctx.scheme = protocol; |
|
|
|
ctx.username = (flags & binding.URL_FLAGS_HAS_USERNAME) !== 0 ? username : ''; |
|
|
|
ctx.password = (flags & binding.URL_FLAGS_HAS_PASSWORD) !== 0 ? password : ''; |
|
|
|
ctx.username = (flags & URL_FLAGS_HAS_USERNAME) !== 0 ? username : ''; |
|
|
|
ctx.password = (flags & URL_FLAGS_HAS_PASSWORD) !== 0 ? password : ''; |
|
|
|
ctx.port = port; |
|
|
|
ctx.path = (flags & binding.URL_FLAGS_HAS_PATH) !== 0 ? path : []; |
|
|
|
ctx.path = (flags & URL_FLAGS_HAS_PATH) !== 0 ? path : []; |
|
|
|
ctx.query = query; |
|
|
|
ctx.fragment = fragment; |
|
|
|
ctx.host = host; |
|
|
@ -1378,7 +1396,7 @@ function constructUrl(flags, protocol, username, password, |
|
|
|
initSearchParams(url[searchParams], query); |
|
|
|
return url; |
|
|
|
} |
|
|
|
binding.setURLConstructor(constructUrl); |
|
|
|
setURLConstructor(constructUrl); |
|
|
|
|
|
|
|
module.exports = { |
|
|
|
toUSVString, |
|
|
|