From 8e9cbf64bc5c617c7644ec0f917ce8a7030ce3c1 Mon Sep 17 00:00:00 2001 From: generaltony007 <191973953+hakarrr@users.noreply.github.com> Date: Mon, 9 Nov 2026 10:23:07 +0530 Subject: [PATCH 1/2] url: convert setter values before reading current href Web IDL converts an assigned value to the attribute's type before the setter steps run. The URL component setters passed `this.#context.href` as the first argument to `bindingUrl.update()`, evaluating it before the assigned value's string conversion. A `toString()` that mutates the URL during conversion therefore had its effects overwritten by the stale href captured beforehand. Hoist the conversion above the href read in the protocol, username, password, host, hostname, port, pathname, search and hash setters, matching the existing `href` setter. Fixes: https://github.com/nodejs/node/issues/67345 Co-authored-by: generaltony007 <144252170+GeneralTony007@users.noreply.github.com> --- lib/internal/url.js | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/lib/internal/url.js b/lib/internal/url.js index 0fe819fe129..35abca64e93 100644 --- a/lib/internal/url.js +++ b/lib/internal/url.js @@ -1065,7 +1065,8 @@ class URL { } set protocol(value) { - const href = bindingUrl.update(this.#context.href, updateActions.kProtocol, `${value}`); + value = `${value}`; + const href = bindingUrl.update(this.#context.href, updateActions.kProtocol, value); if (href) { this.#updateContext(href); } @@ -1079,7 +1080,8 @@ class URL { } set username(value) { - const href = bindingUrl.update(this.#context.href, updateActions.kUsername, `${value}`); + value = `${value}`; + const href = bindingUrl.update(this.#context.href, updateActions.kUsername, value); if (href) { this.#updateContext(href); } @@ -1093,7 +1095,8 @@ class URL { } set password(value) { - const href = bindingUrl.update(this.#context.href, updateActions.kPassword, `${value}`); + value = `${value}`; + const href = bindingUrl.update(this.#context.href, updateActions.kPassword, value); if (href) { this.#updateContext(href); } @@ -1113,7 +1116,8 @@ class URL { } set host(value) { - const href = bindingUrl.update(this.#context.href, updateActions.kHost, `${value}`); + value = `${value}`; + const href = bindingUrl.update(this.#context.href, updateActions.kHost, value); if (href) { this.#updateContext(href); } @@ -1129,7 +1133,8 @@ class URL { } set hostname(value) { - const href = bindingUrl.update(this.#context.href, updateActions.kHostname, `${value}`); + value = `${value}`; + const href = bindingUrl.update(this.#context.href, updateActions.kHostname, value); if (href) { this.#updateContext(href); } @@ -1143,7 +1148,8 @@ class URL { } set port(value) { - const href = bindingUrl.update(this.#context.href, updateActions.kPort, `${value}`); + value = `${value}`; + const href = bindingUrl.update(this.#context.href, updateActions.kPort, value); if (href) { this.#updateContext(href); } @@ -1160,7 +1166,8 @@ class URL { } set pathname(value) { - const href = bindingUrl.update(this.#context.href, updateActions.kPathname, `${value}`); + value = `${value}`; + const href = bindingUrl.update(this.#context.href, updateActions.kPathname, value); if (href) { this.#updateContext(href); } @@ -1173,7 +1180,8 @@ class URL { } set search(value) { - const href = bindingUrl.update(this.#context.href, updateActions.kSearch, StringPrototypeToWellFormed(`${value}`)); + value = StringPrototypeToWellFormed(`${value}`); + const href = bindingUrl.update(this.#context.href, updateActions.kSearch, value); if (href) { this.#updateContext(href, true); } @@ -1198,7 +1206,8 @@ class URL { } set hash(value) { - const href = bindingUrl.update(this.#context.href, updateActions.kHash, `${value}`); + value = `${value}`; + const href = bindingUrl.update(this.#context.href, updateActions.kHash, value); if (href) { this.#updateContext(href); } From 1592a3837897e20f684358518f69c37d89dc3ddf Mon Sep 17 00:00:00 2001 From: generaltony007 <191973953+hakarrr@users.noreply.github.com> Date: Mon, 9 Nov 2026 10:23:38 +0530 Subject: [PATCH 2/2] url: convert setter values before reading current href Regression test: every URL component setter must apply to the URL state after value conversion, not to stale state captured before it. Fixes: https://github.com/nodejs/node/issues/67345 Co-authored-by: generaltony007 <144252170+GeneralTony007@users.noreply.github.com> --- .../test-whatwg-url-setters-coercion-order.js | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 test/parallel/test-whatwg-url-setters-coercion-order.js diff --git a/test/parallel/test-whatwg-url-setters-coercion-order.js b/test/parallel/test-whatwg-url-setters-coercion-order.js new file mode 100644 index 00000000000..364f2354185 --- /dev/null +++ b/test/parallel/test-whatwg-url-setters-coercion-order.js @@ -0,0 +1,34 @@ +'use strict'; + +// Tests below are not from WPT. +// +// Web IDL converts an assigned value to the attribute's type before the +// setter's steps run. A `toString()` that mutates the URL during conversion +// must be observed by the setter: the new component value applies to the +// mutated URL, not to stale state captured before the conversion. +// Refs: https://github.com/nodejs/node/issues/67345 +require('../common'); +const assert = require('assert'); + +const cases = [ + ['protocol', 'http', 'http://after.example/base'], + ['username', 'user', 'https://user@after.example/base'], + ['password', 'pass', 'https://:pass@after.example/base'], + ['host', 'other.example:8080', 'https://other.example:8080/base'], + ['hostname', 'other.example', 'https://other.example/base'], + ['port', '8080', 'https://after.example:8080/base'], + ['pathname', '/new', 'https://after.example/new'], + ['search', '?q=1', 'https://after.example/base?q=1'], + ['hash', '#frag', 'https://after.example/base#frag'], +]; + +for (const [setter, value, expected] of cases) { + const url = new URL('https://before.example/old'); + url[setter] = { + toString() { + url.href = 'https://after.example/base'; + return value; + }, + }; + assert.strictEqual(url.href, expected, `${setter} setter`); +}