From 53b7cdd323ba24cbf297e2345dd1930e861ec8b3 Mon Sep 17 00:00:00 2001 From: Timothy Gu Date: Tue, 4 Apr 2023 20:10:49 -0700 Subject: [PATCH 1/2] url: do not use object as hashmap Fixes cases like new URLSearchParams({ hasOwnProperty: 1 }). --- lib/internal/url.js | 17 +++++++++-------- ...hatwg-url-custom-searchparams-constructor.js | 5 +++++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/lib/internal/url.js b/lib/internal/url.js index e9b4b330385996..79e69a0f5cf677 100644 --- a/lib/internal/url.js +++ b/lib/internal/url.js @@ -20,6 +20,7 @@ const { ReflectGetOwnPropertyDescriptor, ReflectOwnKeys, RegExpPrototypeSymbolReplace, + SafeMap, StringPrototypeCharAt, StringPrototypeCharCodeAt, StringPrototypeCodePointAt, @@ -219,7 +220,7 @@ class URLSearchParams { } else { // Record // Need to use reflection APIs for full spec compliance. - const visited = {}; + const visited = new SafeMap(); const keys = ReflectOwnKeys(init); for (let i = 0; i < keys.length; i++) { const key = keys[i]; @@ -228,14 +229,14 @@ class URLSearchParams { const typedKey = toUSVString(key); const typedValue = toUSVString(init[key]); - // Two different key may result same after `toUSVString()`, we only - // leave the later one. Refers to WPT. - if (visited[typedKey] !== undefined) { - this[searchParams][visited[typedKey]] = typedValue; + // Two different keys may become the same USVString after normalization. + // In that case, we retain the later one. Refer to WPT. + if (visited.has(typedKey)) { + this[searchParams][visited.get(typedKey)] = typedValue; } else { - visited[typedKey] = ArrayPrototypePush(this[searchParams], - typedKey, - typedValue) - 1; + visited.set(typedKey, ArrayPrototypePush(this[searchParams], + typedKey, + typedValue) - 1); } } } diff --git a/test/parallel/test-whatwg-url-custom-searchparams-constructor.js b/test/parallel/test-whatwg-url-custom-searchparams-constructor.js index 1b7409680b2a2a..75888f9270d25b 100644 --- a/test/parallel/test-whatwg-url-custom-searchparams-constructor.js +++ b/test/parallel/test-whatwg-url-custom-searchparams-constructor.js @@ -38,8 +38,13 @@ function makeIterableFunc(array) { makeIterableFunc([['key', 'val'], ['key2', 'val2']].map(makeIterableFunc)) ); assert.strictEqual(params.toString(), 'key=val&key2=val2'); + params = new URLSearchParams({ hasOwnProperty: 1 }); + assert.strictEqual(params.get('hasOwnProperty'), '1'); + assert.strictEqual(params.toString(), 'hasOwnProperty=1'); assert.throws(() => new URLSearchParams([[1]]), tupleError); assert.throws(() => new URLSearchParams([[1, 2, 3]]), tupleError); + assert.throws(() => new URLSearchParams({ [Symbol('test')]: 42 }), + TypeError); assert.throws(() => new URLSearchParams({ [Symbol.iterator]: 42 }), iterableError); assert.throws(() => new URLSearchParams([{}]), tupleError); From 0e02a9abbdaf95dbe6c337ee5f69c58396d210d2 Mon Sep 17 00:00:00 2001 From: Timothy Gu Date: Wed, 5 Apr 2023 14:13:09 -0400 Subject: [PATCH 2/2] fixup! don't lookup twice --- lib/internal/url.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/internal/url.js b/lib/internal/url.js index 79e69a0f5cf677..73e776513329b5 100644 --- a/lib/internal/url.js +++ b/lib/internal/url.js @@ -231,8 +231,9 @@ class URLSearchParams { // Two different keys may become the same USVString after normalization. // In that case, we retain the later one. Refer to WPT. - if (visited.has(typedKey)) { - this[searchParams][visited.get(typedKey)] = typedValue; + const keyIdx = visited.get(typedKey); + if (keyIdx !== undefined) { + this[searchParams][keyIdx] = typedValue; } else { visited.set(typedKey, ArrayPrototypePush(this[searchParams], typedKey,