Skip to content

Commit 0beb5ab

Browse files
aduh95ruyadorno
authored andcommitted
url: ensure getter access do not mutate observable symbols
PR-URL: #48897 Backport-PR-URL: #48891 Refs: #48891 Refs: #48886 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
1 parent 69aaf8b commit 0beb5ab

File tree

2 files changed

+23
-9
lines changed

2 files changed

+23
-9
lines changed

lib/internal/url.js

+21-9
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const {
2222
ReflectOwnKeys,
2323
RegExpPrototypeSymbolReplace,
2424
SafeMap,
25+
SafeWeakMap,
2526
StringPrototypeCharAt,
2627
StringPrototypeCharCodeAt,
2728
StringPrototypeCodePointAt,
@@ -99,6 +100,12 @@ const FORWARD_SLASH = /\//g;
99100
const context = Symbol('context');
100101
const searchParams = Symbol('query');
101102

103+
/**
104+
* We cannot use private fields without a breaking change, so a WeakMap is the alternative.
105+
* @type {WeakMap<URL,URLSearchParams>}
106+
*/
107+
const internalSearchParams = new SafeWeakMap();
108+
102109
const updateActions = {
103110
kProtocol: 0,
104111
kHost: 1,
@@ -179,7 +186,7 @@ class URLContext {
179186
}
180187

181188
function isURLSearchParams(self) {
182-
return self && self[searchParams] && !self[searchParams][searchParams];
189+
return self?.[searchParams];
183190
}
184191

185192
class URLSearchParams {
@@ -672,11 +679,12 @@ class URL {
672679
ctx.hash_start = hash_start;
673680
ctx.scheme_type = scheme_type;
674681

675-
if (this[searchParams]) {
682+
const alreadyInstantiatedSearchParams = internalSearchParams.get(this);
683+
if (alreadyInstantiatedSearchParams) {
676684
if (ctx.hasSearch) {
677-
this[searchParams][searchParams] = parseParams(this.search);
685+
alreadyInstantiatedSearchParams[searchParams] = parseParams(this.search);
678686
} else {
679-
this[searchParams][searchParams] = [];
687+
alreadyInstantiatedSearchParams[searchParams] = [];
680688
}
681689
}
682690
}
@@ -898,11 +906,15 @@ class URL {
898906
get searchParams() {
899907
if (!isURL(this))
900908
throw new ERR_INVALID_THIS('URL');
901-
if (this[searchParams] == null) {
902-
this[searchParams] = new URLSearchParams(this.search);
903-
this[searchParams][context] = this;
904-
}
905-
return this[searchParams];
909+
910+
const cachedValue = internalSearchParams.get(this);
911+
if (cachedValue != null)
912+
return cachedValue;
913+
914+
const value = new URLSearchParams(this.search);
915+
value[context] = this;
916+
internalSearchParams.set(this, value);
917+
return value;
906918
}
907919

908920
get hash() {

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

+2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ const normalizedValues = ['a', '1', 'true', 'undefined', 'null', '\uFFFD',
1616
'[object Object]'];
1717

1818
const m = new URL('http://example.org');
19+
const ownSymbolsBeforeGetterAccess = Object.getOwnPropertySymbols(m);
1920
const sp = m.searchParams;
21+
assert.deepStrictEqual(Object.getOwnPropertySymbols(m), ownSymbolsBeforeGetterAccess);
2022

2123
assert(sp);
2224
assert.strictEqual(sp.toString(), '');

0 commit comments

Comments
 (0)