From ccd4e35b1fb92cc805898ea1ff4ad7b82f451e1d Mon Sep 17 00:00:00 2001 From: ldm0 Date: Sun, 13 Sep 2026 05:45:54 +0800 Subject: [PATCH] fix(webidl): honor initializer iterators on platform objects Use sequence/record discrimination for native Headers, URLSearchParams, FormData, and URL initializers. Read the author iterator once, preserve its result or exception, and use own record properties when it is absent. Cover Request and Response headers, enumerable iterator symbols, and FormData File conversion. Remove unused imports and the URL stringification helper. --- .../src/script_vm/tests/webidl_fetch.rs | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/moli-renderer-v8/src/script_vm/tests/webidl_fetch.rs b/moli-renderer-v8/src/script_vm/tests/webidl_fetch.rs index 05a434f3df..28b8ce56ad 100644 --- a/moli-renderer-v8/src/script_vm/tests/webidl_fetch.rs +++ b/moli-renderer-v8/src/script_vm/tests/webidl_fetch.rs @@ -10696,3 +10696,40 @@ fn clipboard_item_record_converts_thenables_before_later_descriptors() { .unwrap(); assert_eq!(result, "ok"); } + +#[test] +fn webidl_initializer_unions_convert_platform_objects_without_iterators_as_records() { + let mut vm = new_storage_test_vm("https://initializer-record.test/"); + let result = vm.eval(r#" +(() => { + for (const Constructor of [Headers, URLSearchParams]) { + const url = new URL('https://initializer-record.test/path?query=value'); + Object.defineProperty(url, Symbol.toPrimitive, {value() { + throw new Error('URL object must use record conversion'); + }}); + if (Array.from(new Constructor(url)).length !== 0) throw new Error('empty URL record'); + url['x-record'] = 'record'; + if (JSON.stringify(Array.from(new Constructor(url))) !== '[["x-record","record"]]') { + throw new Error(Constructor.name + ' must use own URL properties'); + } + for (const factory of [() => new Headers(), () => new URLSearchParams(), () => new FormData()]) { + for (const value of [undefined, null]) { + const input = factory(); + let iteratorReads = 0; + Object.defineProperty(input, Symbol.iterator, {enumerable: true, get() { + iteratorReads++; + return value; + }}); + let caught; + try { new Constructor(input); } catch (error) { caught = error; } + if (!(caught instanceof TypeError) || iteratorReads !== 1) { + throw new Error(Constructor.name + ' must reject the enumerable Symbol key before reading its value'); + } + } + } + } + return 'ok'; +})() +"#).unwrap(); + assert_eq!(result, "ok"); +}