diff --git a/lib/internal/url.js b/lib/internal/url.js index 66a482f98e8c9c..fc651ad59a8071 100644 --- a/lib/internal/url.js +++ b/lib/internal/url.js @@ -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,