Skip to content

Commit 4b2cf23

Browse files
committed
url: use private properties for brand check
1 parent 928a2b0 commit 4b2cf23

File tree

6 files changed

+59
-117
lines changed

6 files changed

+59
-117
lines changed

lib/internal/modules/cjs/loader.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ const { BuiltinModule } = require('internal/bootstrap/loaders');
7979
const {
8080
maybeCacheSourceMap,
8181
} = require('internal/source_map/source_map_cache');
82-
const { pathToFileURL, fileURLToPath, isURLInstance } = require('internal/url');
82+
const { pathToFileURL, fileURLToPath, isURL } = require('internal/url');
8383
const {
8484
deprecate,
8585
emitExperimentalWarning,
@@ -1396,7 +1396,7 @@ const createRequireError = 'must be a file URL object, file URL string, or ' +
13961396
function createRequire(filename) {
13971397
let filepath;
13981398

1399-
if (isURLInstance(filename) ||
1399+
if (isURL(filename) ||
14001400
(typeof filename === 'string' && !path.isAbsolute(filename))) {
14011401
try {
14021402
filepath = fileURLToPath(filename);

lib/internal/modules/esm/hooks.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const {
2121
ERR_INVALID_RETURN_PROPERTY_VALUE,
2222
ERR_INVALID_RETURN_VALUE,
2323
} = require('internal/errors').codes;
24-
const { isURLInstance, URL } = require('internal/url');
24+
const { isURL, URL } = require('internal/url');
2525
const {
2626
isAnyArrayBuffer,
2727
isArrayBufferView,
@@ -263,7 +263,7 @@ class Hooks {
263263
if (
264264
!isMain &&
265265
typeof parentURL !== 'string' &&
266-
!isURLInstance(parentURL)
266+
!isURL(parentURL)
267267
) {
268268
throw new ERR_INVALID_ARG_TYPE(
269269
'parentURL',

lib/internal/url.js

+47-105
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ const {
1515
ObjectGetOwnPropertySymbols,
1616
ObjectGetPrototypeOf,
1717
ObjectKeys,
18-
ObjectPrototypeHasOwnProperty,
1918
ReflectGetOwnPropertyDescriptor,
2019
ReflectOwnKeys,
2120
RegExpPrototypeSymbolReplace,
@@ -535,14 +534,16 @@ ObjectDefineProperties(URLSearchParams.prototype, {
535534
});
536535

537536
function isURL(self) {
538-
return self != null && ObjectPrototypeHasOwnProperty(self, context);
537+
return self != null && self.href && self.origin;
539538
}
540539

541540
class URL {
541+
#context = new URLContext();
542+
#searchParams;
543+
542544
constructor(input, base = undefined) {
543545
// toUSVString is not needed.
544546
input = `${input}`;
545-
this[context] = new URLContext();
546547

547548
if (base !== undefined) {
548549
base = `${base}`;
@@ -558,11 +559,6 @@ class URL {
558559
}
559560

560561
[inspect.custom](depth, opts) {
561-
if (this == null ||
562-
ObjectGetPrototypeOf(this[context]) !== URLContext.prototype) {
563-
throw new ERR_INVALID_THIS('URL');
564-
}
565-
566562
if (typeof depth === 'number' && depth < 0)
567563
return this;
568564

@@ -583,182 +579,133 @@ class URL {
583579
obj.hash = this.hash;
584580

585581
if (opts.showHidden) {
586-
obj[context] = this[context];
582+
obj[context] = this.#context;
587583
}
588584

589585
return `${constructor.name} ${inspect(obj, opts)}`;
590586
}
591587

592588
#onParseComplete = (href, origin, protocol, hostname, pathname,
593589
search, username, password, port, hash) => {
594-
const ctx = this[context];
595-
ctx.href = href;
596-
ctx.origin = origin;
597-
ctx.protocol = protocol;
598-
ctx.hostname = hostname;
599-
ctx.pathname = pathname;
600-
ctx.search = search;
601-
ctx.username = username;
602-
ctx.password = password;
603-
ctx.port = port;
604-
ctx.hash = hash;
605-
if (this[searchParams]) {
606-
this[searchParams][searchParams] = parseParams(search);
590+
this.#context.href = href;
591+
this.#context.origin = origin;
592+
this.#context.protocol = protocol;
593+
this.#context.hostname = hostname;
594+
this.#context.pathname = pathname;
595+
this.#context.search = search;
596+
this.#context.username = username;
597+
this.#context.password = password;
598+
this.#context.port = port;
599+
this.#context.hash = hash;
600+
if (this.#searchParams) {
601+
this.#searchParams[searchParams] = parseParams(search);
607602
}
608603
};
609604

610605
toString() {
611-
if (!isURL(this))
612-
throw new ERR_INVALID_THIS('URL');
613-
return this[context].href;
606+
return this.#context.href;
614607
}
615608

616609
get href() {
617-
if (!isURL(this))
618-
throw new ERR_INVALID_THIS('URL');
619-
return this[context].href;
610+
return this.#context.href;
620611
}
621612

622613
set href(value) {
623-
if (!isURL(this))
624-
throw new ERR_INVALID_THIS('URL');
625-
const valid = updateUrl(this[context].href, updateActions.kHref, `${value}`, this.#onParseComplete);
614+
const valid = updateUrl(this.#context.href, updateActions.kHref, `${value}`, this.#onParseComplete);
626615
if (!valid) { throw ERR_INVALID_URL(`${value}`); }
627616
}
628617

629618
// readonly
630619
get origin() {
631-
if (!isURL(this))
632-
throw new ERR_INVALID_THIS('URL');
633-
return this[context].origin;
620+
return this.#context.origin;
634621
}
635622

636623
get protocol() {
637-
if (!isURL(this))
638-
throw new ERR_INVALID_THIS('URL');
639-
return this[context].protocol;
624+
return this.#context.protocol;
640625
}
641626

642627
set protocol(value) {
643-
if (!isURL(this))
644-
throw new ERR_INVALID_THIS('URL');
645-
updateUrl(this[context].href, updateActions.kProtocol, `${value}`, this.#onParseComplete);
628+
updateUrl(this.#context.href, updateActions.kProtocol, `${value}`, this.#onParseComplete);
646629
}
647630

648631
get username() {
649-
if (!isURL(this))
650-
throw new ERR_INVALID_THIS('URL');
651-
return this[context].username;
632+
return this.#context.username;
652633
}
653634

654635
set username(value) {
655-
if (!isURL(this))
656-
throw new ERR_INVALID_THIS('URL');
657-
updateUrl(this[context].href, updateActions.kUsername, `${value}`, this.#onParseComplete);
636+
updateUrl(this.#context.href, updateActions.kUsername, `${value}`, this.#onParseComplete);
658637
}
659638

660639
get password() {
661-
if (!isURL(this))
662-
throw new ERR_INVALID_THIS('URL');
663-
return this[context].password;
640+
return this.#context.password;
664641
}
665642

666643
set password(value) {
667-
if (!isURL(this))
668-
throw new ERR_INVALID_THIS('URL');
669-
updateUrl(this[context].href, updateActions.kPassword, `${value}`, this.#onParseComplete);
644+
updateUrl(this.#context.href, updateActions.kPassword, `${value}`, this.#onParseComplete);
670645
}
671646

672647
get host() {
673-
if (!isURL(this))
674-
throw new ERR_INVALID_THIS('URL');
675-
const port = this[context].port;
648+
const port = this.#context.port;
676649
const suffix = port.length > 0 ? `:${port}` : '';
677-
return this[context].hostname + suffix;
650+
return this.#context.hostname + suffix;
678651
}
679652

680653
set host(value) {
681-
if (!isURL(this))
682-
throw new ERR_INVALID_THIS('URL');
683-
updateUrl(this[context].href, updateActions.kHost, `${value}`, this.#onParseComplete);
654+
updateUrl(this.#context.href, updateActions.kHost, `${value}`, this.#onParseComplete);
684655
}
685656

686657
get hostname() {
687-
if (!isURL(this))
688-
throw new ERR_INVALID_THIS('URL');
689-
return this[context].hostname;
658+
return this.#context.hostname;
690659
}
691660

692661
set hostname(value) {
693-
if (!isURL(this))
694-
throw new ERR_INVALID_THIS('URL');
695-
updateUrl(this[context].href, updateActions.kHostname, `${value}`, this.#onParseComplete);
662+
updateUrl(this.#context.href, updateActions.kHostname, `${value}`, this.#onParseComplete);
696663
}
697664

698665
get port() {
699-
if (!isURL(this))
700-
throw new ERR_INVALID_THIS('URL');
701-
return this[context].port;
666+
return this.#context.port;
702667
}
703668

704669
set port(value) {
705-
if (!isURL(this))
706-
throw new ERR_INVALID_THIS('URL');
707-
updateUrl(this[context].href, updateActions.kPort, `${value}`, this.#onParseComplete);
670+
updateUrl(this.#context.href, updateActions.kPort, `${value}`, this.#onParseComplete);
708671
}
709672

710673
get pathname() {
711-
if (!isURL(this))
712-
throw new ERR_INVALID_THIS('URL');
713-
return this[context].pathname;
674+
return this.#context.pathname;
714675
}
715676

716677
set pathname(value) {
717-
if (!isURL(this))
718-
throw new ERR_INVALID_THIS('URL');
719-
updateUrl(this[context].href, updateActions.kPathname, `${value}`, this.#onParseComplete);
678+
updateUrl(this.#context.href, updateActions.kPathname, `${value}`, this.#onParseComplete);
720679
}
721680

722681
get search() {
723-
if (!isURL(this))
724-
throw new ERR_INVALID_THIS('URL');
725-
return this[context].search;
682+
return this.#context.search;
726683
}
727684

728685
set search(value) {
729-
if (!isURL(this))
730-
throw new ERR_INVALID_THIS('URL');
731-
updateUrl(this[context].href, updateActions.kSearch, toUSVString(value), this.#onParseComplete);
686+
updateUrl(this.#context.href, updateActions.kSearch, toUSVString(value), this.#onParseComplete);
732687
}
733688

734689
// readonly
735690
get searchParams() {
736-
if (!isURL(this))
737-
throw new ERR_INVALID_THIS('URL');
738691
// Create URLSearchParams on demand to greatly improve the URL performance.
739-
if (this[searchParams] == null) {
740-
this[searchParams] = new URLSearchParams(this[context].search);
741-
this[searchParams][context] = this;
692+
if (this.#searchParams == null) {
693+
this.#searchParams = new URLSearchParams(this.#context.search);
694+
this.#searchParams[context] = this;
742695
}
743-
return this[searchParams];
696+
return this.#searchParams;
744697
}
745698

746699
get hash() {
747-
if (!isURL(this))
748-
throw new ERR_INVALID_THIS('URL');
749-
return this[context].hash;
700+
return this.#context.hash;
750701
}
751702

752703
set hash(value) {
753-
if (!isURL(this))
754-
throw new ERR_INVALID_THIS('URL');
755-
updateUrl(this[context].href, updateActions.kHash, `${value}`, this.#onParseComplete);
704+
updateUrl(this.#context.href, updateActions.kHash, `${value}`, this.#onParseComplete);
756705
}
757706

758707
toJSON() {
759-
if (!isURL(this))
760-
throw new ERR_INVALID_THIS('URL');
761-
return this[context].href;
708+
return this.#context.href;
762709
}
763710

764711
static createObjectURL(obj) {
@@ -1206,7 +1153,7 @@ function getPathFromURLPosix(url) {
12061153
function fileURLToPath(path) {
12071154
if (typeof path === 'string')
12081155
path = new URL(path);
1209-
else if (!isURLInstance(path))
1156+
else if (!isURL(path))
12101157
throw new ERR_INVALID_ARG_TYPE('path', ['string', 'URL'], path);
12111158
if (path.protocol !== 'file:')
12121159
throw new ERR_INVALID_URL_SCHEME('file');
@@ -1282,12 +1229,8 @@ function pathToFileURL(filepath) {
12821229
return outURL;
12831230
}
12841231

1285-
function isURLInstance(fileURLOrPath) {
1286-
return fileURLOrPath != null && fileURLOrPath.href && fileURLOrPath.origin;
1287-
}
1288-
12891232
function toPathIfFileURL(fileURLOrPath) {
1290-
if (!isURLInstance(fileURLOrPath))
1233+
if (!isURL(fileURLOrPath))
12911234
return fileURLOrPath;
12921235
return fileURLToPath(fileURLOrPath);
12931236
}
@@ -1297,7 +1240,6 @@ module.exports = {
12971240
fileURLToPath,
12981241
pathToFileURL,
12991242
toPathIfFileURL,
1300-
isURLInstance,
13011243
URL,
13021244
URLSearchParams,
13031245
domainToASCII,

lib/internal/worker.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ const {
5555
WritableWorkerStdio,
5656
} = workerIo;
5757
const { deserializeError } = require('internal/error_serdes');
58-
const { fileURLToPath, isURLInstance, pathToFileURL } = require('internal/url');
58+
const { fileURLToPath, isURL, pathToFileURL } = require('internal/url');
5959
const { kEmptyObject } = require('internal/util');
6060
const { validateArray } = require('internal/validators');
6161

@@ -148,13 +148,13 @@ class Worker extends EventEmitter {
148148
}
149149
url = null;
150150
doEval = 'classic';
151-
} else if (isURLInstance(filename) && filename.protocol === 'data:') {
151+
} else if (isURL(filename) && filename.protocol === 'data:') {
152152
url = null;
153153
doEval = 'module';
154154
filename = `import ${JSONStringify(`${filename}`)}`;
155155
} else {
156156
doEval = false;
157-
if (isURLInstance(filename)) {
157+
if (isURL(filename)) {
158158
url = filename;
159159
filename = fileURLToPath(filename);
160160
} else if (typeof filename !== 'string') {

test/parallel/test-whatwg-url-custom-inspect.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ assert.strictEqual(
6161

6262
assert.strictEqual(
6363
util.inspect({ a: url }, { depth: 0 }),
64-
'{ a: [URL] }');
64+
'{ a: URL {} }');
6565

6666
class MyURL extends URL {}
6767
assert(util.inspect(new MyURL(url.href)).startsWith('MyURL {'));

test/parallel/test-whatwg-url-invalidthis.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const assert = require('assert');
1010
'toJSON',
1111
].forEach((i) => {
1212
assert.throws(() => Reflect.apply(URL.prototype[i], [], {}), {
13-
code: 'ERR_INVALID_THIS',
13+
name: 'TypeError',
1414
});
1515
});
1616

@@ -27,11 +27,11 @@ const assert = require('assert');
2727
'hash',
2828
].forEach((i) => {
2929
assert.throws(() => Reflect.get(URL.prototype, i, {}), {
30-
code: 'ERR_INVALID_THIS',
30+
name: 'TypeError',
3131
});
3232

3333
assert.throws(() => Reflect.set(URL.prototype, i, null, {}), {
34-
code: 'ERR_INVALID_THIS',
34+
name: 'TypeError',
3535
});
3636
});
3737

@@ -40,6 +40,6 @@ const assert = require('assert');
4040
'searchParams',
4141
].forEach((i) => {
4242
assert.throws(() => Reflect.get(URL.prototype, i, {}), {
43-
code: 'ERR_INVALID_THIS',
43+
name: 'TypeError',
4444
});
4545
});

0 commit comments

Comments
 (0)