mirror of
https://github.com/lexmount/moli.git
synced 2026-10-06 00:00:56 +00:00
fix(indexeddb): convert iterable key paths only once
This commit is contained in:
@@ -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<KeyPath, webidl::WebIdlError> {
|
||||
if should_parse_key_path_sequence(scope, value, context)? {
|
||||
let key_path =
|
||||
webidl::convert::<webidl::Sequence<webidl::DomString>>(scope, value, context)?;
|
||||
if let Some(key_path) = webidl::convert_optional_sequence::<webidl::DomString>(
|
||||
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<bool, webidl::WebIdlError> {
|
||||
if value.is_string() {
|
||||
return Ok(false);
|
||||
}
|
||||
let Ok(object) = v8::Local::<v8::Object>::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())
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user