diff --git a/moli-renderer-v8/src/context_bootstrap/indexed_db/core/keys/key_path.rs b/moli-renderer-v8/src/context_bootstrap/indexed_db/core/keys/key_path.rs index 7242fee87d..51bbfacce1 100644 --- a/moli-renderer-v8/src/context_bootstrap/indexed_db/core/keys/key_path.rs +++ b/moli-renderer-v8/src/context_bootstrap/indexed_db/core/keys/key_path.rs @@ -7,9 +7,12 @@ pub(in crate::context_bootstrap::indexed_db) fn parse_idb_key_path<'s>( value: v8::Local<'s, v8::Value>, context: webidl::Context, ) -> Result { - if should_parse_key_path_sequence(scope, value, context)? { - let key_path = - webidl::convert::>(scope, value, context)?; + if let Some(key_path) = webidl::convert_optional_sequence::( + scope, + value, + context, + &Default::default(), + )? { return Ok(KeyPath::Sequence( key_path.0.into_iter().map(Into::into).collect(), )); @@ -60,22 +63,3 @@ pub(in crate::context_bootstrap::indexed_db) fn key_path_from_js_value<'s>( .to_string(scope) .map(|value| KeyPath::String(value.to_rust_string_lossy(scope))) } - -fn should_parse_key_path_sequence<'s>( - scope: &mut v8::PinScope<'s, '_>, - value: v8::Local<'s, v8::Value>, - context: webidl::Context, -) -> Result { - if value.is_string() { - return Ok(false); - } - let Ok(object) = v8::Local::::try_from(value) else { - return Ok(false); - }; - let iterator_key = v8::Symbol::get_iterator(scope); - let Some(iterator) = webidl::symbol_property_result(scope, object, iterator_key, context)? - else { - return Ok(false); - }; - Ok(!iterator.is_null_or_undefined()) -} diff --git a/moli-renderer-v8/src/script_vm/tests/indexed_db.rs b/moli-renderer-v8/src/script_vm/tests/indexed_db.rs index b91e0fff39..b7d0478876 100644 --- a/moli-renderer-v8/src/script_vm/tests/indexed_db.rs +++ b/moli-renderer-v8/src/script_vm/tests/indexed_db.rs @@ -5773,3 +5773,40 @@ fn indexed_db_put_rejects_non_serializable_platform_objects() { assert_eq!(result, "DataCloneError|DataCloneError|DataCloneError"); } + +#[test] +fn indexed_db_key_path_reads_iterator_once() { + let mut vm = new_storage_page_task_executor_test_vm("https://key-path-iterator.test/"); + vm.eval( + r#" + globalThis.keyPathResult = 'pending'; + const open = indexedDB.open('key-path-iterator', 1); + open.onupgradeneeded = () => { + try { + let reads = 0; + const keyPath = { + get [Symbol.iterator]() { + if (++reads > 1) throw new Error('iterator read twice'); + return function* () { yield 'id'; }; + } + }; + const store = open.result.createObjectStore('values', {keyPath}); + if (reads !== 1 || String(store.keyPath) !== 'id') throw new Error('store key path'); + reads = 0; + const index = store.createIndex('by-id', keyPath); + if (reads !== 1 || String(index.keyPath) !== 'id') throw new Error('index key path'); + const sentinel = {}; + const throwing = {get [Symbol.iterator]() { throw sentinel; }}; + try { store.createIndex('throws', throwing); throw new Error('missing exception'); } + catch (error) { if (error !== sentinel) throw error; } + globalThis.keyPathResult = 'pass'; + } catch (error) { globalThis.keyPathResult = String(error); } + }; + "#, + ) + .unwrap(); + assert_eq!( + vm.eval_after_selected_page_tasks("keyPathResult").unwrap(), + "pass" + ); +}