Skip to content

Commit

Permalink
url: ensure getter access do not mutate observable symbols
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
aduh95 authored and ruyadorno committed Aug 16, 2023
1 parent 69aaf8b commit 0beb5ab
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 9 deletions.
30 changes: 21 additions & 9 deletions lib/internal/url.js
Expand Up @@ -22,6 +22,7 @@ const {
ReflectOwnKeys,
RegExpPrototypeSymbolReplace,
SafeMap,
SafeWeakMap,
StringPrototypeCharAt,
StringPrototypeCharCodeAt,
StringPrototypeCodePointAt,
Expand Down Expand Up @@ -99,6 +100,12 @@ const FORWARD_SLASH = /\//g;
const context = Symbol('context');
const searchParams = Symbol('query');

/**
* We cannot use private fields without a breaking change, so a WeakMap is the alternative.
* @type {WeakMap<URL,URLSearchParams>}
*/
const internalSearchParams = new SafeWeakMap();

const updateActions = {
kProtocol: 0,
kHost: 1,
Expand Down Expand Up @@ -179,7 +186,7 @@ class URLContext {
}

function isURLSearchParams(self) {
return self && self[searchParams] && !self[searchParams][searchParams];
return self?.[searchParams];
}

class URLSearchParams {
Expand Down Expand Up @@ -672,11 +679,12 @@ class URL {
ctx.hash_start = hash_start;
ctx.scheme_type = scheme_type;

if (this[searchParams]) {
const alreadyInstantiatedSearchParams = internalSearchParams.get(this);
if (alreadyInstantiatedSearchParams) {
if (ctx.hasSearch) {
this[searchParams][searchParams] = parseParams(this.search);
alreadyInstantiatedSearchParams[searchParams] = parseParams(this.search);
} else {
this[searchParams][searchParams] = [];
alreadyInstantiatedSearchParams[searchParams] = [];
}
}
}
Expand Down Expand Up @@ -898,11 +906,15 @@ class URL {
get searchParams() {
if (!isURL(this))
throw new ERR_INVALID_THIS('URL');
if (this[searchParams] == null) {
this[searchParams] = new URLSearchParams(this.search);
this[searchParams][context] = this;
}
return this[searchParams];

const cachedValue = internalSearchParams.get(this);
if (cachedValue != null)
return cachedValue;

const value = new URLSearchParams(this.search);
value[context] = this;
internalSearchParams.set(this, value);
return value;
}

get hash() {
Expand Down
2 changes: 2 additions & 0 deletions test/parallel/test-whatwg-url-custom-searchparams.js
Expand Up @@ -16,7 +16,9 @@ const normalizedValues = ['a', '1', 'true', 'undefined', 'null', '\uFFFD',
'[object Object]'];

const m = new URL('http://example.org');
const ownSymbolsBeforeGetterAccess = Object.getOwnPropertySymbols(m);
const sp = m.searchParams;
assert.deepStrictEqual(Object.getOwnPropertySymbols(m), ownSymbolsBeforeGetterAccess);

assert(sp);
assert.strictEqual(sp.toString(), '');
Expand Down

0 comments on commit 0beb5ab

Please sign in to comment.