mirror of
https://github.com/servo/servo.git
synced 2025-06-25 17:44:33 +01:00
Initial IndexedDB Support (#33044)
Adds indexeddb support to servo. At the moment heed is being used as the backend, although this can be swapped out by implementing `KvsEngine`. This PR adds a thread + a thread pool for Indexeddb related operations. Also `database_access_task_source` is added for Indexeddb related operations. This is a partial rewrite of #25214. (Reopened due to branching issue) Fixes #6963 --------- Signed-off-by: Ashwin Naren <arihant2math@gmail.com> Signed-off-by: Josh Matthews <josh@joshmatthews.net> Co-authored-by: Rasmus Viitanen <rasviitanen@gmail.com> Co-authored-by: Josh Matthews <josh@joshmatthews.net>
This commit is contained in:
parent
d33cf8fbd1
commit
ed9a79f3f4
259 changed files with 11141 additions and 8 deletions
88
Cargo.lock
generated
88
Cargo.lock
generated
|
@ -1425,6 +1425,15 @@ dependencies = [
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-queue"
|
||||||
|
version = "0.3.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-utils"
|
name = "crossbeam-utils"
|
||||||
version = "0.8.21"
|
version = "0.8.21"
|
||||||
|
@ -1772,6 +1781,15 @@ version = "1.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
|
checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "doxygen-rs"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "415b6ec780d34dcf624666747194393603d0373b7141eef01d12ee58881507d9"
|
||||||
|
dependencies = [
|
||||||
|
"phf",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dpi"
|
name = "dpi"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
|
@ -3221,6 +3239,44 @@ version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heed"
|
||||||
|
version = "0.20.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7d4f449bab7320c56003d37732a917e18798e2f1709d80263face2b4f9436ddb"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.9.1",
|
||||||
|
"byteorder",
|
||||||
|
"heed-traits",
|
||||||
|
"heed-types",
|
||||||
|
"libc",
|
||||||
|
"lmdb-master-sys",
|
||||||
|
"once_cell",
|
||||||
|
"page_size",
|
||||||
|
"serde",
|
||||||
|
"synchronoise",
|
||||||
|
"url",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heed-traits"
|
||||||
|
version = "0.20.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eb3130048d404c57ce5a1ac61a903696e8fcde7e8c2991e9fcfc1f27c3ef74ff"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heed-types"
|
||||||
|
version = "0.20.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9d3f528b053a6d700b2734eabcd0fd49cb8230647aa72958467527b0b7917114"
|
||||||
|
dependencies = [
|
||||||
|
"bincode",
|
||||||
|
"byteorder",
|
||||||
|
"heed-traits",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
|
@ -4457,6 +4513,17 @@ version = "0.4.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5"
|
checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lmdb-master-sys"
|
||||||
|
version = "0.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "864808e0b19fb6dd3b70ba94ee671b82fce17554cf80aeb0a155c65bb08027df"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"doxygen-rs",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lock_api"
|
name = "lock_api"
|
||||||
version = "0.4.13"
|
version = "0.4.13"
|
||||||
|
@ -4868,6 +4935,7 @@ dependencies = [
|
||||||
"async-tungstenite",
|
"async-tungstenite",
|
||||||
"base",
|
"base",
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
|
"bincode",
|
||||||
"bytes",
|
"bytes",
|
||||||
"chrono",
|
"chrono",
|
||||||
"compositing_traits",
|
"compositing_traits",
|
||||||
|
@ -4884,6 +4952,7 @@ dependencies = [
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"generic-array",
|
"generic-array",
|
||||||
"headers 0.4.1",
|
"headers 0.4.1",
|
||||||
|
"heed",
|
||||||
"http 1.3.1",
|
"http 1.3.1",
|
||||||
"http-body-util",
|
"http-body-util",
|
||||||
"hyper 1.6.0",
|
"hyper 1.6.0",
|
||||||
|
@ -5581,6 +5650,16 @@ dependencies = [
|
||||||
"ttf-parser",
|
"ttf-parser",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "page_size"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "30d5b2194ed13191c1999ae0704b7839fb18384fa22e49b57eeaa97d79ce40da"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot"
|
name = "parking_lot"
|
||||||
version = "0.12.4"
|
version = "0.12.4"
|
||||||
|
@ -7671,6 +7750,15 @@ dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "synchronoise"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3dbc01390fc626ce8d1cffe3376ded2b72a11bb70e1c75f404a210e4daa4def2"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-queue",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "synstructure"
|
name = "synstructure"
|
||||||
version = "0.13.2"
|
version = "0.13.2"
|
||||||
|
|
|
@ -85,6 +85,7 @@ pub struct Preferences {
|
||||||
pub dom_fullscreen_test: bool,
|
pub dom_fullscreen_test: bool,
|
||||||
pub dom_gamepad_enabled: bool,
|
pub dom_gamepad_enabled: bool,
|
||||||
pub dom_imagebitmap_enabled: bool,
|
pub dom_imagebitmap_enabled: bool,
|
||||||
|
pub dom_indexeddb_enabled: bool,
|
||||||
pub dom_intersection_observer_enabled: bool,
|
pub dom_intersection_observer_enabled: bool,
|
||||||
pub dom_microdata_testing_enabled: bool,
|
pub dom_microdata_testing_enabled: bool,
|
||||||
pub dom_mouse_event_which_enabled: bool,
|
pub dom_mouse_event_which_enabled: bool,
|
||||||
|
@ -258,6 +259,7 @@ impl Preferences {
|
||||||
dom_fullscreen_test: false,
|
dom_fullscreen_test: false,
|
||||||
dom_gamepad_enabled: true,
|
dom_gamepad_enabled: true,
|
||||||
dom_imagebitmap_enabled: false,
|
dom_imagebitmap_enabled: false,
|
||||||
|
dom_indexeddb_enabled: false,
|
||||||
dom_intersection_observer_enabled: false,
|
dom_intersection_observer_enabled: false,
|
||||||
dom_microdata_testing_enabled: false,
|
dom_microdata_testing_enabled: false,
|
||||||
dom_mouse_event_which_enabled: false,
|
dom_mouse_event_which_enabled: false,
|
||||||
|
|
|
@ -47,7 +47,9 @@ mod font_context {
|
||||||
let (system_font_service, system_font_service_proxy) = MockSystemFontService::spawn();
|
let (system_font_service, system_font_service_proxy) = MockSystemFontService::spawn();
|
||||||
let (core_sender, _) = ipc::channel().unwrap();
|
let (core_sender, _) = ipc::channel().unwrap();
|
||||||
let (storage_sender, _) = ipc::channel().unwrap();
|
let (storage_sender, _) = ipc::channel().unwrap();
|
||||||
let mock_resource_threads = ResourceThreads::new(core_sender, storage_sender);
|
let (indexeddb_sender, _) = ipc::channel().unwrap();
|
||||||
|
let mock_resource_threads =
|
||||||
|
ResourceThreads::new(core_sender, storage_sender, indexeddb_sender);
|
||||||
let mock_compositor_api = CrossProcessCompositorApi::dummy();
|
let mock_compositor_api = CrossProcessCompositorApi::dummy();
|
||||||
|
|
||||||
let proxy_clone = Arc::new(system_font_service_proxy.to_sender().to_proxy());
|
let proxy_clone = Arc::new(system_font_service_proxy.to_sender().to_proxy());
|
||||||
|
|
|
@ -20,6 +20,7 @@ async-recursion = "1.1"
|
||||||
async-tungstenite = { workspace = true }
|
async-tungstenite = { workspace = true }
|
||||||
base = { workspace = true }
|
base = { workspace = true }
|
||||||
base64 = { workspace = true }
|
base64 = { workspace = true }
|
||||||
|
bincode = { workspace = true }
|
||||||
bytes = "1"
|
bytes = "1"
|
||||||
chrono = { workspace = true }
|
chrono = { workspace = true }
|
||||||
compositing_traits = { workspace = true }
|
compositing_traits = { workspace = true }
|
||||||
|
@ -35,6 +36,7 @@ futures-core = { version = "0.3.30", default-features = false }
|
||||||
futures-util = { version = "0.3.30", default-features = false }
|
futures-util = { version = "0.3.30", default-features = false }
|
||||||
generic-array = "0.14"
|
generic-array = "0.14"
|
||||||
headers = { workspace = true }
|
headers = { workspace = true }
|
||||||
|
heed = "0.20"
|
||||||
http = { workspace = true }
|
http = { workspace = true }
|
||||||
http-body-util = { workspace = true }
|
http-body-util = { workspace = true }
|
||||||
hyper = { workspace = true, features = ["client", "http1", "http2"] }
|
hyper = { workspace = true, features = ["client", "http1", "http2"] }
|
||||||
|
|
251
components/net/indexeddb/engines/heed.rs
Normal file
251
components/net/indexeddb/engines/heed.rs
Normal file
|
@ -0,0 +1,251 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
|
use heed::types::*;
|
||||||
|
use heed::{Database, Env, EnvOpenOptions};
|
||||||
|
use log::warn;
|
||||||
|
use net_traits::indexeddb_thread::{AsyncOperation, IndexedDBTxnMode};
|
||||||
|
use tokio::sync::oneshot;
|
||||||
|
|
||||||
|
use super::{KvsEngine, KvsTransaction, SanitizedName};
|
||||||
|
use crate::resource_thread::CoreResourceThreadPool;
|
||||||
|
|
||||||
|
type HeedDatabase = Database<Bytes, Bytes>;
|
||||||
|
|
||||||
|
// A simple store that also has a key generator that can be used if no key
|
||||||
|
// is provided for the stored objects
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct Store {
|
||||||
|
inner: HeedDatabase,
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#key-generator
|
||||||
|
key_generator: Option<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct HeedEngine {
|
||||||
|
heed_env: Arc<Env>,
|
||||||
|
open_stores: Arc<RwLock<HashMap<SanitizedName, Store>>>,
|
||||||
|
read_pool: Arc<CoreResourceThreadPool>,
|
||||||
|
write_pool: Arc<CoreResourceThreadPool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HeedEngine {
|
||||||
|
pub fn new(
|
||||||
|
base_dir: &Path,
|
||||||
|
db_file_name: &Path,
|
||||||
|
thread_pool: Arc<CoreResourceThreadPool>,
|
||||||
|
) -> Self {
|
||||||
|
let mut db_dir = PathBuf::new();
|
||||||
|
db_dir.push(base_dir);
|
||||||
|
db_dir.push(db_file_name);
|
||||||
|
|
||||||
|
std::fs::create_dir_all(&db_dir).expect("Could not create OS directory for idb");
|
||||||
|
// FIXME:(arihant2math) gracefully handle errors like hitting max dbs
|
||||||
|
#[allow(unsafe_code)]
|
||||||
|
let env = unsafe {
|
||||||
|
EnvOpenOptions::new()
|
||||||
|
.max_dbs(1024)
|
||||||
|
.open(db_dir)
|
||||||
|
.expect("Failed to open db_dir")
|
||||||
|
};
|
||||||
|
Self {
|
||||||
|
heed_env: Arc::new(env),
|
||||||
|
open_stores: Arc::new(RwLock::new(HashMap::new())),
|
||||||
|
read_pool: thread_pool.clone(),
|
||||||
|
write_pool: thread_pool,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KvsEngine for HeedEngine {
|
||||||
|
fn create_store(&self, store_name: SanitizedName, auto_increment: bool) {
|
||||||
|
let mut write_txn = self
|
||||||
|
.heed_env
|
||||||
|
.write_txn()
|
||||||
|
.expect("Could not create idb store writer");
|
||||||
|
let _ = self.heed_env.clear_stale_readers();
|
||||||
|
let new_store: HeedDatabase = self
|
||||||
|
.heed_env
|
||||||
|
.create_database(&mut write_txn, Some(&*store_name.to_string()))
|
||||||
|
.expect("Failed to create idb store");
|
||||||
|
|
||||||
|
let key_generator = { if auto_increment { Some(0) } else { None } };
|
||||||
|
|
||||||
|
let store = Store {
|
||||||
|
inner: new_store,
|
||||||
|
key_generator,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.open_stores
|
||||||
|
.write()
|
||||||
|
.expect("Could not acquire lock on stores")
|
||||||
|
.insert(store_name, store);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn delete_store(&self, store_name: SanitizedName) {
|
||||||
|
// TODO: Actually delete store instead of just clearing it
|
||||||
|
let mut write_txn = self
|
||||||
|
.heed_env
|
||||||
|
.write_txn()
|
||||||
|
.expect("Could not create idb store writer");
|
||||||
|
let store: HeedDatabase = self
|
||||||
|
.heed_env
|
||||||
|
.create_database(&mut write_txn, Some(&*store_name.to_string()))
|
||||||
|
.expect("Failed to create idb store");
|
||||||
|
store.clear(&mut write_txn).expect("Could not clear store");
|
||||||
|
let mut open_stores = self.open_stores.write().unwrap();
|
||||||
|
open_stores.retain(|key, _| key != &store_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn close_store(&self, store_name: SanitizedName) {
|
||||||
|
// FIXME: (arihant2math) unused
|
||||||
|
// FIXME:(arihant2math) return error if no store ...
|
||||||
|
let mut open_stores = self.open_stores.write().unwrap();
|
||||||
|
open_stores.retain(|key, _| key != &store_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Starts a transaction, processes all operations for that transaction,
|
||||||
|
// and commits the changes.
|
||||||
|
fn process_transaction(
|
||||||
|
&self,
|
||||||
|
transaction: KvsTransaction,
|
||||||
|
) -> oneshot::Receiver<Option<Vec<u8>>> {
|
||||||
|
// This executes in a thread pool, and `readwrite` transactions
|
||||||
|
// will block their thread if the writer is occupied, so we can
|
||||||
|
// probably do some smart things here in order to optimize.
|
||||||
|
// Queueing 8 writers will for example block 7 threads,
|
||||||
|
// so write operations are reserved for just one thread,
|
||||||
|
// so that the rest of the threads can work in parallel with read txns.
|
||||||
|
let heed_env = self.heed_env.clone();
|
||||||
|
let stores = self.open_stores.clone();
|
||||||
|
|
||||||
|
let (tx, rx) = oneshot::channel();
|
||||||
|
if let IndexedDBTxnMode::Readonly = transaction.mode {
|
||||||
|
self.read_pool.spawn(move || {
|
||||||
|
let env = heed_env;
|
||||||
|
let rtxn = env.read_txn().expect("Could not create idb store reader");
|
||||||
|
for request in transaction.requests {
|
||||||
|
match request.operation {
|
||||||
|
AsyncOperation::GetItem(key) => {
|
||||||
|
let key: Vec<u8> = bincode::serialize(&key).unwrap();
|
||||||
|
let stores = stores
|
||||||
|
.read()
|
||||||
|
.expect("Could not acquire read lock on stores");
|
||||||
|
let store = stores
|
||||||
|
.get(&request.store_name)
|
||||||
|
.expect("Could not get store");
|
||||||
|
let result = store.inner.get(&rtxn, &key).expect("Could not get item");
|
||||||
|
|
||||||
|
if let Some(blob) = result {
|
||||||
|
let _ = request.sender.send(Some(blob.to_vec()));
|
||||||
|
} else {
|
||||||
|
let _ = request.sender.send(None);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
// We cannot reach this, as checks are made earlier so that
|
||||||
|
// no modifying requests are executed on readonly transactions
|
||||||
|
unreachable!(
|
||||||
|
"Cannot execute modifying request with readonly transactions"
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if tx.send(None).is_err() {
|
||||||
|
warn!("IDBTransaction's execution channel is dropped");
|
||||||
|
};
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
self.write_pool.spawn(move || {
|
||||||
|
// Acquiring a writer will block the thread if another `readwrite` transaction is active
|
||||||
|
let env = heed_env;
|
||||||
|
let mut wtxn = env.write_txn().expect("Could not creat idb store writer");
|
||||||
|
for request in transaction.requests {
|
||||||
|
match request.operation {
|
||||||
|
AsyncOperation::PutItem(key, value, overwrite) => {
|
||||||
|
let key: Vec<u8> = bincode::serialize(&key).unwrap();
|
||||||
|
let stores = stores
|
||||||
|
.write()
|
||||||
|
.expect("Could not acquire write lock on stores");
|
||||||
|
let store = stores
|
||||||
|
.get(&request.store_name)
|
||||||
|
.expect("Could not get store");
|
||||||
|
if overwrite {
|
||||||
|
let result =
|
||||||
|
store.inner.put(&mut wtxn, &key, &value).ok().and(Some(key));
|
||||||
|
request.sender.send(result).unwrap();
|
||||||
|
} else if store
|
||||||
|
.inner
|
||||||
|
.get(&wtxn, &key)
|
||||||
|
.expect("Could not get item")
|
||||||
|
.is_none()
|
||||||
|
{
|
||||||
|
let result =
|
||||||
|
store.inner.put(&mut wtxn, &key, &value).ok().and(Some(key));
|
||||||
|
let _ = request.sender.send(result);
|
||||||
|
} else {
|
||||||
|
let _ = request.sender.send(None);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
AsyncOperation::GetItem(key) => {
|
||||||
|
let key: Vec<u8> = bincode::serialize(&key).unwrap();
|
||||||
|
let stores = stores
|
||||||
|
.read()
|
||||||
|
.expect("Could not acquire write lock on stores");
|
||||||
|
let store = stores
|
||||||
|
.get(&request.store_name)
|
||||||
|
.expect("Could not get store");
|
||||||
|
let result = store.inner.get(&wtxn, &key).expect("Could not get item");
|
||||||
|
|
||||||
|
if let Some(blob) = result {
|
||||||
|
let _ = request.sender.send(Some(blob.to_vec()));
|
||||||
|
} else {
|
||||||
|
let _ = request.sender.send(None);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
AsyncOperation::RemoveItem(key) => {
|
||||||
|
let key: Vec<u8> = bincode::serialize(&key).unwrap();
|
||||||
|
let stores = stores
|
||||||
|
.write()
|
||||||
|
.expect("Could not acquire write lock on stores");
|
||||||
|
let store = stores
|
||||||
|
.get(&request.store_name)
|
||||||
|
.expect("Could not get store");
|
||||||
|
let result = store.inner.delete(&mut wtxn, &key).ok().and(Some(key));
|
||||||
|
let _ = request.sender.send(result);
|
||||||
|
},
|
||||||
|
AsyncOperation::Count(key) => {
|
||||||
|
let _key: Vec<u8> = bincode::serialize(&key).unwrap();
|
||||||
|
let stores = stores
|
||||||
|
.read()
|
||||||
|
.expect("Could not acquire read lock on stores");
|
||||||
|
let _store = stores
|
||||||
|
.get(&request.store_name)
|
||||||
|
.expect("Could not get store");
|
||||||
|
// FIXME:(arihant2math) Return count with sender
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wtxn.commit().expect("Failed to commit to database");
|
||||||
|
})
|
||||||
|
}
|
||||||
|
rx
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_key_generator(&self, store_name: SanitizedName) -> bool {
|
||||||
|
let has_generator = self
|
||||||
|
.open_stores
|
||||||
|
.read()
|
||||||
|
.expect("Could not acquire read lock on stores")
|
||||||
|
.get(&store_name)
|
||||||
|
.expect("Store not found")
|
||||||
|
.key_generator
|
||||||
|
.is_some();
|
||||||
|
has_generator
|
||||||
|
}
|
||||||
|
}
|
73
components/net/indexeddb/engines/mod.rs
Normal file
73
components/net/indexeddb/engines/mod.rs
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
|
use ipc_channel::ipc::IpcSender;
|
||||||
|
use net_traits::indexeddb_thread::{AsyncOperation, IndexedDBTxnMode};
|
||||||
|
use tokio::sync::oneshot;
|
||||||
|
|
||||||
|
pub use self::heed::HeedEngine;
|
||||||
|
|
||||||
|
mod heed;
|
||||||
|
|
||||||
|
#[derive(Eq, Hash, PartialEq)]
|
||||||
|
pub struct SanitizedName {
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SanitizedName {
|
||||||
|
pub fn new(name: String) -> SanitizedName {
|
||||||
|
let name = name.replace("https://", "");
|
||||||
|
let name = name.replace("http://", "");
|
||||||
|
// FIXME:(arihant2math) Disallowing special characters might be a big problem,
|
||||||
|
// but better safe than sorry. E.g. the db name '../other_origin/db',
|
||||||
|
// would let us access databases from another origin.
|
||||||
|
let name = name
|
||||||
|
.chars()
|
||||||
|
.map(|c| match c {
|
||||||
|
'A'..='Z' => c,
|
||||||
|
'a'..='z' => c,
|
||||||
|
'0'..='9' => c,
|
||||||
|
'-' => c,
|
||||||
|
'_' => c,
|
||||||
|
_ => '-',
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
SanitizedName { name }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for SanitizedName {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}", self.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct KvsOperation {
|
||||||
|
pub sender: IpcSender<Option<Vec<u8>>>,
|
||||||
|
pub store_name: SanitizedName,
|
||||||
|
pub operation: AsyncOperation,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct KvsTransaction {
|
||||||
|
pub mode: IndexedDBTxnMode,
|
||||||
|
pub requests: VecDeque<KvsOperation>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait KvsEngine {
|
||||||
|
fn create_store(&self, store_name: SanitizedName, auto_increment: bool);
|
||||||
|
|
||||||
|
fn delete_store(&self, store_name: SanitizedName);
|
||||||
|
|
||||||
|
#[expect(dead_code)]
|
||||||
|
fn close_store(&self, store_name: SanitizedName);
|
||||||
|
|
||||||
|
fn process_transaction(
|
||||||
|
&self,
|
||||||
|
transaction: KvsTransaction,
|
||||||
|
) -> oneshot::Receiver<Option<Vec<u8>>>;
|
||||||
|
|
||||||
|
fn has_key_generator(&self, store_name: SanitizedName) -> bool;
|
||||||
|
}
|
374
components/net/indexeddb/idb_thread.rs
Normal file
374
components/net/indexeddb/idb_thread.rs
Normal file
|
@ -0,0 +1,374 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
use std::borrow::ToOwned;
|
||||||
|
use std::collections::hash_map::Entry;
|
||||||
|
use std::collections::{HashMap, VecDeque};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::thread;
|
||||||
|
|
||||||
|
use ipc_channel::ipc::{self, IpcError, IpcReceiver, IpcSender};
|
||||||
|
use log::{debug, warn};
|
||||||
|
use net_traits::indexeddb_thread::{
|
||||||
|
AsyncOperation, IndexedDBThreadMsg, IndexedDBThreadReturnType, IndexedDBTxnMode, SyncOperation,
|
||||||
|
};
|
||||||
|
use servo_config::pref;
|
||||||
|
use servo_url::origin::ImmutableOrigin;
|
||||||
|
|
||||||
|
use crate::indexeddb::engines::{
|
||||||
|
HeedEngine, KvsEngine, KvsOperation, KvsTransaction, SanitizedName,
|
||||||
|
};
|
||||||
|
use crate::resource_thread::CoreResourceThreadPool;
|
||||||
|
|
||||||
|
pub trait IndexedDBThreadFactory {
|
||||||
|
fn new(config_dir: Option<PathBuf>) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IndexedDBThreadFactory for IpcSender<IndexedDBThreadMsg> {
|
||||||
|
fn new(config_dir: Option<PathBuf>) -> IpcSender<IndexedDBThreadMsg> {
|
||||||
|
let (chan, port) = ipc::channel().unwrap();
|
||||||
|
|
||||||
|
let mut idb_base_dir = PathBuf::new();
|
||||||
|
if let Some(p) = config_dir {
|
||||||
|
idb_base_dir.push(p);
|
||||||
|
}
|
||||||
|
idb_base_dir.push("IndexedDB");
|
||||||
|
|
||||||
|
thread::Builder::new()
|
||||||
|
.name("IndexedDBManager".to_owned())
|
||||||
|
.spawn(move || {
|
||||||
|
IndexedDBManager::new(port, idb_base_dir).start();
|
||||||
|
})
|
||||||
|
.expect("Thread spawning failed");
|
||||||
|
|
||||||
|
chan
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Eq, Hash, PartialEq)]
|
||||||
|
pub struct IndexedDBDescription {
|
||||||
|
origin: ImmutableOrigin,
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IndexedDBDescription {
|
||||||
|
// Converts the database description to a folder name where all
|
||||||
|
// data for this database is stored
|
||||||
|
fn as_path(&self) -> PathBuf {
|
||||||
|
let mut path = PathBuf::new();
|
||||||
|
|
||||||
|
let sanitized_origin = SanitizedName::new(self.origin.ascii_serialization());
|
||||||
|
let sanitized_name = SanitizedName::new(self.name.clone());
|
||||||
|
path.push(sanitized_origin.to_string());
|
||||||
|
path.push(sanitized_name.to_string());
|
||||||
|
|
||||||
|
path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct IndexedDBEnvironment<E: KvsEngine> {
|
||||||
|
engine: E,
|
||||||
|
version: u64,
|
||||||
|
|
||||||
|
transactions: HashMap<u64, KvsTransaction>,
|
||||||
|
serial_number_counter: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: KvsEngine> IndexedDBEnvironment<E> {
|
||||||
|
fn new(engine: E, version: u64) -> IndexedDBEnvironment<E> {
|
||||||
|
IndexedDBEnvironment {
|
||||||
|
engine,
|
||||||
|
version,
|
||||||
|
|
||||||
|
transactions: HashMap::new(),
|
||||||
|
serial_number_counter: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn queue_operation(
|
||||||
|
&mut self,
|
||||||
|
sender: IpcSender<Option<Vec<u8>>>,
|
||||||
|
store_name: SanitizedName,
|
||||||
|
serial_number: u64,
|
||||||
|
mode: IndexedDBTxnMode,
|
||||||
|
operation: AsyncOperation,
|
||||||
|
) {
|
||||||
|
self.transactions
|
||||||
|
.entry(serial_number)
|
||||||
|
.or_insert_with(|| KvsTransaction {
|
||||||
|
requests: VecDeque::new(),
|
||||||
|
mode,
|
||||||
|
})
|
||||||
|
.requests
|
||||||
|
.push_back(KvsOperation {
|
||||||
|
sender,
|
||||||
|
operation,
|
||||||
|
store_name,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Executes all requests for a transaction (without committing)
|
||||||
|
fn start_transaction(&mut self, txn: u64, sender: Option<IpcSender<Result<(), ()>>>) {
|
||||||
|
// FIXME:(arihant2math) find a way to optimizations in this function
|
||||||
|
// rather than on the engine level code (less repetition)
|
||||||
|
if let Some(txn) = self.transactions.remove(&txn) {
|
||||||
|
let _ = self.engine.process_transaction(txn).blocking_recv();
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have a sender if the transaction is started manually, and they
|
||||||
|
// probably want to know when it is finished
|
||||||
|
if let Some(sender) = sender {
|
||||||
|
if sender.send(Ok(())).is_err() {
|
||||||
|
warn!("IDBTransaction starter dropped its channel");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_key_generator(&self, store_name: SanitizedName) -> bool {
|
||||||
|
self.engine.has_key_generator(store_name)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_object_store(
|
||||||
|
&mut self,
|
||||||
|
sender: IpcSender<Result<(), ()>>,
|
||||||
|
store_name: SanitizedName,
|
||||||
|
auto_increment: bool,
|
||||||
|
) {
|
||||||
|
self.engine.create_store(store_name, auto_increment);
|
||||||
|
|
||||||
|
let _ = sender.send(Ok(()));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn delete_object_store(
|
||||||
|
&mut self,
|
||||||
|
sender: IpcSender<Result<(), ()>>,
|
||||||
|
store_name: SanitizedName,
|
||||||
|
) {
|
||||||
|
self.engine.delete_store(store_name);
|
||||||
|
|
||||||
|
let _ = sender.send(Ok(()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct IndexedDBManager {
|
||||||
|
port: IpcReceiver<IndexedDBThreadMsg>,
|
||||||
|
idb_base_dir: PathBuf,
|
||||||
|
databases: HashMap<IndexedDBDescription, IndexedDBEnvironment<HeedEngine>>,
|
||||||
|
thread_pool: Arc<CoreResourceThreadPool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IndexedDBManager {
|
||||||
|
fn new(port: IpcReceiver<IndexedDBThreadMsg>, idb_base_dir: PathBuf) -> IndexedDBManager {
|
||||||
|
debug!("New indexedDBManager");
|
||||||
|
|
||||||
|
let thread_count = thread::available_parallelism()
|
||||||
|
.map(|i| i.get())
|
||||||
|
.unwrap_or(pref!(threadpools_fallback_worker_num) as usize)
|
||||||
|
.min(pref!(threadpools_async_runtime_workers_max).max(1) as usize);
|
||||||
|
IndexedDBManager {
|
||||||
|
port,
|
||||||
|
idb_base_dir,
|
||||||
|
databases: HashMap::new(),
|
||||||
|
thread_pool: Arc::new(CoreResourceThreadPool::new(
|
||||||
|
thread_count,
|
||||||
|
"ImageCache".to_string(),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IndexedDBManager {
|
||||||
|
fn start(&mut self) {
|
||||||
|
if !pref!(dom_indexeddb_enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
loop {
|
||||||
|
// FIXME:(arihant2math) No message *most likely* means that
|
||||||
|
// the ipc sender has been dropped, so we break the look
|
||||||
|
let message = match self.port.recv() {
|
||||||
|
Ok(msg) => msg,
|
||||||
|
Err(e) => match e {
|
||||||
|
IpcError::Disconnected => {
|
||||||
|
break;
|
||||||
|
},
|
||||||
|
other => {
|
||||||
|
warn!("Error in IndexedDB thread: {:?}", other);
|
||||||
|
continue;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
match message {
|
||||||
|
IndexedDBThreadMsg::Sync(operation) => {
|
||||||
|
self.handle_sync_operation(operation);
|
||||||
|
},
|
||||||
|
IndexedDBThreadMsg::Async(
|
||||||
|
sender,
|
||||||
|
origin,
|
||||||
|
db_name,
|
||||||
|
store_name,
|
||||||
|
txn,
|
||||||
|
mode,
|
||||||
|
operation,
|
||||||
|
) => {
|
||||||
|
let store_name = SanitizedName::new(store_name);
|
||||||
|
if let Some(db) = self.get_database_mut(origin, db_name) {
|
||||||
|
// Queues an operation for a transaction without starting it
|
||||||
|
db.queue_operation(sender, store_name, txn, mode, operation);
|
||||||
|
// FIXME:(arihant2math) Schedule transactions properly:
|
||||||
|
// for now, we start them directly.
|
||||||
|
db.start_transaction(txn, None);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_database(
|
||||||
|
&self,
|
||||||
|
origin: ImmutableOrigin,
|
||||||
|
db_name: String,
|
||||||
|
) -> Option<&IndexedDBEnvironment<HeedEngine>> {
|
||||||
|
let idb_description = IndexedDBDescription {
|
||||||
|
origin,
|
||||||
|
name: db_name,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.databases.get(&idb_description)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_database_mut(
|
||||||
|
&mut self,
|
||||||
|
origin: ImmutableOrigin,
|
||||||
|
db_name: String,
|
||||||
|
) -> Option<&mut IndexedDBEnvironment<HeedEngine>> {
|
||||||
|
let idb_description = IndexedDBDescription {
|
||||||
|
origin,
|
||||||
|
name: db_name,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.databases.get_mut(&idb_description)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_sync_operation(&mut self, operation: SyncOperation) {
|
||||||
|
match operation {
|
||||||
|
SyncOperation::CloseDatabase(sender, origin, db_name) => {
|
||||||
|
let idb_description = IndexedDBDescription {
|
||||||
|
origin,
|
||||||
|
name: db_name,
|
||||||
|
};
|
||||||
|
if let Some(_db) = self.databases.remove(&idb_description) {
|
||||||
|
// TODO: maybe close store here?
|
||||||
|
}
|
||||||
|
let _ = sender.send(Ok(()));
|
||||||
|
},
|
||||||
|
SyncOperation::OpenDatabase(sender, origin, db_name, version) => {
|
||||||
|
let idb_description = IndexedDBDescription {
|
||||||
|
origin,
|
||||||
|
name: db_name,
|
||||||
|
};
|
||||||
|
|
||||||
|
let idb_base_dir = self.idb_base_dir.as_path();
|
||||||
|
|
||||||
|
match self.databases.entry(idb_description.clone()) {
|
||||||
|
Entry::Vacant(e) => {
|
||||||
|
let db = IndexedDBEnvironment::new(
|
||||||
|
HeedEngine::new(
|
||||||
|
idb_base_dir,
|
||||||
|
&idb_description.as_path(),
|
||||||
|
self.thread_pool.clone(),
|
||||||
|
),
|
||||||
|
version.unwrap_or(0),
|
||||||
|
);
|
||||||
|
let _ = sender.send(db.version);
|
||||||
|
e.insert(db);
|
||||||
|
},
|
||||||
|
Entry::Occupied(db) => {
|
||||||
|
let _ = sender.send(db.get().version);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SyncOperation::DeleteDatabase(sender, origin, db_name) => {
|
||||||
|
let idb_description = IndexedDBDescription {
|
||||||
|
origin,
|
||||||
|
name: db_name,
|
||||||
|
};
|
||||||
|
self.databases.remove(&idb_description);
|
||||||
|
|
||||||
|
// FIXME:(rasviitanen) Possible security issue?
|
||||||
|
// FIXME:(arihant2math) using remove_dir_all with arbitrary input ...
|
||||||
|
let mut db_dir = self.idb_base_dir.clone();
|
||||||
|
db_dir.push(idb_description.as_path());
|
||||||
|
if std::fs::remove_dir_all(&db_dir).is_err() {
|
||||||
|
let _ = sender.send(Err(()));
|
||||||
|
} else {
|
||||||
|
let _ = sender.send(Ok(()));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SyncOperation::HasKeyGenerator(sender, origin, db_name, store_name) => {
|
||||||
|
let store_name = SanitizedName::new(store_name);
|
||||||
|
let result = self
|
||||||
|
.get_database(origin, db_name)
|
||||||
|
.map(|db| db.has_key_generator(store_name))
|
||||||
|
.expect("No Database");
|
||||||
|
sender.send(result).expect("Could not send generator info");
|
||||||
|
},
|
||||||
|
SyncOperation::Commit(sender, _origin, _db_name, _txn) => {
|
||||||
|
// FIXME:(arihant2math) This does nothing at the moment
|
||||||
|
sender
|
||||||
|
.send(IndexedDBThreadReturnType::Commit(Err(())))
|
||||||
|
.expect("Could not send commit status");
|
||||||
|
},
|
||||||
|
SyncOperation::UpgradeVersion(sender, origin, db_name, _txn, version) => {
|
||||||
|
if let Some(db) = self.get_database_mut(origin, db_name) {
|
||||||
|
db.version = version;
|
||||||
|
};
|
||||||
|
|
||||||
|
// FIXME:(arihant2math) Get the version from the database instead
|
||||||
|
// We never fail as of now, so we can just return it like this
|
||||||
|
// for now...
|
||||||
|
sender
|
||||||
|
.send(IndexedDBThreadReturnType::UpgradeVersion(Ok(version)))
|
||||||
|
.expect("Could not upgrade version");
|
||||||
|
},
|
||||||
|
SyncOperation::CreateObjectStore(
|
||||||
|
sender,
|
||||||
|
origin,
|
||||||
|
db_name,
|
||||||
|
store_name,
|
||||||
|
auto_increment,
|
||||||
|
) => {
|
||||||
|
let store_name = SanitizedName::new(store_name);
|
||||||
|
if let Some(db) = self.get_database_mut(origin, db_name) {
|
||||||
|
db.create_object_store(sender, store_name, auto_increment);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SyncOperation::DeleteObjectStore(sender, origin, db_name, store_name) => {
|
||||||
|
let store_name = SanitizedName::new(store_name);
|
||||||
|
if let Some(db) = self.get_database_mut(origin, db_name) {
|
||||||
|
db.delete_object_store(sender, store_name);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SyncOperation::StartTransaction(sender, origin, db_name, txn) => {
|
||||||
|
if let Some(db) = self.get_database_mut(origin, db_name) {
|
||||||
|
db.start_transaction(txn, Some(sender));
|
||||||
|
};
|
||||||
|
},
|
||||||
|
SyncOperation::Version(sender, origin, db_name) => {
|
||||||
|
if let Some(db) = self.get_database(origin, db_name) {
|
||||||
|
let _ = sender.send(db.version);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
SyncOperation::RegisterNewTxn(sender, origin, db_name) => {
|
||||||
|
if let Some(db) = self.get_database_mut(origin, db_name) {
|
||||||
|
db.serial_number_counter += 1;
|
||||||
|
let _ = sender.send(db.serial_number_counter);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SyncOperation::Exit(sender) => {
|
||||||
|
// FIXME:(rasviitanen) Nothing to do?
|
||||||
|
let _ = sender.send(IndexedDBThreadReturnType::Exit);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
9
components/net/indexeddb/mod.rs
Normal file
9
components/net/indexeddb/mod.rs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
pub use self::idb_thread::IndexedDBThreadFactory;
|
||||||
|
|
||||||
|
mod engines;
|
||||||
|
|
||||||
|
pub mod idb_thread;
|
|
@ -15,6 +15,7 @@ pub mod hsts;
|
||||||
pub mod http_cache;
|
pub mod http_cache;
|
||||||
pub mod http_loader;
|
pub mod http_loader;
|
||||||
pub mod image_cache;
|
pub mod image_cache;
|
||||||
|
pub mod indexeddb;
|
||||||
pub mod local_directory_listing;
|
pub mod local_directory_listing;
|
||||||
pub mod protocols;
|
pub mod protocols;
|
||||||
pub mod request_interceptor;
|
pub mod request_interceptor;
|
||||||
|
|
|
@ -23,6 +23,7 @@ use ipc_channel::ipc::{self, IpcReceiver, IpcReceiverSet, IpcSender};
|
||||||
use log::{debug, trace, warn};
|
use log::{debug, trace, warn};
|
||||||
use net_traits::blob_url_store::parse_blob_url;
|
use net_traits::blob_url_store::parse_blob_url;
|
||||||
use net_traits::filemanager_thread::FileTokenCheck;
|
use net_traits::filemanager_thread::FileTokenCheck;
|
||||||
|
use net_traits::indexeddb_thread::IndexedDBThreadMsg;
|
||||||
use net_traits::pub_domains::public_suffix_list_size_of;
|
use net_traits::pub_domains::public_suffix_list_size_of;
|
||||||
use net_traits::request::{Destination, RequestBuilder, RequestId};
|
use net_traits::request::{Destination, RequestBuilder, RequestId};
|
||||||
use net_traits::response::{Response, ResponseInit};
|
use net_traits::response::{Response, ResponseInit};
|
||||||
|
@ -56,6 +57,7 @@ use crate::filemanager_thread::FileManager;
|
||||||
use crate::hsts::{self, HstsList};
|
use crate::hsts::{self, HstsList};
|
||||||
use crate::http_cache::HttpCache;
|
use crate::http_cache::HttpCache;
|
||||||
use crate::http_loader::{HttpState, http_redirect_fetch};
|
use crate::http_loader::{HttpState, http_redirect_fetch};
|
||||||
|
use crate::indexeddb::idb_thread::IndexedDBThreadFactory;
|
||||||
use crate::protocols::ProtocolRegistry;
|
use crate::protocols::ProtocolRegistry;
|
||||||
use crate::request_interceptor::RequestInterceptor;
|
use crate::request_interceptor::RequestInterceptor;
|
||||||
use crate::storage_thread::StorageThreadFactory;
|
use crate::storage_thread::StorageThreadFactory;
|
||||||
|
@ -104,11 +106,12 @@ pub fn new_resource_threads(
|
||||||
ignore_certificate_errors,
|
ignore_certificate_errors,
|
||||||
protocols,
|
protocols,
|
||||||
);
|
);
|
||||||
|
let idb: IpcSender<IndexedDBThreadMsg> = IndexedDBThreadFactory::new(config_dir.clone());
|
||||||
let storage: IpcSender<StorageThreadMsg> =
|
let storage: IpcSender<StorageThreadMsg> =
|
||||||
StorageThreadFactory::new(config_dir, mem_profiler_chan);
|
StorageThreadFactory::new(config_dir, mem_profiler_chan);
|
||||||
(
|
(
|
||||||
ResourceThreads::new(public_core, storage.clone()),
|
ResourceThreads::new(public_core, storage.clone(), idb.clone()),
|
||||||
ResourceThreads::new(private_core, storage),
|
ResourceThreads::new(private_core, storage, idb),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,12 +86,15 @@ pub(crate) fn throw_dom_exception(
|
||||||
},
|
},
|
||||||
None => DOMErrorName::DataCloneError,
|
None => DOMErrorName::DataCloneError,
|
||||||
},
|
},
|
||||||
|
Error::Data => DOMErrorName::DataError,
|
||||||
|
Error::TransactionInactive => DOMErrorName::TransactionInactiveError,
|
||||||
|
Error::ReadOnly => DOMErrorName::ReadOnlyError,
|
||||||
|
Error::Version => DOMErrorName::VersionError,
|
||||||
Error::NoModificationAllowed => DOMErrorName::NoModificationAllowedError,
|
Error::NoModificationAllowed => DOMErrorName::NoModificationAllowedError,
|
||||||
Error::QuotaExceeded => DOMErrorName::QuotaExceededError,
|
Error::QuotaExceeded => DOMErrorName::QuotaExceededError,
|
||||||
Error::TypeMismatch => DOMErrorName::TypeMismatchError,
|
Error::TypeMismatch => DOMErrorName::TypeMismatchError,
|
||||||
Error::InvalidModification => DOMErrorName::InvalidModificationError,
|
Error::InvalidModification => DOMErrorName::InvalidModificationError,
|
||||||
Error::NotReadable => DOMErrorName::NotReadableError,
|
Error::NotReadable => DOMErrorName::NotReadableError,
|
||||||
Error::Data => DOMErrorName::DataError,
|
|
||||||
Error::Operation => DOMErrorName::OperationError,
|
Error::Operation => DOMErrorName::OperationError,
|
||||||
Error::NotAllowed => DOMErrorName::NotAllowedError,
|
Error::NotAllowed => DOMErrorName::NotAllowedError,
|
||||||
Error::Type(message) => unsafe {
|
Error::Type(message) => unsafe {
|
||||||
|
|
|
@ -49,9 +49,12 @@ pub(crate) enum DOMErrorName {
|
||||||
TimeoutError = DOMExceptionConstants::TIMEOUT_ERR,
|
TimeoutError = DOMExceptionConstants::TIMEOUT_ERR,
|
||||||
InvalidNodeTypeError = DOMExceptionConstants::INVALID_NODE_TYPE_ERR,
|
InvalidNodeTypeError = DOMExceptionConstants::INVALID_NODE_TYPE_ERR,
|
||||||
DataCloneError = DOMExceptionConstants::DATA_CLONE_ERR,
|
DataCloneError = DOMExceptionConstants::DATA_CLONE_ERR,
|
||||||
|
DataError,
|
||||||
|
TransactionInactiveError,
|
||||||
|
ReadOnlyError,
|
||||||
|
VersionError,
|
||||||
EncodingError,
|
EncodingError,
|
||||||
NotReadableError,
|
NotReadableError,
|
||||||
DataError,
|
|
||||||
OperationError,
|
OperationError,
|
||||||
NotAllowedError,
|
NotAllowedError,
|
||||||
}
|
}
|
||||||
|
@ -81,9 +84,12 @@ impl DOMErrorName {
|
||||||
"TimeoutError" => Some(DOMErrorName::TimeoutError),
|
"TimeoutError" => Some(DOMErrorName::TimeoutError),
|
||||||
"InvalidNodeTypeError" => Some(DOMErrorName::InvalidNodeTypeError),
|
"InvalidNodeTypeError" => Some(DOMErrorName::InvalidNodeTypeError),
|
||||||
"DataCloneError" => Some(DOMErrorName::DataCloneError),
|
"DataCloneError" => Some(DOMErrorName::DataCloneError),
|
||||||
|
"DataError" => Some(DOMErrorName::DataError),
|
||||||
|
"TransactionInactiveError" => Some(DOMErrorName::TransactionInactiveError),
|
||||||
|
"ReadOnlyError" => Some(DOMErrorName::ReadOnlyError),
|
||||||
|
"VersionError" => Some(DOMErrorName::VersionError),
|
||||||
"EncodingError" => Some(DOMErrorName::EncodingError),
|
"EncodingError" => Some(DOMErrorName::EncodingError),
|
||||||
"NotReadableError" => Some(DOMErrorName::NotReadableError),
|
"NotReadableError" => Some(DOMErrorName::NotReadableError),
|
||||||
"DataError" => Some(DOMErrorName::DataError),
|
|
||||||
"OperationError" => Some(DOMErrorName::OperationError),
|
"OperationError" => Some(DOMErrorName::OperationError),
|
||||||
"NotAllowedError" => Some(DOMErrorName::NotAllowedError),
|
"NotAllowedError" => Some(DOMErrorName::NotAllowedError),
|
||||||
_ => None,
|
_ => None,
|
||||||
|
@ -129,11 +135,20 @@ impl DOMException {
|
||||||
"The supplied node is incorrect or has an incorrect ancestor for this operation."
|
"The supplied node is incorrect or has an incorrect ancestor for this operation."
|
||||||
},
|
},
|
||||||
DOMErrorName::DataCloneError => "The object can not be cloned.",
|
DOMErrorName::DataCloneError => "The object can not be cloned.",
|
||||||
|
DOMErrorName::DataError => "Provided data is inadequate.",
|
||||||
|
DOMErrorName::TransactionInactiveError => {
|
||||||
|
"A request was placed against a transaction which is currently not active, or which is finished."
|
||||||
|
},
|
||||||
|
DOMErrorName::ReadOnlyError => {
|
||||||
|
"The mutating operation was attempted in a \"readonly\" transaction."
|
||||||
|
},
|
||||||
|
DOMErrorName::VersionError => {
|
||||||
|
"An attempt was made to open a database using a lower version than the existing version."
|
||||||
|
},
|
||||||
DOMErrorName::EncodingError => {
|
DOMErrorName::EncodingError => {
|
||||||
"The encoding operation (either encoded or decoding) failed."
|
"The encoding operation (either encoded or decoding) failed."
|
||||||
},
|
},
|
||||||
DOMErrorName::NotReadableError => "The I/O read operation failed.",
|
DOMErrorName::NotReadableError => "The I/O read operation failed.",
|
||||||
DOMErrorName::DataError => "Provided data is inadequate.",
|
|
||||||
DOMErrorName::OperationError => {
|
DOMErrorName::OperationError => {
|
||||||
"The operation failed for an operation-specific reason."
|
"The operation failed for an operation-specific reason."
|
||||||
},
|
},
|
||||||
|
|
388
components/script/dom/idbdatabase.rs
Normal file
388
components/script/dom/idbdatabase.rs
Normal file
|
@ -0,0 +1,388 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use std::cell::Cell;
|
||||||
|
|
||||||
|
use dom_struct::dom_struct;
|
||||||
|
use ipc_channel::ipc::IpcSender;
|
||||||
|
use net_traits::IpcSend;
|
||||||
|
use net_traits::indexeddb_thread::{IndexedDBThreadMsg, SyncOperation};
|
||||||
|
use profile_traits::ipc;
|
||||||
|
use stylo_atoms::Atom;
|
||||||
|
|
||||||
|
use crate::dom::bindings::cell::DomRefCell;
|
||||||
|
use crate::dom::bindings::codegen::Bindings::IDBDatabaseBinding::{
|
||||||
|
IDBDatabaseMethods, IDBObjectStoreParameters, IDBTransactionOptions,
|
||||||
|
};
|
||||||
|
use crate::dom::bindings::codegen::Bindings::IDBTransactionBinding::IDBTransactionMode;
|
||||||
|
use crate::dom::bindings::codegen::UnionTypes::StringOrStringSequence;
|
||||||
|
use crate::dom::bindings::error::{Error, Fallible};
|
||||||
|
use crate::dom::bindings::inheritance::Castable;
|
||||||
|
use crate::dom::bindings::refcounted::Trusted;
|
||||||
|
use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object};
|
||||||
|
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
|
||||||
|
use crate::dom::bindings::str::DOMString;
|
||||||
|
use crate::dom::domstringlist::DOMStringList;
|
||||||
|
use crate::dom::event::{Event, EventBubbles, EventCancelable};
|
||||||
|
use crate::dom::eventtarget::EventTarget;
|
||||||
|
use crate::dom::globalscope::GlobalScope;
|
||||||
|
use crate::dom::idbobjectstore::IDBObjectStore;
|
||||||
|
use crate::dom::idbtransaction::IDBTransaction;
|
||||||
|
use crate::dom::idbversionchangeevent::IDBVersionChangeEvent;
|
||||||
|
use crate::script_runtime::CanGc;
|
||||||
|
|
||||||
|
#[dom_struct]
|
||||||
|
pub struct IDBDatabase {
|
||||||
|
eventtarget: EventTarget,
|
||||||
|
/// <https://w3c.github.io/IndexedDB/#database-name>
|
||||||
|
name: DOMString,
|
||||||
|
/// <https://w3c.github.io/IndexedDB/#database-version>
|
||||||
|
version: Cell<u64>,
|
||||||
|
/// <https://w3c.github.io/IndexedDB/#object-store>
|
||||||
|
object_store_names: DomRefCell<Vec<DOMString>>,
|
||||||
|
/// <https://w3c.github.io/IndexedDB/#database-upgrade-transaction>
|
||||||
|
upgrade_transaction: MutNullableDom<IDBTransaction>,
|
||||||
|
|
||||||
|
// Flags
|
||||||
|
/// <https://w3c.github.io/IndexedDB/#connection-close-pending-flag>
|
||||||
|
closing: Cell<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IDBDatabase {
|
||||||
|
pub fn new_inherited(name: DOMString, version: u64) -> IDBDatabase {
|
||||||
|
IDBDatabase {
|
||||||
|
eventtarget: EventTarget::new_inherited(),
|
||||||
|
name,
|
||||||
|
version: Cell::new(version),
|
||||||
|
object_store_names: Default::default(),
|
||||||
|
|
||||||
|
upgrade_transaction: Default::default(),
|
||||||
|
closing: Cell::new(false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(
|
||||||
|
global: &GlobalScope,
|
||||||
|
name: DOMString,
|
||||||
|
version: u64,
|
||||||
|
can_gc: CanGc,
|
||||||
|
) -> DomRoot<IDBDatabase> {
|
||||||
|
reflect_dom_object(
|
||||||
|
Box::new(IDBDatabase::new_inherited(name, version)),
|
||||||
|
global,
|
||||||
|
can_gc,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_idb_thread(&self) -> IpcSender<IndexedDBThreadMsg> {
|
||||||
|
self.global().resource_threads().sender()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_name(&self) -> DOMString {
|
||||||
|
self.name.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn object_stores(&self) -> DomRoot<DOMStringList> {
|
||||||
|
DOMStringList::new(
|
||||||
|
self.global().as_window(),
|
||||||
|
self.object_store_names.borrow().clone(),
|
||||||
|
CanGc::note(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn version(&self) -> u64 {
|
||||||
|
let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
|
||||||
|
let operation = SyncOperation::Version(
|
||||||
|
sender,
|
||||||
|
self.global().origin().immutable().clone(),
|
||||||
|
self.name.to_string(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let _ = self
|
||||||
|
.get_idb_thread()
|
||||||
|
.send(IndexedDBThreadMsg::Sync(operation));
|
||||||
|
|
||||||
|
receiver.recv().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_transaction(&self, transaction: &IDBTransaction) {
|
||||||
|
self.upgrade_transaction.set(Some(transaction));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)] // This will be used once we allow multiple concurrent connections
|
||||||
|
pub fn dispatch_versionchange(
|
||||||
|
&self,
|
||||||
|
old_version: u64,
|
||||||
|
new_version: Option<u64>,
|
||||||
|
_can_gc: CanGc,
|
||||||
|
) {
|
||||||
|
let global = self.global();
|
||||||
|
let this = Trusted::new(self);
|
||||||
|
global.task_manager().database_access_task_source().queue(
|
||||||
|
task!(send_versionchange_notification: move || {
|
||||||
|
let this = this.root();
|
||||||
|
let global = this.global();
|
||||||
|
let event = IDBVersionChangeEvent::new(
|
||||||
|
&global,
|
||||||
|
Atom::from("versionchange"),
|
||||||
|
EventBubbles::DoesNotBubble,
|
||||||
|
EventCancelable::NotCancelable,
|
||||||
|
old_version,
|
||||||
|
new_version,
|
||||||
|
CanGc::note()
|
||||||
|
);
|
||||||
|
event.upcast::<Event>().fire(this.upcast(), CanGc::note());
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IDBDatabaseMethods<crate::DomTypeHolder> for IDBDatabase {
|
||||||
|
/// <https://w3c.github.io/IndexedDB/#dom-idbdatabase-transaction>
|
||||||
|
fn Transaction(
|
||||||
|
&self,
|
||||||
|
store_names: StringOrStringSequence,
|
||||||
|
mode: IDBTransactionMode,
|
||||||
|
_options: &IDBTransactionOptions,
|
||||||
|
) -> Fallible<DomRoot<IDBTransaction>> {
|
||||||
|
// FIXIME:(arihant2math) use options
|
||||||
|
// Step 1: Check if upgrade transaction is running
|
||||||
|
// FIXME:(rasviitanen)
|
||||||
|
|
||||||
|
// Step 2: if close flag is set, throw error
|
||||||
|
if self.closing.get() {
|
||||||
|
return Err(Error::InvalidState);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3
|
||||||
|
Ok(match store_names {
|
||||||
|
StringOrStringSequence::String(name) => IDBTransaction::new(
|
||||||
|
&self.global(),
|
||||||
|
self,
|
||||||
|
mode,
|
||||||
|
&DOMStringList::new(self.global().as_window(), vec![name], CanGc::note()),
|
||||||
|
CanGc::note(),
|
||||||
|
),
|
||||||
|
StringOrStringSequence::StringSequence(sequence) => {
|
||||||
|
// FIXME:(rasviitanen) Remove eventual duplicated names
|
||||||
|
// from the sequence
|
||||||
|
IDBTransaction::new(
|
||||||
|
&self.global(),
|
||||||
|
self,
|
||||||
|
mode,
|
||||||
|
&DOMStringList::new(self.global().as_window(), sequence, CanGc::note()),
|
||||||
|
CanGc::note(),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbdatabase-createobjectstore
|
||||||
|
fn CreateObjectStore(
|
||||||
|
&self,
|
||||||
|
name: DOMString,
|
||||||
|
options: &IDBObjectStoreParameters,
|
||||||
|
) -> Fallible<DomRoot<IDBObjectStore>> {
|
||||||
|
// FIXME:(arihant2math) ^^ Change idl to match above.
|
||||||
|
// Step 2
|
||||||
|
let upgrade_transaction = match self.upgrade_transaction.get() {
|
||||||
|
Some(txn) => txn,
|
||||||
|
None => return Err(Error::InvalidState),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Step 3
|
||||||
|
if !upgrade_transaction.is_active() {
|
||||||
|
return Err(Error::TransactionInactive);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 4
|
||||||
|
let key_path = options.keyPath.as_ref();
|
||||||
|
|
||||||
|
// Step 5
|
||||||
|
if let Some(path) = key_path {
|
||||||
|
if !IDBObjectStore::is_valid_key_path(path) {
|
||||||
|
return Err(Error::Syntax);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 6
|
||||||
|
if self
|
||||||
|
.object_store_names
|
||||||
|
.borrow()
|
||||||
|
.iter()
|
||||||
|
.any(|store_name| store_name.to_string() == name.to_string())
|
||||||
|
{
|
||||||
|
// TODO: Add constraint as an dom exception and throw that instead
|
||||||
|
return Err(Error::InvalidState);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 7
|
||||||
|
let auto_increment = options.autoIncrement;
|
||||||
|
|
||||||
|
// Step 8
|
||||||
|
if auto_increment {
|
||||||
|
match key_path {
|
||||||
|
Some(StringOrStringSequence::String(path)) => {
|
||||||
|
if path == "" {
|
||||||
|
return Err(Error::InvalidAccess);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Some(StringOrStringSequence::StringSequence(_)) => {
|
||||||
|
return Err(Error::InvalidAccess);
|
||||||
|
},
|
||||||
|
None => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 9
|
||||||
|
let object_store = IDBObjectStore::new(
|
||||||
|
&self.global(),
|
||||||
|
self.name.clone(),
|
||||||
|
name.clone(),
|
||||||
|
Some(options),
|
||||||
|
CanGc::note(),
|
||||||
|
);
|
||||||
|
object_store.set_transaction(&upgrade_transaction);
|
||||||
|
|
||||||
|
let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
|
||||||
|
|
||||||
|
let operation = SyncOperation::CreateObjectStore(
|
||||||
|
sender,
|
||||||
|
self.global().origin().immutable().clone(),
|
||||||
|
self.name.to_string(),
|
||||||
|
name.to_string(),
|
||||||
|
auto_increment,
|
||||||
|
);
|
||||||
|
|
||||||
|
self.get_idb_thread()
|
||||||
|
.send(IndexedDBThreadMsg::Sync(operation))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
if receiver
|
||||||
|
.recv()
|
||||||
|
.expect("Could not receive object store creation status")
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
|
warn!("Object store creation failed in idb thread");
|
||||||
|
return Err(Error::InvalidState);
|
||||||
|
};
|
||||||
|
|
||||||
|
self.object_store_names.borrow_mut().push(name);
|
||||||
|
Ok(object_store)
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbdatabase-deleteobjectstore
|
||||||
|
fn DeleteObjectStore(&self, name: DOMString) -> Fallible<()> {
|
||||||
|
// Steps 1 & 2
|
||||||
|
let transaction = self.upgrade_transaction.get();
|
||||||
|
let transaction = match transaction {
|
||||||
|
Some(transaction) => transaction,
|
||||||
|
None => return Err(Error::InvalidState),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Step 3
|
||||||
|
if !transaction.is_active() {
|
||||||
|
return Err(Error::TransactionInactive);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 4
|
||||||
|
if !self
|
||||||
|
.object_store_names
|
||||||
|
.borrow()
|
||||||
|
.iter()
|
||||||
|
.any(|store_name| store_name.to_string() == name.to_string())
|
||||||
|
{
|
||||||
|
return Err(Error::NotFound);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 5
|
||||||
|
self.object_store_names
|
||||||
|
.borrow_mut()
|
||||||
|
.retain(|store_name| store_name.to_string() != name.to_string());
|
||||||
|
|
||||||
|
// Step 6
|
||||||
|
// FIXME:(arihant2math) Remove from index set ...
|
||||||
|
|
||||||
|
// Step 7
|
||||||
|
let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
|
||||||
|
|
||||||
|
let operation = SyncOperation::DeleteObjectStore(
|
||||||
|
sender,
|
||||||
|
self.global().origin().immutable().clone(),
|
||||||
|
self.name.to_string(),
|
||||||
|
name.to_string(),
|
||||||
|
);
|
||||||
|
|
||||||
|
self.get_idb_thread()
|
||||||
|
.send(IndexedDBThreadMsg::Sync(operation))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
if receiver
|
||||||
|
.recv()
|
||||||
|
.expect("Could not receive object store deletion status")
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
|
warn!("Object store deletion failed in idb thread");
|
||||||
|
return Err(Error::InvalidState);
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbdatabase-name
|
||||||
|
fn Name(&self) -> DOMString {
|
||||||
|
self.name.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbdatabase-version
|
||||||
|
fn Version(&self) -> u64 {
|
||||||
|
self.version()
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbdatabase-objectstorenames
|
||||||
|
fn ObjectStoreNames(&self) -> DomRoot<DOMStringList> {
|
||||||
|
// FIXME: (arihant2math) Sort the list of names, as per spec
|
||||||
|
DOMStringList::new(
|
||||||
|
self.global().as_window(),
|
||||||
|
self.object_store_names.borrow().clone(),
|
||||||
|
CanGc::note(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbdatabase-close
|
||||||
|
fn Close(&self) {
|
||||||
|
// Step 1: Set the close pending flag of connection.
|
||||||
|
self.closing.set(true);
|
||||||
|
|
||||||
|
// Step 2: Handle force flag
|
||||||
|
// FIXME:(arihant2math)
|
||||||
|
// Step 3: Wait for all transactions by this db to finish
|
||||||
|
// FIXME:(arihant2math)
|
||||||
|
// Step 4: If force flag is set, fire a close event
|
||||||
|
let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
|
||||||
|
let operation = SyncOperation::CloseDatabase(
|
||||||
|
sender,
|
||||||
|
self.global().origin().immutable().clone(),
|
||||||
|
self.name.to_string(),
|
||||||
|
);
|
||||||
|
let _ = self
|
||||||
|
.get_idb_thread()
|
||||||
|
.send(IndexedDBThreadMsg::Sync(operation));
|
||||||
|
|
||||||
|
if receiver.recv().is_err() {
|
||||||
|
warn!("Database close failed in idb thread");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbdatabase-onabort
|
||||||
|
event_handler!(abort, GetOnabort, SetOnabort);
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbdatabase-onclose
|
||||||
|
event_handler!(close, GetOnclose, SetOnclose);
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbdatabase-onerror
|
||||||
|
event_handler!(error, GetOnerror, SetOnerror);
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbdatabase-onversionchange
|
||||||
|
event_handler!(versionchange, GetOnversionchange, SetOnversionchange);
|
||||||
|
}
|
97
components/script/dom/idbfactory.rs
Normal file
97
components/script/dom/idbfactory.rs
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use dom_struct::dom_struct;
|
||||||
|
use servo_url::origin::ImmutableOrigin;
|
||||||
|
|
||||||
|
use crate::dom::bindings::codegen::Bindings::IDBFactoryBinding::IDBFactoryMethods;
|
||||||
|
use crate::dom::bindings::error::{Error, Fallible};
|
||||||
|
use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
|
||||||
|
use crate::dom::bindings::root::DomRoot;
|
||||||
|
use crate::dom::bindings::str::DOMString;
|
||||||
|
use crate::dom::globalscope::GlobalScope;
|
||||||
|
use crate::dom::idbopendbrequest::IDBOpenDBRequest;
|
||||||
|
use crate::script_runtime::CanGc;
|
||||||
|
|
||||||
|
#[dom_struct]
|
||||||
|
pub struct IDBFactory {
|
||||||
|
reflector_: Reflector,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IDBFactory {
|
||||||
|
pub fn new_inherited() -> IDBFactory {
|
||||||
|
IDBFactory {
|
||||||
|
reflector_: Reflector::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(global: &GlobalScope, can_gc: CanGc) -> DomRoot<IDBFactory> {
|
||||||
|
reflect_dom_object(Box::new(IDBFactory::new_inherited()), global, can_gc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IDBFactoryMethods<crate::DomTypeHolder> for IDBFactory {
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbfactory-open
|
||||||
|
fn Open(&self, name: DOMString, version: Option<u64>) -> Fallible<DomRoot<IDBOpenDBRequest>> {
|
||||||
|
// Step 1: If version is 0 (zero), throw a TypeError.
|
||||||
|
if version == Some(0) {
|
||||||
|
return Err(Error::Type(
|
||||||
|
"The version must be an integer >= 1".to_owned(),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Step 2: Let origin be the origin of the global scope used to
|
||||||
|
// access this IDBFactory.
|
||||||
|
let global = self.global();
|
||||||
|
let origin = global.origin();
|
||||||
|
|
||||||
|
// Step 3: if origin is an opaque origin,
|
||||||
|
// throw a "SecurityError" DOMException and abort these steps.
|
||||||
|
if let ImmutableOrigin::Opaque(_) = origin.immutable() {
|
||||||
|
return Err(Error::Security);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 4: Let request be a new open request.
|
||||||
|
let request = IDBOpenDBRequest::new(&self.global(), CanGc::note());
|
||||||
|
|
||||||
|
// Step 5: Runs in parallel
|
||||||
|
request.open_database(name, version);
|
||||||
|
|
||||||
|
// Step 6
|
||||||
|
Ok(request)
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbfactory-deletedatabase
|
||||||
|
fn DeleteDatabase(&self, name: DOMString) -> Fallible<DomRoot<IDBOpenDBRequest>> {
|
||||||
|
// Step 1: Let origin be the origin of the global scope used to
|
||||||
|
// access this IDBFactory.
|
||||||
|
let global = self.global();
|
||||||
|
let origin = global.origin();
|
||||||
|
|
||||||
|
// Step 2: if origin is an opaque origin,
|
||||||
|
// throw a "SecurityError" DOMException and abort these steps.
|
||||||
|
if let ImmutableOrigin::Opaque(_) = origin.immutable() {
|
||||||
|
return Err(Error::Security);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: Let request be a new open request
|
||||||
|
let request = IDBOpenDBRequest::new(&self.global(), CanGc::note());
|
||||||
|
|
||||||
|
// Step 4: Runs in parallel
|
||||||
|
request.delete_database(name.to_string());
|
||||||
|
|
||||||
|
// Step 5: Return request
|
||||||
|
Ok(request)
|
||||||
|
}
|
||||||
|
|
||||||
|
// // https://www.w3.org/TR/IndexedDB-2/#dom-idbfactory-databases
|
||||||
|
// fn Databases(&self) -> Rc<Promise> {
|
||||||
|
// unimplemented!();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // https://www.w3.org/TR/IndexedDB-2/#dom-idbfactory-cmp
|
||||||
|
// fn Cmp(&self, _cx: SafeJSContext, _first: HandleValue, _second: HandleValue) -> i16 {
|
||||||
|
// unimplemented!();
|
||||||
|
// }
|
||||||
|
}
|
588
components/script/dom/idbobjectstore.rs
Normal file
588
components/script/dom/idbobjectstore.rs
Normal file
|
@ -0,0 +1,588 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use std::ptr;
|
||||||
|
|
||||||
|
use dom_struct::dom_struct;
|
||||||
|
use js::conversions::ToJSValConvertible;
|
||||||
|
use js::jsapi::{
|
||||||
|
ESClass, GetBuiltinClass, IsArrayBufferObject, JS_DeleteUCProperty,
|
||||||
|
JS_GetOwnUCPropertyDescriptor, JS_GetStringLength, JS_IsArrayBufferViewObject, JSObject,
|
||||||
|
ObjectOpResult, ObjectOpResult_SpecialCodes, PropertyDescriptor,
|
||||||
|
};
|
||||||
|
use js::jsval::UndefinedValue;
|
||||||
|
use js::rust::{HandleValue, MutableHandleValue};
|
||||||
|
use net_traits::IpcSend;
|
||||||
|
use net_traits::indexeddb_thread::{
|
||||||
|
AsyncOperation, IndexedDBKeyType, IndexedDBThreadMsg, SyncOperation,
|
||||||
|
};
|
||||||
|
use profile_traits::ipc;
|
||||||
|
|
||||||
|
use crate::dom::bindings::cell::DomRefCell;
|
||||||
|
use crate::dom::bindings::codegen::Bindings::IDBDatabaseBinding::IDBObjectStoreParameters;
|
||||||
|
use crate::dom::bindings::codegen::Bindings::IDBObjectStoreBinding::IDBObjectStoreMethods;
|
||||||
|
use crate::dom::bindings::codegen::Bindings::IDBTransactionBinding::IDBTransactionMode;
|
||||||
|
// We need to alias this name, otherwise test-tidy complains at &String reference.
|
||||||
|
use crate::dom::bindings::codegen::UnionTypes::StringOrStringSequence as StrOrStringSequence;
|
||||||
|
use crate::dom::bindings::error::{Error, Fallible};
|
||||||
|
use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
|
||||||
|
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
|
||||||
|
use crate::dom::bindings::str::DOMString;
|
||||||
|
use crate::dom::bindings::structuredclone;
|
||||||
|
use crate::dom::domstringlist::DOMStringList;
|
||||||
|
use crate::dom::globalscope::GlobalScope;
|
||||||
|
use crate::dom::idbrequest::IDBRequest;
|
||||||
|
use crate::dom::idbtransaction::IDBTransaction;
|
||||||
|
use crate::script_runtime::{CanGc, JSContext as SafeJSContext};
|
||||||
|
|
||||||
|
#[derive(JSTraceable, MallocSizeOf)]
|
||||||
|
pub enum KeyPath {
|
||||||
|
String(DOMString),
|
||||||
|
StringSequence(Vec<DOMString>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[dom_struct]
|
||||||
|
pub struct IDBObjectStore {
|
||||||
|
reflector_: Reflector,
|
||||||
|
name: DomRefCell<DOMString>,
|
||||||
|
key_path: Option<KeyPath>,
|
||||||
|
index_names: DomRoot<DOMStringList>,
|
||||||
|
transaction: MutNullableDom<IDBTransaction>,
|
||||||
|
auto_increment: bool,
|
||||||
|
|
||||||
|
// We store the db name in the object store to be able to find the correct
|
||||||
|
// store in the idb thread when checking if we have a key generator
|
||||||
|
db_name: DOMString,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IDBObjectStore {
|
||||||
|
pub fn new_inherited(
|
||||||
|
global: &GlobalScope,
|
||||||
|
db_name: DOMString,
|
||||||
|
name: DOMString,
|
||||||
|
options: Option<&IDBObjectStoreParameters>,
|
||||||
|
can_gc: CanGc,
|
||||||
|
) -> IDBObjectStore {
|
||||||
|
let key_path: Option<KeyPath> = match options {
|
||||||
|
Some(options) => options.keyPath.as_ref().map(|path| match path {
|
||||||
|
StrOrStringSequence::String(inner) => KeyPath::String(inner.clone()),
|
||||||
|
StrOrStringSequence::StringSequence(inner) => {
|
||||||
|
KeyPath::StringSequence(inner.clone())
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
IDBObjectStore {
|
||||||
|
reflector_: Reflector::new(),
|
||||||
|
name: DomRefCell::new(name),
|
||||||
|
key_path,
|
||||||
|
|
||||||
|
index_names: DOMStringList::new(global.as_window(), Vec::new(), can_gc),
|
||||||
|
transaction: Default::default(),
|
||||||
|
// FIXME:(arihant2math)
|
||||||
|
auto_increment: false,
|
||||||
|
|
||||||
|
db_name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(
|
||||||
|
global: &GlobalScope,
|
||||||
|
db_name: DOMString,
|
||||||
|
name: DOMString,
|
||||||
|
options: Option<&IDBObjectStoreParameters>,
|
||||||
|
can_gc: CanGc,
|
||||||
|
) -> DomRoot<IDBObjectStore> {
|
||||||
|
reflect_dom_object(
|
||||||
|
Box::new(IDBObjectStore::new_inherited(
|
||||||
|
global, db_name, name, options, can_gc,
|
||||||
|
)),
|
||||||
|
global,
|
||||||
|
can_gc,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_name(&self) -> DOMString {
|
||||||
|
self.name.borrow().clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_transaction(&self, transaction: &IDBTransaction) {
|
||||||
|
self.transaction.set(Some(transaction));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transaction(&self) -> Option<DomRoot<IDBTransaction>> {
|
||||||
|
self.transaction.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#valid-key-path
|
||||||
|
pub fn is_valid_key_path(key_path: &StrOrStringSequence) -> bool {
|
||||||
|
fn is_identifier(_s: &str) -> bool {
|
||||||
|
// FIXME: (arihant2math)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
let is_valid = |path: &DOMString| {
|
||||||
|
path.is_empty() || is_identifier(path) || path.split(".").all(is_identifier)
|
||||||
|
};
|
||||||
|
|
||||||
|
match key_path {
|
||||||
|
StrOrStringSequence::StringSequence(paths) => {
|
||||||
|
if paths.is_empty() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
paths.iter().all(is_valid)
|
||||||
|
},
|
||||||
|
StrOrStringSequence::String(path) => is_valid(path),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unsafe_code)]
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#convert-value-to-key
|
||||||
|
fn convert_value_to_key(
|
||||||
|
cx: SafeJSContext,
|
||||||
|
input: HandleValue,
|
||||||
|
seen: Option<Vec<HandleValue>>,
|
||||||
|
) -> Result<IndexedDBKeyType, Error> {
|
||||||
|
// Step 1: If seen was not given, then let seen be a new empty set.
|
||||||
|
let _seen = seen.unwrap_or_default();
|
||||||
|
|
||||||
|
// Step 2: If seen contains input, then return invalid.
|
||||||
|
// FIXME:(rasviitanen)
|
||||||
|
// Check if we have seen this key
|
||||||
|
// Does not currently work with HandleValue,
|
||||||
|
// as it does not implement PartialEq
|
||||||
|
|
||||||
|
// Step 3
|
||||||
|
// FIXME:(rasviitanen) Accept buffer, array and date as well
|
||||||
|
if input.is_number() {
|
||||||
|
// FIXME:(rasviitanen) check for NaN
|
||||||
|
let key = structuredclone::write(cx, input, None).expect("Could not serialize key");
|
||||||
|
return Ok(IndexedDBKeyType::Number(key.serialized));
|
||||||
|
}
|
||||||
|
|
||||||
|
if input.is_string() {
|
||||||
|
let key = structuredclone::write(cx, input, None).expect("Could not serialize key");
|
||||||
|
return Ok(IndexedDBKeyType::String(key.serialized));
|
||||||
|
}
|
||||||
|
|
||||||
|
if input.is_object() {
|
||||||
|
rooted!(in(*cx) let object = input.to_object());
|
||||||
|
unsafe {
|
||||||
|
let mut built_in_class = ESClass::Other;
|
||||||
|
|
||||||
|
if !GetBuiltinClass(*cx, object.handle().into(), &mut built_in_class) {
|
||||||
|
return Err(Error::Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let ESClass::Date = built_in_class {
|
||||||
|
// FIXME:(arihant2math) implement it the correct way
|
||||||
|
let key =
|
||||||
|
structuredclone::write(cx, input, None).expect("Could not serialize key");
|
||||||
|
return Ok(IndexedDBKeyType::Date(key.serialized.clone()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if IsArrayBufferObject(*object) || JS_IsArrayBufferViewObject(*object) {
|
||||||
|
let key =
|
||||||
|
structuredclone::write(cx, input, None).expect("Could not serialize key");
|
||||||
|
// FIXME:(arihant2math) Return the correct type here
|
||||||
|
// it doesn't really matter at the moment...
|
||||||
|
return Ok(IndexedDBKeyType::Number(key.serialized.clone()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let ESClass::Array = built_in_class {
|
||||||
|
// FIXME:(arihant2math)
|
||||||
|
unimplemented!("Arrays as keys is currently unsupported");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(Error::Data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#evaluate-a-key-path-on-a-value
|
||||||
|
#[allow(unsafe_code)]
|
||||||
|
fn evaluate_key_path_on_value(
|
||||||
|
cx: SafeJSContext,
|
||||||
|
value: HandleValue,
|
||||||
|
mut return_val: MutableHandleValue,
|
||||||
|
key_path: &KeyPath,
|
||||||
|
) {
|
||||||
|
// The implementation is translated from gecko:
|
||||||
|
// https://github.com/mozilla/gecko-dev/blob/master/dom/indexedDB/KeyPath.cpp
|
||||||
|
return_val.set(*value);
|
||||||
|
|
||||||
|
rooted!(in(*cx) let mut target_object = ptr::null_mut::<JSObject>());
|
||||||
|
rooted!(in(*cx) let mut current_val = *value);
|
||||||
|
rooted!(in(*cx) let mut object = ptr::null_mut::<JSObject>());
|
||||||
|
|
||||||
|
let mut target_object_prop_name: Option<String> = None;
|
||||||
|
|
||||||
|
match key_path {
|
||||||
|
KeyPath::String(path) => {
|
||||||
|
// Step 3
|
||||||
|
let path_as_string = path.to_string();
|
||||||
|
let mut tokenizer = path_as_string.split('.').peekable();
|
||||||
|
|
||||||
|
while let Some(token) = tokenizer.next() {
|
||||||
|
if target_object.get().is_null() {
|
||||||
|
if token == "length" &&
|
||||||
|
tokenizer.peek().is_none() &&
|
||||||
|
current_val.is_string()
|
||||||
|
{
|
||||||
|
rooted!(in(*cx) let input_val = current_val.to_string());
|
||||||
|
unsafe {
|
||||||
|
let string_len = JS_GetStringLength(*input_val) as u64;
|
||||||
|
string_len.to_jsval(*cx, return_val);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !current_val.is_object() {
|
||||||
|
// FIXME:(rasviitanen) Return a proper error
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
object.handle_mut().set(current_val.to_object());
|
||||||
|
rooted!(in(*cx) let mut desc = PropertyDescriptor::default());
|
||||||
|
rooted!(in(*cx) let mut intermediate = UndefinedValue());
|
||||||
|
|
||||||
|
// So rust says that this value is never read, but it is.
|
||||||
|
#[allow(unused)]
|
||||||
|
let mut has_prop = false;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let prop_name_as_utf16: Vec<u16> = token.encode_utf16().collect();
|
||||||
|
let mut is_descriptor_none: bool = false;
|
||||||
|
let ok = JS_GetOwnUCPropertyDescriptor(
|
||||||
|
*cx,
|
||||||
|
object.handle().into(),
|
||||||
|
prop_name_as_utf16.as_ptr(),
|
||||||
|
prop_name_as_utf16.len(),
|
||||||
|
desc.handle_mut().into(),
|
||||||
|
&mut is_descriptor_none,
|
||||||
|
);
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
// FIXME:(arihant2math) Handle this
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if desc.hasWritable_() || desc.hasValue_() {
|
||||||
|
intermediate.handle_mut().set(desc.handle().value_);
|
||||||
|
has_prop = true;
|
||||||
|
} else {
|
||||||
|
// If we get here it means the object doesn't have the property or the
|
||||||
|
// property is available throuch a getter. We don't want to call any
|
||||||
|
// getters to avoid potential re-entrancy.
|
||||||
|
// The blob object is special since its properties are available
|
||||||
|
// only through getters but we still want to support them for key
|
||||||
|
// extraction. So they need to be handled manually.
|
||||||
|
unimplemented!("Blob tokens are not yet supported");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if has_prop {
|
||||||
|
// Treat undefined as an error
|
||||||
|
if intermediate.is_undefined() {
|
||||||
|
// FIXME:(rasviitanen) Throw/return error
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if tokenizer.peek().is_some() {
|
||||||
|
// ...and walk to it if there are more steps...
|
||||||
|
current_val.handle_mut().set(*intermediate);
|
||||||
|
} else {
|
||||||
|
// ...otherwise use it as key
|
||||||
|
return_val.set(*intermediate);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
target_object.handle_mut().set(*object);
|
||||||
|
target_object_prop_name = Some(token.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !target_object.get().is_null() {
|
||||||
|
// We have started inserting new objects or are about to just insert
|
||||||
|
// the first one.
|
||||||
|
// FIXME:(rasviitanen) Implement this piece
|
||||||
|
unimplemented!("keyPath tokens that requires insertion are not supported.");
|
||||||
|
}
|
||||||
|
} // All tokens processed
|
||||||
|
|
||||||
|
if !target_object.get().is_null() {
|
||||||
|
// If this fails, we lose, and the web page sees a magical property
|
||||||
|
// appear on the object :-(
|
||||||
|
unsafe {
|
||||||
|
let prop_name_as_utf16: Vec<u16> =
|
||||||
|
target_object_prop_name.unwrap().encode_utf16().collect();
|
||||||
|
#[allow(clippy::cast_enum_truncation)]
|
||||||
|
let mut succeeded = ObjectOpResult {
|
||||||
|
code_: ObjectOpResult_SpecialCodes::Uninitialized as usize,
|
||||||
|
};
|
||||||
|
if !JS_DeleteUCProperty(
|
||||||
|
*cx,
|
||||||
|
target_object.handle().into(),
|
||||||
|
prop_name_as_utf16.as_ptr(),
|
||||||
|
prop_name_as_utf16.len(),
|
||||||
|
&mut succeeded,
|
||||||
|
) {
|
||||||
|
// FIXME:(rasviitanen) Throw/return error
|
||||||
|
// return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
KeyPath::StringSequence(_) => {
|
||||||
|
unimplemented!("String sequence keyPath is currently unsupported");
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_key_generator(&self) -> bool {
|
||||||
|
let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
|
||||||
|
|
||||||
|
let operation = SyncOperation::HasKeyGenerator(
|
||||||
|
sender,
|
||||||
|
self.global().origin().immutable().clone(),
|
||||||
|
self.db_name.to_string(),
|
||||||
|
self.name.borrow().to_string(),
|
||||||
|
);
|
||||||
|
|
||||||
|
self.global()
|
||||||
|
.resource_threads()
|
||||||
|
.sender()
|
||||||
|
.send(IndexedDBThreadMsg::Sync(operation))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
receiver.recv().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#extract-a-key-from-a-value-using-a-key-path
|
||||||
|
fn extract_key(
|
||||||
|
cx: SafeJSContext,
|
||||||
|
input: HandleValue,
|
||||||
|
key_path: &KeyPath,
|
||||||
|
multi_entry: Option<bool>,
|
||||||
|
) -> Result<IndexedDBKeyType, Error> {
|
||||||
|
// Step 1: Evaluate key path
|
||||||
|
// FIXME:(rasviitanen) Do this propertly
|
||||||
|
rooted!(in(*cx) let mut r = UndefinedValue());
|
||||||
|
IDBObjectStore::evaluate_key_path_on_value(cx, input, r.handle_mut(), key_path);
|
||||||
|
|
||||||
|
if let Some(_multi_entry) = multi_entry {
|
||||||
|
// FIXME:(rasviitanen) handle multi_entry cases
|
||||||
|
unimplemented!("multiEntry keys are not yet supported");
|
||||||
|
} else {
|
||||||
|
IDBObjectStore::convert_value_to_key(cx, r.handle(), None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#object-store-in-line-keys
|
||||||
|
fn uses_inline_keys(&self) -> bool {
|
||||||
|
self.key_path.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-put
|
||||||
|
fn put(
|
||||||
|
&self,
|
||||||
|
cx: SafeJSContext,
|
||||||
|
value: HandleValue,
|
||||||
|
key: HandleValue,
|
||||||
|
overwrite: bool,
|
||||||
|
can_gc: CanGc,
|
||||||
|
) -> Fallible<DomRoot<IDBRequest>> {
|
||||||
|
// Step 1: Let transaction be this object store handle's transaction.
|
||||||
|
let transaction = self
|
||||||
|
.transaction
|
||||||
|
.get()
|
||||||
|
.expect("No transaction in Object Store");
|
||||||
|
|
||||||
|
// Step 2: Let store be this object store handle's object store.
|
||||||
|
// This is resolved in the `execute_async` function.
|
||||||
|
|
||||||
|
// Step 3: If store has been deleted, throw an "InvalidStateError" DOMException.
|
||||||
|
// FIXME:(rasviitanen)
|
||||||
|
|
||||||
|
// Step 4-5: If transaction is not active, throw a "TransactionInactiveError" DOMException.
|
||||||
|
if !transaction.is_active() {
|
||||||
|
return Err(Error::TransactionInactive);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 5: If transaction is a read-only transaction, throw a "ReadOnlyError" DOMException.
|
||||||
|
if let IDBTransactionMode::Readonly = transaction.get_mode() {
|
||||||
|
return Err(Error::ReadOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 6: If store uses in-line keys and key was given, throw a "DataError" DOMException.
|
||||||
|
if !key.is_undefined() && self.uses_inline_keys() {
|
||||||
|
return Err(Error::Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 7: If store uses out-of-line keys and has no key generator
|
||||||
|
// and key was not given, throw a "DataError" DOMException.
|
||||||
|
if !self.uses_inline_keys() && !self.has_key_generator() && key.is_undefined() {
|
||||||
|
return Err(Error::Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 8: If key was given, then: convert a value to a key with key
|
||||||
|
let serialized_key: IndexedDBKeyType;
|
||||||
|
|
||||||
|
if !key.is_undefined() {
|
||||||
|
serialized_key = IDBObjectStore::convert_value_to_key(cx, key, None)?;
|
||||||
|
} else {
|
||||||
|
// Step 11: We should use in-line keys instead
|
||||||
|
if let Ok(kpk) = IDBObjectStore::extract_key(
|
||||||
|
cx,
|
||||||
|
value,
|
||||||
|
self.key_path.as_ref().expect("No key path"),
|
||||||
|
None,
|
||||||
|
) {
|
||||||
|
serialized_key = kpk;
|
||||||
|
} else {
|
||||||
|
// FIXME:(rasviitanen)
|
||||||
|
// Check if store has a key generator
|
||||||
|
// Check if we can inject a key
|
||||||
|
return Err(Error::Data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let serialized_value =
|
||||||
|
structuredclone::write(cx, value, None).expect("Could not serialize value");
|
||||||
|
|
||||||
|
IDBRequest::execute_async(
|
||||||
|
self,
|
||||||
|
AsyncOperation::PutItem(serialized_key, serialized_value.serialized, overwrite),
|
||||||
|
None,
|
||||||
|
can_gc,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IDBObjectStoreMethods<crate::DomTypeHolder> for IDBObjectStore {
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-put
|
||||||
|
fn Put(
|
||||||
|
&self,
|
||||||
|
cx: SafeJSContext,
|
||||||
|
value: HandleValue,
|
||||||
|
key: HandleValue,
|
||||||
|
) -> Fallible<DomRoot<IDBRequest>> {
|
||||||
|
self.put(cx, value, key, true, CanGc::note())
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-add
|
||||||
|
fn Add(
|
||||||
|
&self,
|
||||||
|
cx: SafeJSContext,
|
||||||
|
value: HandleValue,
|
||||||
|
key: HandleValue,
|
||||||
|
) -> Fallible<DomRoot<IDBRequest>> {
|
||||||
|
self.put(cx, value, key, false, CanGc::note())
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-delete
|
||||||
|
fn Delete(&self, cx: SafeJSContext, query: HandleValue) -> Fallible<DomRoot<IDBRequest>> {
|
||||||
|
let serialized_query = IDBObjectStore::convert_value_to_key(cx, query, None);
|
||||||
|
serialized_query.and_then(|q| {
|
||||||
|
IDBRequest::execute_async(self, AsyncOperation::RemoveItem(q), None, CanGc::note())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-clear
|
||||||
|
fn Clear(&self) -> Fallible<DomRoot<IDBRequest>> {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-get
|
||||||
|
fn Get(&self, cx: SafeJSContext, query: HandleValue) -> Fallible<DomRoot<IDBRequest>> {
|
||||||
|
let serialized_query = IDBObjectStore::convert_value_to_key(cx, query, None);
|
||||||
|
serialized_query.and_then(|q| {
|
||||||
|
IDBRequest::execute_async(self, AsyncOperation::GetItem(q), None, CanGc::note())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-getkey
|
||||||
|
// fn GetKey(&self, _cx: SafeJSContext, _query: HandleValue) -> DomRoot<IDBRequest> {
|
||||||
|
// unimplemented!();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-getall
|
||||||
|
// fn GetAll(
|
||||||
|
// &self,
|
||||||
|
// _cx: SafeJSContext,
|
||||||
|
// _query: HandleValue,
|
||||||
|
// _count: Option<u32>,
|
||||||
|
// ) -> DomRoot<IDBRequest> {
|
||||||
|
// unimplemented!();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-getallkeys
|
||||||
|
// fn GetAllKeys(
|
||||||
|
// &self,
|
||||||
|
// _cx: SafeJSContext,
|
||||||
|
// _query: HandleValue,
|
||||||
|
// _count: Option<u32>,
|
||||||
|
// ) -> DomRoot<IDBRequest> {
|
||||||
|
// unimplemented!();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-count
|
||||||
|
fn Count(&self, cx: SafeJSContext, query: HandleValue) -> Fallible<DomRoot<IDBRequest>> {
|
||||||
|
// Step 1
|
||||||
|
let transaction = self.transaction.get().expect("Could not get transaction");
|
||||||
|
|
||||||
|
// Step 2
|
||||||
|
// FIXME(arihant2math): investigate further
|
||||||
|
|
||||||
|
// Step 3
|
||||||
|
// FIXME(arihant2math): Cannot tell if store has been deleted
|
||||||
|
|
||||||
|
// Step 4
|
||||||
|
if !transaction.is_active() {
|
||||||
|
return Err(Error::TransactionInactive);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 5
|
||||||
|
let _serialized_query = IDBObjectStore::convert_value_to_key(cx, query, None);
|
||||||
|
|
||||||
|
// Step 6
|
||||||
|
// match serialized_query {
|
||||||
|
// Ok(q) => IDBRequest::execute_async(&*self, AsyncOperation::Count(q), None),
|
||||||
|
// Err(e) => Err(e),
|
||||||
|
// }
|
||||||
|
Err(Error::NotSupported)
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-name
|
||||||
|
fn Name(&self) -> DOMString {
|
||||||
|
self.name.borrow().clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-setname
|
||||||
|
fn SetName(&self, value: DOMString) {
|
||||||
|
*self.name.borrow_mut() = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-keypath
|
||||||
|
// fn KeyPath(&self, _cx: SafeJSContext, _val: MutableHandleValue) {
|
||||||
|
// unimplemented!();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-indexnames
|
||||||
|
// fn IndexNames(&self) -> DomRoot<DOMStringList> {
|
||||||
|
// unimplemented!();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-transaction
|
||||||
|
// fn Transaction(&self) -> DomRoot<IDBTransaction> {
|
||||||
|
// unimplemented!();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-autoincrement
|
||||||
|
fn AutoIncrement(&self) -> bool {
|
||||||
|
// FIXME(arihant2math): This is wrong
|
||||||
|
self.auto_increment
|
||||||
|
}
|
||||||
|
}
|
371
components/script/dom/idbopendbrequest.rs
Normal file
371
components/script/dom/idbopendbrequest.rs
Normal file
|
@ -0,0 +1,371 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use dom_struct::dom_struct;
|
||||||
|
use ipc_channel::router::ROUTER;
|
||||||
|
use js::jsval::UndefinedValue;
|
||||||
|
use js::rust::HandleValue;
|
||||||
|
use net_traits::IpcSend;
|
||||||
|
use net_traits::indexeddb_thread::{IndexedDBThreadMsg, SyncOperation};
|
||||||
|
use profile_traits::ipc;
|
||||||
|
use stylo_atoms::Atom;
|
||||||
|
|
||||||
|
use crate::dom::bindings::codegen::Bindings::IDBOpenDBRequestBinding::IDBOpenDBRequestMethods;
|
||||||
|
use crate::dom::bindings::codegen::Bindings::IDBTransactionBinding::IDBTransactionMode;
|
||||||
|
use crate::dom::bindings::error::{Error, Fallible};
|
||||||
|
use crate::dom::bindings::inheritance::Castable;
|
||||||
|
use crate::dom::bindings::refcounted::Trusted;
|
||||||
|
use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object};
|
||||||
|
use crate::dom::bindings::root::DomRoot;
|
||||||
|
use crate::dom::bindings::str::DOMString;
|
||||||
|
use crate::dom::event::{Event, EventBubbles, EventCancelable};
|
||||||
|
use crate::dom::globalscope::GlobalScope;
|
||||||
|
use crate::dom::idbdatabase::IDBDatabase;
|
||||||
|
use crate::dom::idbrequest::IDBRequest;
|
||||||
|
use crate::dom::idbtransaction::IDBTransaction;
|
||||||
|
use crate::dom::idbversionchangeevent::IDBVersionChangeEvent;
|
||||||
|
use crate::js::conversions::ToJSValConvertible;
|
||||||
|
use crate::realms::enter_realm;
|
||||||
|
use crate::script_runtime::CanGc;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct OpenRequestListener {
|
||||||
|
open_request: Trusted<IDBOpenDBRequest>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OpenRequestListener {
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#open-a-database
|
||||||
|
fn handle_open_db(
|
||||||
|
&self,
|
||||||
|
name: String,
|
||||||
|
request_version: Option<u64>,
|
||||||
|
db_version: u64,
|
||||||
|
can_gc: CanGc,
|
||||||
|
) -> (Fallible<DomRoot<IDBDatabase>>, bool) {
|
||||||
|
// Step 5-6
|
||||||
|
let request_version = match request_version {
|
||||||
|
Some(v) => v,
|
||||||
|
None => {
|
||||||
|
if db_version == 0 {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
db_version
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Step 7
|
||||||
|
if request_version < db_version {
|
||||||
|
return (Err(Error::Version), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 8-9
|
||||||
|
let open_request = self.open_request.root();
|
||||||
|
let global = open_request.global();
|
||||||
|
let connection = IDBDatabase::new(
|
||||||
|
&global,
|
||||||
|
DOMString::from_string(name.clone()),
|
||||||
|
request_version,
|
||||||
|
can_gc,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Step 10
|
||||||
|
if request_version > db_version {
|
||||||
|
// FIXME:(rasviitanen) Do step 10.1-10.5
|
||||||
|
// connection.dispatch_versionchange(db_version, Some(request_version));
|
||||||
|
// Step 10.6
|
||||||
|
open_request.upgrade_db_version(&connection, request_version, CanGc::note());
|
||||||
|
// Step 11
|
||||||
|
(Ok(connection), true)
|
||||||
|
} else {
|
||||||
|
// Step 11
|
||||||
|
(Ok(connection), false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_delete_db(&self, result: Result<(), ()>, can_gc: CanGc) {
|
||||||
|
let open_request = self.open_request.root();
|
||||||
|
let global = open_request.global();
|
||||||
|
open_request.idbrequest.set_ready_state_done();
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(_) => {
|
||||||
|
let _ac = enter_realm(&*open_request);
|
||||||
|
#[allow(unsafe_code)]
|
||||||
|
unsafe {
|
||||||
|
open_request
|
||||||
|
.set_result(js::gc::Handle::from_raw(js::jsapi::UndefinedHandleValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
let event = Event::new(
|
||||||
|
&global,
|
||||||
|
Atom::from("success"),
|
||||||
|
EventBubbles::DoesNotBubble,
|
||||||
|
EventCancelable::NotCancelable,
|
||||||
|
can_gc,
|
||||||
|
);
|
||||||
|
event.fire(open_request.upcast(), can_gc);
|
||||||
|
},
|
||||||
|
Err(_e) => {
|
||||||
|
// FIXME(rasviitanen) Set the error of request to the
|
||||||
|
// appropriate error
|
||||||
|
|
||||||
|
let event = Event::new(
|
||||||
|
&global,
|
||||||
|
Atom::from("error"),
|
||||||
|
EventBubbles::Bubbles,
|
||||||
|
EventCancelable::Cancelable,
|
||||||
|
can_gc,
|
||||||
|
);
|
||||||
|
event.fire(open_request.upcast(), can_gc);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[dom_struct]
|
||||||
|
pub struct IDBOpenDBRequest {
|
||||||
|
idbrequest: IDBRequest,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IDBOpenDBRequest {
|
||||||
|
pub fn new_inherited() -> IDBOpenDBRequest {
|
||||||
|
IDBOpenDBRequest {
|
||||||
|
idbrequest: IDBRequest::new_inherited(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(global: &GlobalScope, can_gc: CanGc) -> DomRoot<IDBOpenDBRequest> {
|
||||||
|
reflect_dom_object(Box::new(IDBOpenDBRequest::new_inherited()), global, can_gc)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unsafe_code)]
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#run-an-upgrade-transaction
|
||||||
|
fn upgrade_db_version(&self, connection: &IDBDatabase, version: u64, can_gc: CanGc) {
|
||||||
|
let global = self.global();
|
||||||
|
// Step 2
|
||||||
|
let transaction = IDBTransaction::new(
|
||||||
|
&global,
|
||||||
|
connection,
|
||||||
|
IDBTransactionMode::Versionchange,
|
||||||
|
&connection.object_stores(),
|
||||||
|
can_gc,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Step 3
|
||||||
|
connection.set_transaction(&transaction);
|
||||||
|
|
||||||
|
// Step 4
|
||||||
|
transaction.set_active_flag(false);
|
||||||
|
|
||||||
|
// Step 5-7
|
||||||
|
let old_version = connection.version();
|
||||||
|
transaction.upgrade_db_version(version);
|
||||||
|
|
||||||
|
// Step 8
|
||||||
|
let this = Trusted::new(self);
|
||||||
|
let connection = Trusted::new(connection);
|
||||||
|
let trusted_transaction = Trusted::new(&*transaction);
|
||||||
|
global.task_manager().database_access_task_source().queue(
|
||||||
|
task!(send_upgradeneeded_notification: move || {
|
||||||
|
let this = this.root();
|
||||||
|
let txn = trusted_transaction.root();
|
||||||
|
let conn = connection.root();
|
||||||
|
let global = this.global();
|
||||||
|
let cx = GlobalScope::get_cx();
|
||||||
|
|
||||||
|
// Step 8.1
|
||||||
|
let _ac = enter_realm(&*conn);
|
||||||
|
rooted!(in(*cx) let mut connection_val = UndefinedValue());
|
||||||
|
unsafe {
|
||||||
|
conn.to_jsval(*cx, connection_val.handle_mut());
|
||||||
|
}
|
||||||
|
this.idbrequest.set_result(connection_val.handle());
|
||||||
|
|
||||||
|
// Step 8.2
|
||||||
|
this.idbrequest.set_transaction(&txn);
|
||||||
|
|
||||||
|
// Step 8.3
|
||||||
|
this.idbrequest.set_ready_state_done();
|
||||||
|
|
||||||
|
let event = IDBVersionChangeEvent::new(
|
||||||
|
&global,
|
||||||
|
Atom::from("upgradeneeded"),
|
||||||
|
EventBubbles::DoesNotBubble,
|
||||||
|
EventCancelable::NotCancelable,
|
||||||
|
old_version,
|
||||||
|
Some(version),
|
||||||
|
CanGc::note(),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Step 8.4
|
||||||
|
txn.set_active_flag(true);
|
||||||
|
// Step 8.5
|
||||||
|
let _did_throw = event.upcast::<Event>().fire(this.upcast(), CanGc::note());
|
||||||
|
// FIXME:(rasviitanen) Handle throw (Step 8.5)
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#run-an-upgrade-transaction
|
||||||
|
// Step 8.6
|
||||||
|
txn.set_active_flag(false);
|
||||||
|
|
||||||
|
// Implementation specific: we fire the success on db here
|
||||||
|
// to make sure the success event occurs after the upgrade event.
|
||||||
|
txn.wait();
|
||||||
|
this.dispatch_success(&conn);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Step 9: Starts and waits for the transaction to finish
|
||||||
|
transaction.wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_result(&self, result: HandleValue) {
|
||||||
|
self.idbrequest.set_result(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_error(&self, error: Error, can_gc: CanGc) {
|
||||||
|
self.idbrequest.set_error(error, can_gc);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn open_database(&self, name: DOMString, version: Option<u64>) {
|
||||||
|
let global = self.global();
|
||||||
|
|
||||||
|
let (sender, receiver) = ipc::channel(global.time_profiler_chan().clone()).unwrap();
|
||||||
|
let response_listener = OpenRequestListener {
|
||||||
|
open_request: Trusted::new(self),
|
||||||
|
};
|
||||||
|
|
||||||
|
let open_operation = SyncOperation::OpenDatabase(
|
||||||
|
sender,
|
||||||
|
global.origin().immutable().clone(),
|
||||||
|
name.to_string(),
|
||||||
|
version,
|
||||||
|
);
|
||||||
|
|
||||||
|
let task_source = global
|
||||||
|
.task_manager()
|
||||||
|
.database_access_task_source()
|
||||||
|
.to_sendable();
|
||||||
|
|
||||||
|
let trusted_request = Trusted::new(self);
|
||||||
|
let name = name.to_string();
|
||||||
|
ROUTER.add_typed_route(
|
||||||
|
receiver.to_ipc_receiver(),
|
||||||
|
Box::new(move |message| {
|
||||||
|
let trusted_request = trusted_request.clone();
|
||||||
|
let response_listener = response_listener.clone();
|
||||||
|
let name = name.clone();
|
||||||
|
|
||||||
|
task_source.queue(
|
||||||
|
task!(set_request_result_to_database: move || {
|
||||||
|
let (result, did_upgrade) =
|
||||||
|
response_listener.handle_open_db(name, version, message.unwrap(), CanGc::note());
|
||||||
|
// If an upgrade event was created, it will be responsible for
|
||||||
|
// dispatching the success event
|
||||||
|
if did_upgrade {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let request = trusted_request.root();
|
||||||
|
let global = request.global();
|
||||||
|
match result {
|
||||||
|
Ok(db) => {
|
||||||
|
request.dispatch_success(&db);
|
||||||
|
},
|
||||||
|
Err(dom_exception) => {
|
||||||
|
request.set_result(HandleValue::undefined());
|
||||||
|
request.set_error(dom_exception, CanGc::note());
|
||||||
|
let event = Event::new(
|
||||||
|
&global,
|
||||||
|
Atom::from("error"),
|
||||||
|
EventBubbles::Bubbles,
|
||||||
|
EventCancelable::Cancelable,
|
||||||
|
CanGc::note()
|
||||||
|
);
|
||||||
|
event.fire(request.upcast(), CanGc::note());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
global
|
||||||
|
.resource_threads()
|
||||||
|
.sender()
|
||||||
|
.send(IndexedDBThreadMsg::Sync(open_operation))
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn delete_database(&self, name: String) {
|
||||||
|
let global = self.global();
|
||||||
|
|
||||||
|
let (sender, receiver) = ipc::channel(global.time_profiler_chan().clone()).unwrap();
|
||||||
|
let task_source = global
|
||||||
|
.task_manager()
|
||||||
|
.database_access_task_source()
|
||||||
|
.to_sendable();
|
||||||
|
let response_listener = OpenRequestListener {
|
||||||
|
open_request: Trusted::new(self),
|
||||||
|
};
|
||||||
|
|
||||||
|
let delete_operation =
|
||||||
|
SyncOperation::DeleteDatabase(sender, global.origin().immutable().clone(), name);
|
||||||
|
|
||||||
|
ROUTER.add_typed_route(
|
||||||
|
receiver.to_ipc_receiver(),
|
||||||
|
Box::new(move |message| {
|
||||||
|
let response_listener = response_listener.clone();
|
||||||
|
task_source.queue(task!(request_callback: move || {
|
||||||
|
response_listener.handle_delete_db(message.unwrap(), CanGc::note());
|
||||||
|
}));
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
global
|
||||||
|
.resource_threads()
|
||||||
|
.sender()
|
||||||
|
.send(IndexedDBThreadMsg::Sync(delete_operation))
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unsafe_code)]
|
||||||
|
pub fn dispatch_success(&self, result: &IDBDatabase) {
|
||||||
|
let global = self.global();
|
||||||
|
let this = Trusted::new(self);
|
||||||
|
let result = Trusted::new(result);
|
||||||
|
|
||||||
|
global.task_manager().database_access_task_source().queue(
|
||||||
|
task!(send_success_notification: move || {
|
||||||
|
let this = this.root();
|
||||||
|
let result = result.root();
|
||||||
|
this.idbrequest.set_ready_state_done();
|
||||||
|
let global = this.global();
|
||||||
|
let cx = GlobalScope::get_cx();
|
||||||
|
|
||||||
|
let _ac = enter_realm(&*result);
|
||||||
|
rooted!(in(*cx) let mut result_val = UndefinedValue());
|
||||||
|
unsafe {
|
||||||
|
result.to_jsval(*cx, result_val.handle_mut());
|
||||||
|
}
|
||||||
|
this.set_result(result_val.handle());
|
||||||
|
|
||||||
|
let event = Event::new(
|
||||||
|
&global,
|
||||||
|
Atom::from("success"),
|
||||||
|
EventBubbles::DoesNotBubble,
|
||||||
|
EventCancelable::NotCancelable,
|
||||||
|
CanGc::note()
|
||||||
|
);
|
||||||
|
event.fire(this.upcast(), CanGc::note());
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IDBOpenDBRequestMethods<crate::DomTypeHolder> for IDBOpenDBRequest {
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbopendbrequest-onblocked
|
||||||
|
event_handler!(blocked, GetOnblocked, SetOnblocked);
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbopendbrequest-onupgradeneeded
|
||||||
|
event_handler!(upgradeneeded, GetOnupgradeneeded, SetOnupgradeneeded);
|
||||||
|
}
|
276
components/script/dom/idbrequest.rs
Normal file
276
components/script/dom/idbrequest.rs
Normal file
|
@ -0,0 +1,276 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use std::cell::Cell;
|
||||||
|
|
||||||
|
use constellation_traits::StructuredSerializedData;
|
||||||
|
use dom_struct::dom_struct;
|
||||||
|
use ipc_channel::router::ROUTER;
|
||||||
|
use js::jsapi::Heap;
|
||||||
|
use js::jsval::{JSVal, UndefinedValue};
|
||||||
|
use js::rust::HandleValue;
|
||||||
|
use net_traits::IpcSend;
|
||||||
|
use net_traits::indexeddb_thread::{AsyncOperation, IndexedDBThreadMsg, IndexedDBTxnMode};
|
||||||
|
use profile_traits::ipc;
|
||||||
|
use stylo_atoms::Atom;
|
||||||
|
|
||||||
|
use crate::dom::bindings::codegen::Bindings::IDBRequestBinding::{
|
||||||
|
IDBRequestMethods, IDBRequestReadyState,
|
||||||
|
};
|
||||||
|
use crate::dom::bindings::codegen::Bindings::IDBTransactionBinding::IDBTransactionMode;
|
||||||
|
use crate::dom::bindings::error::{Error, Fallible};
|
||||||
|
use crate::dom::bindings::inheritance::Castable;
|
||||||
|
use crate::dom::bindings::refcounted::Trusted;
|
||||||
|
use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object};
|
||||||
|
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
|
||||||
|
use crate::dom::bindings::structuredclone;
|
||||||
|
use crate::dom::domexception::{DOMErrorName, DOMException};
|
||||||
|
use crate::dom::event::{Event, EventBubbles, EventCancelable};
|
||||||
|
use crate::dom::eventtarget::EventTarget;
|
||||||
|
use crate::dom::globalscope::GlobalScope;
|
||||||
|
use crate::dom::idbobjectstore::IDBObjectStore;
|
||||||
|
use crate::dom::idbtransaction::IDBTransaction;
|
||||||
|
use crate::realms::enter_realm;
|
||||||
|
use crate::script_runtime::{CanGc, JSContext as SafeJSContext};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct RequestListener {
|
||||||
|
request: Trusted<IDBRequest>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RequestListener {
|
||||||
|
fn handle_async_request_finished(&self, result: Option<Vec<u8>>) {
|
||||||
|
let request = self.request.root();
|
||||||
|
let global = request.global();
|
||||||
|
let cx = GlobalScope::get_cx();
|
||||||
|
|
||||||
|
request.set_ready_state_done();
|
||||||
|
|
||||||
|
let _ac = enter_realm(&*request);
|
||||||
|
rooted!(in(*cx) let mut answer = UndefinedValue());
|
||||||
|
|
||||||
|
if let Some(serialized_data) = result {
|
||||||
|
let data = StructuredSerializedData {
|
||||||
|
serialized: serialized_data,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
if structuredclone::read(&global, data, answer.handle_mut()).is_err() {
|
||||||
|
warn!("Error reading structuredclone data");
|
||||||
|
}
|
||||||
|
|
||||||
|
request.set_result(answer.handle());
|
||||||
|
|
||||||
|
let transaction = request
|
||||||
|
.transaction
|
||||||
|
.get()
|
||||||
|
.expect("Request unexpectedly has no transaction");
|
||||||
|
|
||||||
|
let event = Event::new(
|
||||||
|
&global,
|
||||||
|
Atom::from("success"),
|
||||||
|
EventBubbles::DoesNotBubble,
|
||||||
|
EventCancelable::NotCancelable,
|
||||||
|
CanGc::note(),
|
||||||
|
);
|
||||||
|
|
||||||
|
transaction.set_active_flag(true);
|
||||||
|
event
|
||||||
|
.upcast::<Event>()
|
||||||
|
.fire(request.upcast(), CanGc::note());
|
||||||
|
transaction.set_active_flag(false);
|
||||||
|
} else {
|
||||||
|
request.set_result(answer.handle());
|
||||||
|
|
||||||
|
// FIXME:(rasviitanen)
|
||||||
|
// Set the error of request to result
|
||||||
|
|
||||||
|
let transaction = request
|
||||||
|
.transaction
|
||||||
|
.get()
|
||||||
|
.expect("Request has no transaction");
|
||||||
|
|
||||||
|
let event = Event::new(
|
||||||
|
&global,
|
||||||
|
Atom::from("error"),
|
||||||
|
EventBubbles::Bubbles,
|
||||||
|
EventCancelable::Cancelable,
|
||||||
|
CanGc::note(),
|
||||||
|
);
|
||||||
|
|
||||||
|
transaction.set_active_flag(true);
|
||||||
|
event
|
||||||
|
.upcast::<Event>()
|
||||||
|
.fire(request.upcast(), CanGc::note());
|
||||||
|
transaction.set_active_flag(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[dom_struct]
|
||||||
|
pub struct IDBRequest {
|
||||||
|
eventtarget: EventTarget,
|
||||||
|
#[ignore_malloc_size_of = "mozjs"]
|
||||||
|
result: Heap<JSVal>,
|
||||||
|
error: MutNullableDom<DOMException>,
|
||||||
|
source: MutNullableDom<IDBObjectStore>,
|
||||||
|
transaction: MutNullableDom<IDBTransaction>,
|
||||||
|
ready_state: Cell<IDBRequestReadyState>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IDBRequest {
|
||||||
|
pub fn new_inherited() -> IDBRequest {
|
||||||
|
IDBRequest {
|
||||||
|
eventtarget: EventTarget::new_inherited(),
|
||||||
|
|
||||||
|
result: Heap::default(),
|
||||||
|
error: Default::default(),
|
||||||
|
source: Default::default(),
|
||||||
|
transaction: Default::default(),
|
||||||
|
ready_state: Cell::new(IDBRequestReadyState::Pending),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(global: &GlobalScope, can_gc: CanGc) -> DomRoot<IDBRequest> {
|
||||||
|
reflect_dom_object(Box::new(IDBRequest::new_inherited()), global, can_gc)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_source(&self, source: Option<&IDBObjectStore>) {
|
||||||
|
self.source.set(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_ready_state_done(&self) {
|
||||||
|
self.ready_state.set(IDBRequestReadyState::Done);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_result(&self, result: HandleValue) {
|
||||||
|
self.result.set(result.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_error(&self, error: Error, can_gc: CanGc) {
|
||||||
|
// FIXME:(rasviitanen) Support all error types
|
||||||
|
if let Error::Version = error {
|
||||||
|
self.error.set(Some(&DOMException::new(
|
||||||
|
&self.global(),
|
||||||
|
DOMErrorName::VersionError,
|
||||||
|
can_gc,
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_transaction(&self, transaction: &IDBTransaction) {
|
||||||
|
self.transaction.set(Some(transaction));
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#asynchronously-execute-a-request
|
||||||
|
pub fn execute_async(
|
||||||
|
source: &IDBObjectStore,
|
||||||
|
operation: AsyncOperation,
|
||||||
|
request: Option<DomRoot<IDBRequest>>,
|
||||||
|
can_gc: CanGc,
|
||||||
|
) -> Fallible<DomRoot<IDBRequest>> {
|
||||||
|
// Step 1: Let transaction be the transaction associated with source.
|
||||||
|
let transaction = source.transaction().expect("Store has no transaction");
|
||||||
|
let global = transaction.global();
|
||||||
|
|
||||||
|
// Step 2: Assert: transaction is active.
|
||||||
|
if !transaction.is_active() {
|
||||||
|
return Err(Error::TransactionInactive);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: If request was not given, let request be a new request with source as source.
|
||||||
|
let request = request.unwrap_or_else(|| {
|
||||||
|
let new_request = IDBRequest::new(&global, can_gc);
|
||||||
|
new_request.set_source(Some(source));
|
||||||
|
new_request.set_transaction(&transaction);
|
||||||
|
new_request
|
||||||
|
});
|
||||||
|
|
||||||
|
// Step 4: Add request to the end of transaction’s request list.
|
||||||
|
transaction.add_request(&request);
|
||||||
|
|
||||||
|
// Step 5: Run the operation, and queue a returning task in parallel
|
||||||
|
// the result will be put into `receiver`
|
||||||
|
let transaction_mode = match transaction.get_mode() {
|
||||||
|
IDBTransactionMode::Readonly => IndexedDBTxnMode::Readonly,
|
||||||
|
IDBTransactionMode::Readwrite => IndexedDBTxnMode::Readwrite,
|
||||||
|
IDBTransactionMode::Versionchange => IndexedDBTxnMode::Versionchange,
|
||||||
|
};
|
||||||
|
|
||||||
|
let (sender, receiver) =
|
||||||
|
ipc::channel::<std::option::Option<Vec<u8>>>(global.time_profiler_chan().clone())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let response_listener = RequestListener {
|
||||||
|
request: Trusted::new(&request),
|
||||||
|
};
|
||||||
|
|
||||||
|
let task_source = global
|
||||||
|
.task_manager()
|
||||||
|
.database_access_task_source()
|
||||||
|
.to_sendable();
|
||||||
|
|
||||||
|
ROUTER.add_typed_route(
|
||||||
|
receiver.to_ipc_receiver(),
|
||||||
|
Box::new(move |message| {
|
||||||
|
let response_listener = response_listener.clone();
|
||||||
|
task_source.queue(task!(request_callback: move || {
|
||||||
|
response_listener.handle_async_request_finished(
|
||||||
|
message.expect("Could not unwrap message"));
|
||||||
|
}));
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
transaction
|
||||||
|
.global()
|
||||||
|
.resource_threads()
|
||||||
|
.sender()
|
||||||
|
.send(IndexedDBThreadMsg::Async(
|
||||||
|
sender,
|
||||||
|
global.origin().immutable().clone(),
|
||||||
|
transaction.get_db_name().to_string(),
|
||||||
|
source.get_name().to_string(),
|
||||||
|
transaction.get_serial_number(),
|
||||||
|
transaction_mode,
|
||||||
|
operation,
|
||||||
|
))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Step 6
|
||||||
|
Ok(request)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IDBRequestMethods<crate::DomTypeHolder> for IDBRequest {
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbrequest-result
|
||||||
|
fn Result(&self, _cx: SafeJSContext, _val: js::rust::MutableHandle<'_, js::jsapi::Value>) {
|
||||||
|
self.result.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbrequest-error
|
||||||
|
fn GetError(&self) -> Option<DomRoot<DOMException>> {
|
||||||
|
self.error.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbrequest-source
|
||||||
|
fn GetSource(&self) -> Option<DomRoot<IDBObjectStore>> {
|
||||||
|
self.source.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbrequest-transaction
|
||||||
|
fn GetTransaction(&self) -> Option<DomRoot<IDBTransaction>> {
|
||||||
|
self.transaction.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbrequest-readystate
|
||||||
|
fn ReadyState(&self) -> IDBRequestReadyState {
|
||||||
|
self.ready_state.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbrequest-onsuccess
|
||||||
|
event_handler!(success, GetOnsuccess, SetOnsuccess);
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbrequest-onerror
|
||||||
|
event_handler!(error, GetOnerror, SetOnerror);
|
||||||
|
}
|
320
components/script/dom/idbtransaction.rs
Normal file
320
components/script/dom/idbtransaction.rs
Normal file
|
@ -0,0 +1,320 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use std::cell::Cell;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use dom_struct::dom_struct;
|
||||||
|
use ipc_channel::ipc::IpcSender;
|
||||||
|
use net_traits::IpcSend;
|
||||||
|
use net_traits::indexeddb_thread::{IndexedDBThreadMsg, IndexedDBThreadReturnType, SyncOperation};
|
||||||
|
use profile_traits::ipc;
|
||||||
|
use stylo_atoms::Atom;
|
||||||
|
|
||||||
|
use crate::dom::bindings::cell::DomRefCell;
|
||||||
|
use crate::dom::bindings::codegen::Bindings::DOMStringListBinding::DOMStringListMethods;
|
||||||
|
use crate::dom::bindings::codegen::Bindings::IDBTransactionBinding::{
|
||||||
|
IDBTransactionMethods, IDBTransactionMode,
|
||||||
|
};
|
||||||
|
use crate::dom::bindings::error::{Error, Fallible};
|
||||||
|
use crate::dom::bindings::inheritance::Castable;
|
||||||
|
use crate::dom::bindings::refcounted::Trusted;
|
||||||
|
use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object};
|
||||||
|
use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
|
||||||
|
use crate::dom::bindings::str::DOMString;
|
||||||
|
use crate::dom::domexception::DOMException;
|
||||||
|
use crate::dom::domstringlist::DOMStringList;
|
||||||
|
use crate::dom::event::{Event, EventBubbles, EventCancelable};
|
||||||
|
use crate::dom::eventtarget::EventTarget;
|
||||||
|
use crate::dom::globalscope::GlobalScope;
|
||||||
|
use crate::dom::idbdatabase::IDBDatabase;
|
||||||
|
use crate::dom::idbobjectstore::IDBObjectStore;
|
||||||
|
use crate::dom::idbrequest::IDBRequest;
|
||||||
|
use crate::script_runtime::CanGc;
|
||||||
|
|
||||||
|
#[dom_struct]
|
||||||
|
pub struct IDBTransaction {
|
||||||
|
eventtarget: EventTarget,
|
||||||
|
object_store_names: Dom<DOMStringList>,
|
||||||
|
mode: IDBTransactionMode,
|
||||||
|
db: Dom<IDBDatabase>,
|
||||||
|
error: MutNullableDom<DOMException>,
|
||||||
|
|
||||||
|
store_handles: DomRefCell<HashMap<String, Dom<IDBObjectStore>>>,
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#transaction-request-list
|
||||||
|
requests: DomRefCell<Vec<Dom<IDBRequest>>>,
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#transaction-active-flag
|
||||||
|
active: Cell<bool>,
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#transaction-finish
|
||||||
|
finished: Cell<bool>,
|
||||||
|
// An unique identifier, used to commit and revert this transaction
|
||||||
|
// FIXME:(rasviitanen) Replace this with a channel
|
||||||
|
serial_number: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IDBTransaction {
|
||||||
|
fn new_inherited(
|
||||||
|
connection: &IDBDatabase,
|
||||||
|
mode: IDBTransactionMode,
|
||||||
|
scope: &DOMStringList,
|
||||||
|
serial_number: u64,
|
||||||
|
) -> IDBTransaction {
|
||||||
|
IDBTransaction {
|
||||||
|
eventtarget: EventTarget::new_inherited(),
|
||||||
|
object_store_names: Dom::from_ref(scope),
|
||||||
|
mode,
|
||||||
|
db: Dom::from_ref(connection),
|
||||||
|
error: Default::default(),
|
||||||
|
|
||||||
|
store_handles: Default::default(),
|
||||||
|
requests: Default::default(),
|
||||||
|
active: Cell::new(true),
|
||||||
|
finished: Cell::new(false),
|
||||||
|
serial_number,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(
|
||||||
|
global: &GlobalScope,
|
||||||
|
connection: &IDBDatabase,
|
||||||
|
mode: IDBTransactionMode,
|
||||||
|
scope: &DOMStringList,
|
||||||
|
can_gc: CanGc,
|
||||||
|
) -> DomRoot<IDBTransaction> {
|
||||||
|
let serial_number = IDBTransaction::register_new(global, connection.get_name());
|
||||||
|
reflect_dom_object(
|
||||||
|
Box::new(IDBTransaction::new_inherited(
|
||||||
|
connection,
|
||||||
|
mode,
|
||||||
|
scope,
|
||||||
|
serial_number,
|
||||||
|
)),
|
||||||
|
global,
|
||||||
|
can_gc,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Registers a new transaction in the idb thread, and gets an unique serial number in return.
|
||||||
|
// The serial number is used when placing requests against a transaction
|
||||||
|
// and allows us to commit/abort transactions running in our idb thread.
|
||||||
|
// FIXME:(rasviitanen) We could probably replace this with a channel instead,
|
||||||
|
// and queue requests directly to that channel.
|
||||||
|
fn register_new(global: &GlobalScope, db_name: DOMString) -> u64 {
|
||||||
|
let (sender, receiver) = ipc::channel(global.time_profiler_chan().clone()).unwrap();
|
||||||
|
|
||||||
|
global
|
||||||
|
.resource_threads()
|
||||||
|
.sender()
|
||||||
|
.send(IndexedDBThreadMsg::Sync(SyncOperation::RegisterNewTxn(
|
||||||
|
sender,
|
||||||
|
global.origin().immutable().clone(),
|
||||||
|
db_name.to_string(),
|
||||||
|
)))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
receiver.recv().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Runs the transaction and waits for it to finish
|
||||||
|
pub fn wait(&self) {
|
||||||
|
// Start the transaction
|
||||||
|
let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
|
||||||
|
|
||||||
|
let start_operation = SyncOperation::StartTransaction(
|
||||||
|
sender,
|
||||||
|
self.global().origin().immutable().clone(),
|
||||||
|
self.db.get_name().to_string(),
|
||||||
|
self.serial_number,
|
||||||
|
);
|
||||||
|
|
||||||
|
self.get_idb_thread()
|
||||||
|
.send(IndexedDBThreadMsg::Sync(start_operation))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Wait for transaction to complete
|
||||||
|
if receiver.recv().is_err() {
|
||||||
|
warn!("IDBtransaction failed to run");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_active_flag(&self, status: bool) {
|
||||||
|
self.active.set(status)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_active(&self) -> bool {
|
||||||
|
self.active.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_mode(&self) -> IDBTransactionMode {
|
||||||
|
self.mode
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_db_name(&self) -> DOMString {
|
||||||
|
self.db.get_name()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_serial_number(&self) -> u64 {
|
||||||
|
self.serial_number
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_request(&self, request: &IDBRequest) {
|
||||||
|
self.requests.borrow_mut().push(Dom::from_ref(request));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn upgrade_db_version(&self, version: u64) {
|
||||||
|
// Runs the previous request and waits for them to finish
|
||||||
|
self.wait();
|
||||||
|
// Queue a request to upgrade the db version
|
||||||
|
let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
|
||||||
|
let upgrade_version_operation = SyncOperation::UpgradeVersion(
|
||||||
|
sender,
|
||||||
|
self.global().origin().immutable().clone(),
|
||||||
|
self.db.get_name().to_string(),
|
||||||
|
self.serial_number,
|
||||||
|
version,
|
||||||
|
);
|
||||||
|
self.get_idb_thread()
|
||||||
|
.send(IndexedDBThreadMsg::Sync(upgrade_version_operation))
|
||||||
|
.unwrap();
|
||||||
|
// Wait for the version to be updated
|
||||||
|
receiver.recv().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dispatch_complete(&self) {
|
||||||
|
let global = self.global();
|
||||||
|
let this = Trusted::new(self);
|
||||||
|
global.task_manager().database_access_task_source().queue(
|
||||||
|
task!(send_complete_notification: move || {
|
||||||
|
let this = this.root();
|
||||||
|
let global = this.global();
|
||||||
|
let event = Event::new(
|
||||||
|
&global,
|
||||||
|
Atom::from("complete"),
|
||||||
|
EventBubbles::DoesNotBubble,
|
||||||
|
EventCancelable::NotCancelable,
|
||||||
|
CanGc::note()
|
||||||
|
);
|
||||||
|
event.fire(this.upcast(), CanGc::note());
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_idb_thread(&self) -> IpcSender<IndexedDBThreadMsg> {
|
||||||
|
self.global().resource_threads().sender()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IDBTransactionMethods<crate::DomTypeHolder> for IDBTransaction {
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbtransaction-db
|
||||||
|
fn Db(&self) -> DomRoot<IDBDatabase> {
|
||||||
|
DomRoot::from_ref(&*self.db)
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbtransaction-objectstore
|
||||||
|
fn ObjectStore(&self, name: DOMString) -> Fallible<DomRoot<IDBObjectStore>> {
|
||||||
|
// Step 1: Handle the case where transaction has finised
|
||||||
|
if self.finished.get() {
|
||||||
|
return Err(Error::InvalidState);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2: Check that the object store exists
|
||||||
|
if !self.object_store_names.Contains(name.clone()) {
|
||||||
|
return Err(Error::NotFound);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: Each call to this method on the same
|
||||||
|
// IDBTransaction instance with the same name
|
||||||
|
// returns the same IDBObjectStore instance.
|
||||||
|
let mut store_handles = self.store_handles.borrow_mut();
|
||||||
|
let store = store_handles.entry(name.to_string()).or_insert_with(|| {
|
||||||
|
let store = IDBObjectStore::new(
|
||||||
|
&self.global(),
|
||||||
|
self.db.get_name(),
|
||||||
|
name,
|
||||||
|
None,
|
||||||
|
CanGc::note(),
|
||||||
|
);
|
||||||
|
store.set_transaction(self);
|
||||||
|
Dom::from_ref(&*store)
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(DomRoot::from_ref(&*store))
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#commit-transaction
|
||||||
|
fn Commit(&self) -> Fallible<()> {
|
||||||
|
// Step 1
|
||||||
|
let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
|
||||||
|
let start_operation = SyncOperation::Commit(
|
||||||
|
sender,
|
||||||
|
self.global().origin().immutable().clone(),
|
||||||
|
self.db.get_name().to_string(),
|
||||||
|
self.serial_number,
|
||||||
|
);
|
||||||
|
|
||||||
|
self.get_idb_thread()
|
||||||
|
.send(IndexedDBThreadMsg::Sync(start_operation))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let result = receiver.recv().unwrap();
|
||||||
|
|
||||||
|
// Step 2
|
||||||
|
if let IndexedDBThreadReturnType::Commit(Err(_result)) = result {
|
||||||
|
// FIXME:(rasviitanen) also support Unknown error
|
||||||
|
return Err(Error::QuotaExceeded);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3
|
||||||
|
// FIXME:(rasviitanen) https://www.w3.org/TR/IndexedDB-2/#commit-a-transaction
|
||||||
|
|
||||||
|
// Steps 3.1 and 3.3
|
||||||
|
self.dispatch_complete();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbtransaction-abort
|
||||||
|
fn Abort(&self) -> Fallible<()> {
|
||||||
|
// FIXME:(rasviitanen)
|
||||||
|
// This only sets the flags, and does not abort the transaction
|
||||||
|
// see https://www.w3.org/TR/IndexedDB-2/#abort-a-transaction
|
||||||
|
if self.finished.get() {
|
||||||
|
return Err(Error::InvalidState);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.active.set(false);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbtransaction-objectstorenames
|
||||||
|
fn ObjectStoreNames(&self) -> DomRoot<DOMStringList> {
|
||||||
|
self.object_store_names.as_rooted()
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbtransaction-mode
|
||||||
|
fn Mode(&self) -> IDBTransactionMode {
|
||||||
|
self.mode
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbtransaction-mode
|
||||||
|
// fn Durability(&self) -> IDBTransactionDurability {
|
||||||
|
// // FIXME:(arihant2math) Durability is not implemented at all
|
||||||
|
// unimplemented!();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbtransaction-error
|
||||||
|
fn GetError(&self) -> Option<DomRoot<DOMException>> {
|
||||||
|
self.error.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbtransaction-onabort
|
||||||
|
event_handler!(abort, GetOnabort, SetOnabort);
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbtransaction-oncomplete
|
||||||
|
event_handler!(complete, GetOncomplete, SetOncomplete);
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbtransaction-onerror
|
||||||
|
event_handler!(error, GetOnerror, SetOnerror);
|
||||||
|
}
|
117
components/script/dom/idbversionchangeevent.rs
Normal file
117
components/script/dom/idbversionchangeevent.rs
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use dom_struct::dom_struct;
|
||||||
|
use stylo_atoms::Atom;
|
||||||
|
|
||||||
|
use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods;
|
||||||
|
use crate::dom::bindings::codegen::Bindings::IDBVersionChangeEventBinding::{
|
||||||
|
IDBVersionChangeEventInit, IDBVersionChangeEventMethods,
|
||||||
|
};
|
||||||
|
use crate::dom::bindings::import::module::HandleObject;
|
||||||
|
use crate::dom::bindings::inheritance::Castable;
|
||||||
|
use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object};
|
||||||
|
use crate::dom::bindings::root::DomRoot;
|
||||||
|
use crate::dom::bindings::str::DOMString;
|
||||||
|
use crate::dom::event::{Event, EventBubbles, EventCancelable};
|
||||||
|
use crate::dom::globalscope::GlobalScope;
|
||||||
|
use crate::dom::window::Window;
|
||||||
|
use crate::script_runtime::CanGc;
|
||||||
|
|
||||||
|
#[dom_struct]
|
||||||
|
pub(crate) struct IDBVersionChangeEvent {
|
||||||
|
event: Event,
|
||||||
|
old_version: u64,
|
||||||
|
new_version: Option<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IDBVersionChangeEvent {
|
||||||
|
pub fn new_inherited(old_version: u64, new_version: Option<u64>) -> IDBVersionChangeEvent {
|
||||||
|
IDBVersionChangeEvent {
|
||||||
|
event: Event::new_inherited(),
|
||||||
|
old_version,
|
||||||
|
new_version,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(
|
||||||
|
global: &GlobalScope,
|
||||||
|
type_: Atom,
|
||||||
|
bubbles: EventBubbles,
|
||||||
|
cancelable: EventCancelable,
|
||||||
|
old_version: u64,
|
||||||
|
new_version: Option<u64>,
|
||||||
|
can_gc: CanGc,
|
||||||
|
) -> DomRoot<IDBVersionChangeEvent> {
|
||||||
|
Self::new_with_proto(
|
||||||
|
global,
|
||||||
|
type_,
|
||||||
|
bool::from(bubbles),
|
||||||
|
bool::from(cancelable),
|
||||||
|
old_version,
|
||||||
|
new_version,
|
||||||
|
can_gc,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_with_proto(
|
||||||
|
global: &GlobalScope,
|
||||||
|
type_: Atom,
|
||||||
|
bubbles: bool,
|
||||||
|
cancelable: bool,
|
||||||
|
old_version: u64,
|
||||||
|
new_version: Option<u64>,
|
||||||
|
can_gc: CanGc,
|
||||||
|
) -> DomRoot<Self> {
|
||||||
|
let ev = reflect_dom_object(
|
||||||
|
Box::new(IDBVersionChangeEvent::new_inherited(
|
||||||
|
old_version,
|
||||||
|
new_version,
|
||||||
|
)),
|
||||||
|
global,
|
||||||
|
can_gc,
|
||||||
|
);
|
||||||
|
{
|
||||||
|
let event = ev.upcast::<Event>();
|
||||||
|
event.init_event(type_, bubbles, cancelable);
|
||||||
|
}
|
||||||
|
ev
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IDBVersionChangeEventMethods<crate::DomTypeHolder> for IDBVersionChangeEvent {
|
||||||
|
/// <https://w3c.github.io/IndexedDB/#dom-idbversionchangeevent-idbversionchangeevent>
|
||||||
|
fn Constructor(
|
||||||
|
window: &Window,
|
||||||
|
_proto: Option<HandleObject>,
|
||||||
|
can_gc: CanGc,
|
||||||
|
type_: DOMString,
|
||||||
|
init: &IDBVersionChangeEventInit,
|
||||||
|
) -> DomRoot<Self> {
|
||||||
|
Self::new_with_proto(
|
||||||
|
&window.global(),
|
||||||
|
Atom::from(type_),
|
||||||
|
init.parent.bubbles,
|
||||||
|
init.parent.cancelable,
|
||||||
|
init.oldVersion,
|
||||||
|
init.newVersion,
|
||||||
|
can_gc,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbversionchangeevent-oldversion
|
||||||
|
fn OldVersion(&self) -> u64 {
|
||||||
|
self.old_version
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbversionchangeevent-newversion
|
||||||
|
fn GetNewVersion(&self) -> Option<u64> {
|
||||||
|
self.new_version
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://dom.spec.whatwg.org/#dom-event-istrusted
|
||||||
|
fn IsTrusted(&self) -> bool {
|
||||||
|
self.event.IsTrusted()
|
||||||
|
}
|
||||||
|
}
|
|
@ -419,6 +419,13 @@ pub(crate) mod htmltrackelement;
|
||||||
pub(crate) mod htmlulistelement;
|
pub(crate) mod htmlulistelement;
|
||||||
pub(crate) mod htmlunknownelement;
|
pub(crate) mod htmlunknownelement;
|
||||||
pub(crate) mod htmlvideoelement;
|
pub(crate) mod htmlvideoelement;
|
||||||
|
pub(crate) mod idbdatabase;
|
||||||
|
pub(crate) mod idbfactory;
|
||||||
|
pub(crate) mod idbobjectstore;
|
||||||
|
pub(crate) mod idbopendbrequest;
|
||||||
|
pub(crate) mod idbrequest;
|
||||||
|
pub(crate) mod idbtransaction;
|
||||||
|
pub(crate) mod idbversionchangeevent;
|
||||||
pub(crate) mod iirfilternode;
|
pub(crate) mod iirfilternode;
|
||||||
pub(crate) mod imagebitmap;
|
pub(crate) mod imagebitmap;
|
||||||
pub(crate) mod imagedata;
|
pub(crate) mod imagedata;
|
||||||
|
|
|
@ -136,6 +136,7 @@ use crate::dom::hashchangeevent::HashChangeEvent;
|
||||||
use crate::dom::history::History;
|
use crate::dom::history::History;
|
||||||
use crate::dom::htmlcollection::{CollectionFilter, HTMLCollection};
|
use crate::dom::htmlcollection::{CollectionFilter, HTMLCollection};
|
||||||
use crate::dom::htmliframeelement::HTMLIFrameElement;
|
use crate::dom::htmliframeelement::HTMLIFrameElement;
|
||||||
|
use crate::dom::idbfactory::IDBFactory;
|
||||||
use crate::dom::location::Location;
|
use crate::dom::location::Location;
|
||||||
use crate::dom::medialist::MediaList;
|
use crate::dom::medialist::MediaList;
|
||||||
use crate::dom::mediaquerylist::{MediaQueryList, MediaQueryListMatchState};
|
use crate::dom::mediaquerylist::{MediaQueryList, MediaQueryListMatchState};
|
||||||
|
@ -248,6 +249,7 @@ pub(crate) struct Window {
|
||||||
document: MutNullableDom<Document>,
|
document: MutNullableDom<Document>,
|
||||||
location: MutNullableDom<Location>,
|
location: MutNullableDom<Location>,
|
||||||
history: MutNullableDom<History>,
|
history: MutNullableDom<History>,
|
||||||
|
indexeddb: MutNullableDom<IDBFactory>,
|
||||||
custom_element_registry: MutNullableDom<CustomElementRegistry>,
|
custom_element_registry: MutNullableDom<CustomElementRegistry>,
|
||||||
performance: MutNullableDom<Performance>,
|
performance: MutNullableDom<Performance>,
|
||||||
#[no_trace]
|
#[no_trace]
|
||||||
|
@ -1096,6 +1098,14 @@ impl WindowMethods<crate::DomTypeHolder> for Window {
|
||||||
self.history.or_init(|| History::new(self, CanGc::note()))
|
self.history.or_init(|| History::new(self, CanGc::note()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://w3c.github.io/IndexedDB/#factory-interface
|
||||||
|
fn IndexedDB(&self) -> DomRoot<IDBFactory> {
|
||||||
|
self.indexeddb.or_init(|| {
|
||||||
|
let global_scope = self.upcast::<GlobalScope>();
|
||||||
|
IDBFactory::new(global_scope, CanGc::note())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-window-customelements
|
// https://html.spec.whatwg.org/multipage/#dom-window-customelements
|
||||||
fn CustomElements(&self) -> DomRoot<CustomElementRegistry> {
|
fn CustomElements(&self) -> DomRoot<CustomElementRegistry> {
|
||||||
self.custom_element_registry
|
self.custom_element_registry
|
||||||
|
@ -3093,6 +3103,7 @@ impl Window {
|
||||||
navigator: Default::default(),
|
navigator: Default::default(),
|
||||||
location: Default::default(),
|
location: Default::default(),
|
||||||
history: Default::default(),
|
history: Default::default(),
|
||||||
|
indexeddb: Default::default(),
|
||||||
custom_element_registry: Default::default(),
|
custom_element_registry: Default::default(),
|
||||||
window_proxy: Default::default(),
|
window_proxy: Default::default(),
|
||||||
document: Default::default(),
|
document: Default::default(),
|
||||||
|
|
|
@ -53,6 +53,7 @@ use crate::dom::bindings::trace::RootedTraceableBox;
|
||||||
use crate::dom::crypto::Crypto;
|
use crate::dom::crypto::Crypto;
|
||||||
use crate::dom::dedicatedworkerglobalscope::DedicatedWorkerGlobalScope;
|
use crate::dom::dedicatedworkerglobalscope::DedicatedWorkerGlobalScope;
|
||||||
use crate::dom::globalscope::GlobalScope;
|
use crate::dom::globalscope::GlobalScope;
|
||||||
|
use crate::dom::idbfactory::IDBFactory;
|
||||||
use crate::dom::performance::Performance;
|
use crate::dom::performance::Performance;
|
||||||
use crate::dom::promise::Promise;
|
use crate::dom::promise::Promise;
|
||||||
use crate::dom::trustedscripturl::TrustedScriptURL;
|
use crate::dom::trustedscripturl::TrustedScriptURL;
|
||||||
|
@ -127,6 +128,7 @@ pub(crate) struct WorkerGlobalScope {
|
||||||
#[no_trace]
|
#[no_trace]
|
||||||
navigation_start: CrossProcessInstant,
|
navigation_start: CrossProcessInstant,
|
||||||
performance: MutNullableDom<Performance>,
|
performance: MutNullableDom<Performance>,
|
||||||
|
indexeddb: MutNullableDom<IDBFactory>,
|
||||||
trusted_types: MutNullableDom<TrustedTypePolicyFactory>,
|
trusted_types: MutNullableDom<TrustedTypePolicyFactory>,
|
||||||
|
|
||||||
/// A [`TimerScheduler`] used to schedule timers for this [`WorkerGlobalScope`].
|
/// A [`TimerScheduler`] used to schedule timers for this [`WorkerGlobalScope`].
|
||||||
|
@ -188,6 +190,7 @@ impl WorkerGlobalScope {
|
||||||
_devtools_sender: init.from_devtools_sender,
|
_devtools_sender: init.from_devtools_sender,
|
||||||
navigation_start: CrossProcessInstant::now(),
|
navigation_start: CrossProcessInstant::now(),
|
||||||
performance: Default::default(),
|
performance: Default::default(),
|
||||||
|
indexeddb: Default::default(),
|
||||||
timer_scheduler: RefCell::default(),
|
timer_scheduler: RefCell::default(),
|
||||||
insecure_requests_policy,
|
insecure_requests_policy,
|
||||||
trusted_types: Default::default(),
|
trusted_types: Default::default(),
|
||||||
|
@ -274,6 +277,14 @@ impl WorkerGlobalScopeMethods<crate::DomTypeHolder> for WorkerGlobalScope {
|
||||||
DomRoot::from_ref(self)
|
DomRoot::from_ref(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://w3c.github.io/IndexedDB/#factory-interface
|
||||||
|
fn IndexedDB(&self) -> DomRoot<IDBFactory> {
|
||||||
|
self.indexeddb.or_init(|| {
|
||||||
|
let global_scope = self.upcast::<GlobalScope>();
|
||||||
|
IDBFactory::new(global_scope, CanGc::note())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-workerglobalscope-location
|
// https://html.spec.whatwg.org/multipage/#dom-workerglobalscope-location
|
||||||
fn Location(&self) -> DomRoot<WorkerLocation> {
|
fn Location(&self) -> DomRoot<WorkerLocation> {
|
||||||
self.location
|
self.location
|
||||||
|
|
|
@ -99,6 +99,7 @@ static SECURITY_CALLBACKS: JSSecurityCallbacks = JSSecurityCallbacks {
|
||||||
pub(crate) enum ScriptThreadEventCategory {
|
pub(crate) enum ScriptThreadEventCategory {
|
||||||
AttachLayout,
|
AttachLayout,
|
||||||
ConstellationMsg,
|
ConstellationMsg,
|
||||||
|
DatabaseAccessEvent,
|
||||||
DevtoolsMsg,
|
DevtoolsMsg,
|
||||||
DocumentEvent,
|
DocumentEvent,
|
||||||
FileRead,
|
FileRead,
|
||||||
|
@ -133,6 +134,9 @@ impl From<ScriptThreadEventCategory> for ProfilerCategory {
|
||||||
match category {
|
match category {
|
||||||
ScriptThreadEventCategory::AttachLayout => ProfilerCategory::ScriptAttachLayout,
|
ScriptThreadEventCategory::AttachLayout => ProfilerCategory::ScriptAttachLayout,
|
||||||
ScriptThreadEventCategory::ConstellationMsg => ProfilerCategory::ScriptConstellationMsg,
|
ScriptThreadEventCategory::ConstellationMsg => ProfilerCategory::ScriptConstellationMsg,
|
||||||
|
ScriptThreadEventCategory::DatabaseAccessEvent => {
|
||||||
|
ProfilerCategory::ScriptDatabaseAccessEvent
|
||||||
|
},
|
||||||
ScriptThreadEventCategory::DevtoolsMsg => ProfilerCategory::ScriptDevtoolsMsg,
|
ScriptThreadEventCategory::DevtoolsMsg => ProfilerCategory::ScriptDevtoolsMsg,
|
||||||
ScriptThreadEventCategory::DocumentEvent => ProfilerCategory::ScriptDocumentEvent,
|
ScriptThreadEventCategory::DocumentEvent => ProfilerCategory::ScriptDocumentEvent,
|
||||||
ScriptThreadEventCategory::EnterFullscreen => ProfilerCategory::ScriptEnterFullscreen,
|
ScriptThreadEventCategory::EnterFullscreen => ProfilerCategory::ScriptEnterFullscreen,
|
||||||
|
@ -177,6 +181,9 @@ impl From<ScriptThreadEventCategory> for ScriptHangAnnotation {
|
||||||
match category {
|
match category {
|
||||||
ScriptThreadEventCategory::AttachLayout => ScriptHangAnnotation::AttachLayout,
|
ScriptThreadEventCategory::AttachLayout => ScriptHangAnnotation::AttachLayout,
|
||||||
ScriptThreadEventCategory::ConstellationMsg => ScriptHangAnnotation::ConstellationMsg,
|
ScriptThreadEventCategory::ConstellationMsg => ScriptHangAnnotation::ConstellationMsg,
|
||||||
|
ScriptThreadEventCategory::DatabaseAccessEvent => {
|
||||||
|
ScriptHangAnnotation::DatabaseAccessEvent
|
||||||
|
},
|
||||||
ScriptThreadEventCategory::DevtoolsMsg => ScriptHangAnnotation::DevtoolsMsg,
|
ScriptThreadEventCategory::DevtoolsMsg => ScriptHangAnnotation::DevtoolsMsg,
|
||||||
ScriptThreadEventCategory::DocumentEvent => ScriptHangAnnotation::DocumentEvent,
|
ScriptThreadEventCategory::DocumentEvent => ScriptHangAnnotation::DocumentEvent,
|
||||||
ScriptThreadEventCategory::InputEvent => ScriptHangAnnotation::InputEvent,
|
ScriptThreadEventCategory::InputEvent => ScriptHangAnnotation::InputEvent,
|
||||||
|
|
|
@ -1739,6 +1739,12 @@ impl ScriptThread {
|
||||||
profiler_chan,
|
profiler_chan,
|
||||||
f
|
f
|
||||||
),
|
),
|
||||||
|
ScriptThreadEventCategory::DatabaseAccessEvent => time_profile!(
|
||||||
|
ProfilerCategory::ScriptDatabaseAccessEvent,
|
||||||
|
None,
|
||||||
|
profiler_chan,
|
||||||
|
f
|
||||||
|
),
|
||||||
ScriptThreadEventCategory::DevtoolsMsg => {
|
ScriptThreadEventCategory::DevtoolsMsg => {
|
||||||
time_profile!(ProfilerCategory::ScriptDevtoolsMsg, None, profiler_chan, f)
|
time_profile!(ProfilerCategory::ScriptDevtoolsMsg, None, profiler_chan, f)
|
||||||
},
|
},
|
||||||
|
|
|
@ -135,6 +135,7 @@ impl TaskManager {
|
||||||
task_source_functions!(self, bitmap_task_source, Bitmap);
|
task_source_functions!(self, bitmap_task_source, Bitmap);
|
||||||
task_source_functions!(self, canvas_blob_task_source, Canvas);
|
task_source_functions!(self, canvas_blob_task_source, Canvas);
|
||||||
task_source_functions!(self, clipboard_task_source, Clipboard);
|
task_source_functions!(self, clipboard_task_source, Clipboard);
|
||||||
|
task_source_functions!(self, database_access_task_source, DatabaseAccess);
|
||||||
task_source_functions!(self, dom_manipulation_task_source, DOMManipulation);
|
task_source_functions!(self, dom_manipulation_task_source, DOMManipulation);
|
||||||
task_source_functions!(self, file_reading_task_source, FileReading);
|
task_source_functions!(self, file_reading_task_source, FileReading);
|
||||||
task_source_functions!(self, font_loading_task_source, FontLoading);
|
task_source_functions!(self, font_loading_task_source, FontLoading);
|
||||||
|
|
|
@ -26,6 +26,7 @@ pub(crate) enum TaskSourceName {
|
||||||
Bitmap,
|
Bitmap,
|
||||||
Canvas,
|
Canvas,
|
||||||
Clipboard,
|
Clipboard,
|
||||||
|
DatabaseAccess,
|
||||||
DOMManipulation,
|
DOMManipulation,
|
||||||
FileReading,
|
FileReading,
|
||||||
/// <https://drafts.csswg.org/css-font-loading/#task-source>
|
/// <https://drafts.csswg.org/css-font-loading/#task-source>
|
||||||
|
@ -53,6 +54,7 @@ impl From<TaskSourceName> for ScriptThreadEventCategory {
|
||||||
TaskSourceName::Bitmap => ScriptThreadEventCategory::ScriptEvent,
|
TaskSourceName::Bitmap => ScriptThreadEventCategory::ScriptEvent,
|
||||||
TaskSourceName::Canvas => ScriptThreadEventCategory::ScriptEvent,
|
TaskSourceName::Canvas => ScriptThreadEventCategory::ScriptEvent,
|
||||||
TaskSourceName::Clipboard => ScriptThreadEventCategory::ScriptEvent,
|
TaskSourceName::Clipboard => ScriptThreadEventCategory::ScriptEvent,
|
||||||
|
TaskSourceName::DatabaseAccess => ScriptThreadEventCategory::ScriptEvent,
|
||||||
TaskSourceName::DOMManipulation => ScriptThreadEventCategory::ScriptEvent,
|
TaskSourceName::DOMManipulation => ScriptThreadEventCategory::ScriptEvent,
|
||||||
TaskSourceName::FileReading => ScriptThreadEventCategory::FileRead,
|
TaskSourceName::FileReading => ScriptThreadEventCategory::FileRead,
|
||||||
TaskSourceName::FontLoading => ScriptThreadEventCategory::FontLoading,
|
TaskSourceName::FontLoading => ScriptThreadEventCategory::FontLoading,
|
||||||
|
|
|
@ -45,6 +45,12 @@ pub enum Error {
|
||||||
InvalidNodeType,
|
InvalidNodeType,
|
||||||
/// DataCloneError DOMException
|
/// DataCloneError DOMException
|
||||||
DataClone(Option<String>),
|
DataClone(Option<String>),
|
||||||
|
/// TransactionInactiveError DOMException
|
||||||
|
TransactionInactive,
|
||||||
|
/// ReadOnlyError DOMException
|
||||||
|
ReadOnly,
|
||||||
|
/// VersionError DOMException
|
||||||
|
Version,
|
||||||
/// NoModificationAllowedError DOMException
|
/// NoModificationAllowedError DOMException
|
||||||
NoModificationAllowed,
|
NoModificationAllowed,
|
||||||
/// QuotaExceededError DOMException
|
/// QuotaExceededError DOMException
|
||||||
|
|
44
components/script_bindings/webidls/IDBDatabase.webidl
Normal file
44
components/script_bindings/webidls/IDBDatabase.webidl
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
/*
|
||||||
|
* The origin of this IDL file is
|
||||||
|
* https://w3c.github.io/IndexedDB/#idbdatabase
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// https://w3c.github.io/IndexedDB/#idbdatabase
|
||||||
|
[Pref="dom_indexeddb_enabled", Exposed=(Window,Worker)]
|
||||||
|
interface IDBDatabase : EventTarget {
|
||||||
|
readonly attribute DOMString name;
|
||||||
|
readonly attribute unsigned long long version;
|
||||||
|
readonly attribute DOMStringList objectStoreNames;
|
||||||
|
|
||||||
|
[Throws, NewObject] IDBTransaction transaction((DOMString or sequence<DOMString>) storeNames,
|
||||||
|
optional IDBTransactionMode mode = "readonly",
|
||||||
|
optional IDBTransactionOptions options = {});
|
||||||
|
undefined close();
|
||||||
|
|
||||||
|
[Throws, NewObject] IDBObjectStore createObjectStore(
|
||||||
|
DOMString name,
|
||||||
|
optional IDBObjectStoreParameters options = {}
|
||||||
|
);
|
||||||
|
[Throws] undefined deleteObjectStore(DOMString name);
|
||||||
|
|
||||||
|
// Event handlers:
|
||||||
|
attribute EventHandler onabort;
|
||||||
|
attribute EventHandler onclose;
|
||||||
|
attribute EventHandler onerror;
|
||||||
|
attribute EventHandler onversionchange;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum IDBTransactionDurability { "default", "strict", "relaxed" };
|
||||||
|
|
||||||
|
dictionary IDBTransactionOptions {
|
||||||
|
IDBTransactionDurability durability = "default";
|
||||||
|
};
|
||||||
|
|
||||||
|
dictionary IDBObjectStoreParameters {
|
||||||
|
(DOMString or sequence<DOMString>)? keyPath = null;
|
||||||
|
boolean autoIncrement = false;
|
||||||
|
};
|
31
components/script_bindings/webidls/IDBFactory.webidl
Normal file
31
components/script_bindings/webidls/IDBFactory.webidl
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
/*
|
||||||
|
* The origin of this IDL file is
|
||||||
|
* https://w3c.github.io/IndexedDB/#idbfactory
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// https://w3c.github.io/IndexedDB/#idbfactory
|
||||||
|
partial interface mixin WindowOrWorkerGlobalScope {
|
||||||
|
[Pref="dom_indexeddb_enabled", SameObject] readonly attribute IDBFactory indexedDB;
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://w3c.github.io/IndexedDB/#idbfactory
|
||||||
|
[Pref="dom_indexeddb_enabled", Exposed=(Window,Worker)]
|
||||||
|
interface IDBFactory {
|
||||||
|
[NewObject, Throws] IDBOpenDBRequest open(DOMString name,
|
||||||
|
optional [EnforceRange] unsigned long long version);
|
||||||
|
[NewObject, Throws] IDBOpenDBRequest deleteDatabase(DOMString name);
|
||||||
|
|
||||||
|
// Promise<sequence<IDBDatabaseInfo>> databases();
|
||||||
|
|
||||||
|
// short cmp(any first, any second);
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://w3c.github.io/IndexedDB/#dictdef-idbdatabaseinfo
|
||||||
|
dictionary IDBDatabaseInfo {
|
||||||
|
DOMString name;
|
||||||
|
unsigned long long version;
|
||||||
|
};
|
48
components/script_bindings/webidls/IDBObjectStore.webidl
Normal file
48
components/script_bindings/webidls/IDBObjectStore.webidl
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
/*
|
||||||
|
* The origin of this IDL file is
|
||||||
|
* https://w3c.github.io/IndexedDB/#idbobjectstore
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// https://w3c.github.io/IndexedDB/#idbobjectstore
|
||||||
|
[Pref="dom_indexeddb_enabled", Exposed=(Window,Worker)]
|
||||||
|
interface IDBObjectStore {
|
||||||
|
attribute DOMString name;
|
||||||
|
// readonly attribute any keyPath;
|
||||||
|
// readonly attribute DOMStringList indexNames;
|
||||||
|
// [SameObject] readonly attribute IDBTransaction transaction;
|
||||||
|
readonly attribute boolean autoIncrement;
|
||||||
|
|
||||||
|
[NewObject, Throws] IDBRequest put(any value, optional any key);
|
||||||
|
[NewObject, Throws] IDBRequest add(any value, optional any key);
|
||||||
|
[NewObject, Throws] IDBRequest delete(any query);
|
||||||
|
[NewObject, Throws] IDBRequest clear();
|
||||||
|
[NewObject, Throws] IDBRequest get(any query);
|
||||||
|
// [NewObject] IDBRequest getKey(any query);
|
||||||
|
// [NewObject] IDBRequest getAll(optional any query,
|
||||||
|
// optional [EnforceRange] unsigned long count);
|
||||||
|
// [NewObject] IDBRequest getAllKeys(optional any query,
|
||||||
|
// optional [EnforceRange] unsigned long count);
|
||||||
|
[NewObject, Throws] IDBRequest count(optional any query);
|
||||||
|
|
||||||
|
// [NewObject] IDBRequest openCursor(optional any query,
|
||||||
|
// optional IDBCursorDirection direction = "next");
|
||||||
|
// [NewObject] IDBRequest openKeyCursor(optional any query,
|
||||||
|
// optional IDBCursorDirection direction = "next");
|
||||||
|
|
||||||
|
// IDBIndex index(DOMString name);
|
||||||
|
|
||||||
|
// [NewObject] IDBIndex createIndex(DOMString name,
|
||||||
|
// (DOMString or sequence<DOMString>) keyPath,
|
||||||
|
// optional IDBIndexParameters options = {});
|
||||||
|
// void deleteIndex(DOMString name);
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://w3c.github.io/IndexedDB/#dictdef-idbindexparameters
|
||||||
|
dictionary IDBIndexParameters {
|
||||||
|
boolean unique = false;
|
||||||
|
boolean multiEntry = false;
|
||||||
|
};
|
16
components/script_bindings/webidls/IDBOpenDBRequest.webidl
Normal file
16
components/script_bindings/webidls/IDBOpenDBRequest.webidl
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
/*
|
||||||
|
* The origin of this IDL file is
|
||||||
|
* https://w3c.github.io/IndexedDB/#idbopendbrequest
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// https://w3c.github.io/IndexedDB/#idbopendbrequest
|
||||||
|
[Pref="dom_indexeddb_enabled", Exposed=(Window,Worker)]
|
||||||
|
interface IDBOpenDBRequest : IDBRequest {
|
||||||
|
// Event handlers:
|
||||||
|
attribute EventHandler onblocked;
|
||||||
|
attribute EventHandler onupgradeneeded;
|
||||||
|
};
|
29
components/script_bindings/webidls/IDBRequest.webidl
Normal file
29
components/script_bindings/webidls/IDBRequest.webidl
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
/*
|
||||||
|
* The origin of this IDL file is
|
||||||
|
* https://w3c.github.io/IndexedDB/#idbrequest
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// https://w3c.github.io/IndexedDB/#idbrequest
|
||||||
|
[Pref="dom_indexeddb_enabled", Exposed=(Window,Worker)]
|
||||||
|
interface IDBRequest : EventTarget {
|
||||||
|
readonly attribute any result;
|
||||||
|
readonly attribute DOMException? error;
|
||||||
|
// readonly attribute (IDBObjectStore or IDBIndex or IDBCursor)? source;
|
||||||
|
readonly attribute IDBObjectStore? source;
|
||||||
|
readonly attribute IDBTransaction? transaction;
|
||||||
|
readonly attribute IDBRequestReadyState readyState;
|
||||||
|
|
||||||
|
// Event handlers:
|
||||||
|
attribute EventHandler onsuccess;
|
||||||
|
attribute EventHandler onerror;
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://w3c.github.io/IndexedDB/#enumdef-idbrequestreadystate
|
||||||
|
enum IDBRequestReadyState {
|
||||||
|
"pending",
|
||||||
|
"done"
|
||||||
|
};
|
33
components/script_bindings/webidls/IDBTransaction.webidl
Normal file
33
components/script_bindings/webidls/IDBTransaction.webidl
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
/*
|
||||||
|
* The origin of this IDL file is
|
||||||
|
* https://w3c.github.io/IndexedDB/#idbtransaction
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// https://w3c.github.io/IndexedDB/#idbtransaction
|
||||||
|
[Pref="dom_indexeddb_enabled", Exposed=(Window,Worker)]
|
||||||
|
interface IDBTransaction : EventTarget {
|
||||||
|
readonly attribute DOMStringList objectStoreNames;
|
||||||
|
readonly attribute IDBTransactionMode mode;
|
||||||
|
// readonly attribute IDBTransactionDurability durability;
|
||||||
|
[SameObject] readonly attribute IDBDatabase db;
|
||||||
|
readonly attribute DOMException? error;
|
||||||
|
|
||||||
|
[Throws] IDBObjectStore objectStore(DOMString name);
|
||||||
|
[Throws] undefined commit();
|
||||||
|
[Throws] undefined abort();
|
||||||
|
|
||||||
|
// Event handlers:
|
||||||
|
attribute EventHandler onabort;
|
||||||
|
attribute EventHandler oncomplete;
|
||||||
|
attribute EventHandler onerror;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum IDBTransactionMode {
|
||||||
|
"readonly",
|
||||||
|
"readwrite",
|
||||||
|
"versionchange"
|
||||||
|
};
|
|
@ -0,0 +1,25 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
/*
|
||||||
|
* The origin of this IDL file is
|
||||||
|
* https://w3c.github.io/IndexedDB/#idbversionchangeevent
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// FIXME:(arihant2math) Expose to Worker too
|
||||||
|
|
||||||
|
// https://w3c.github.io/IndexedDB/#idbversionchangeevent
|
||||||
|
[Pref="dom_indexeddb_enabled", Exposed=(Window)]
|
||||||
|
interface IDBVersionChangeEvent : Event {
|
||||||
|
constructor(DOMString type, optional IDBVersionChangeEventInit eventInitDict = {});
|
||||||
|
|
||||||
|
readonly attribute unsigned long long oldVersion;
|
||||||
|
readonly attribute unsigned long long? newVersion;
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://w3c.github.io/IndexedDB/#idbversionchangeevent
|
||||||
|
dictionary IDBVersionChangeEventInit : EventInit {
|
||||||
|
unsigned long long oldVersion = 0;
|
||||||
|
unsigned long long? newVersion = null;
|
||||||
|
};
|
|
@ -18,6 +18,7 @@ use serde::{Deserialize, Serialize};
|
||||||
pub enum ScriptHangAnnotation {
|
pub enum ScriptHangAnnotation {
|
||||||
AttachLayout,
|
AttachLayout,
|
||||||
ConstellationMsg,
|
ConstellationMsg,
|
||||||
|
DatabaseAccessEvent,
|
||||||
DevtoolsMsg,
|
DevtoolsMsg,
|
||||||
DocumentEvent,
|
DocumentEvent,
|
||||||
FileRead,
|
FileRead,
|
||||||
|
|
173
components/shared/net/indexeddb_thread.rs
Normal file
173
components/shared/net/indexeddb_thread.rs
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use ipc_channel::ipc::IpcSender;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use servo_url::origin::ImmutableOrigin;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
|
pub enum IndexedDBThreadReturnType {
|
||||||
|
Open(Option<u64>),
|
||||||
|
NextSerialNumber(u64),
|
||||||
|
StartTransaction(Result<(), ()>),
|
||||||
|
Commit(Result<(), ()>),
|
||||||
|
Version(u64),
|
||||||
|
CreateObjectStore(Option<String>),
|
||||||
|
UpgradeVersion(Result<u64, ()>),
|
||||||
|
KVResult(Option<Vec<u8>>),
|
||||||
|
Exit,
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#enumdef-idbtransactionmode
|
||||||
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
|
pub enum IndexedDBTxnMode {
|
||||||
|
Readonly,
|
||||||
|
Readwrite,
|
||||||
|
Versionchange,
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#key-type
|
||||||
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
|
pub enum IndexedDBKeyType {
|
||||||
|
Number(Vec<u8>),
|
||||||
|
String(Vec<u8>),
|
||||||
|
Binary(Vec<u8>),
|
||||||
|
Date(Vec<u8>),
|
||||||
|
// FIXME:(arihant2math) implment Array(),
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#key-range
|
||||||
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
|
#[allow(unused)]
|
||||||
|
pub enum IndexedDBKeyRange {}
|
||||||
|
|
||||||
|
// Operations that are not executed instantly, but rather added to a
|
||||||
|
// queue that is eventually run.
|
||||||
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
|
pub enum AsyncOperation {
|
||||||
|
/// Gets the value associated with the given key in the associated idb data
|
||||||
|
GetItem(
|
||||||
|
IndexedDBKeyType, // Key
|
||||||
|
),
|
||||||
|
|
||||||
|
/// Sets the value of the given key in the associated idb data
|
||||||
|
PutItem(
|
||||||
|
IndexedDBKeyType, // Key
|
||||||
|
Vec<u8>, // Value
|
||||||
|
bool, // Should overwrite
|
||||||
|
),
|
||||||
|
|
||||||
|
/// Removes the key/value pair for the given key in the associated idb data
|
||||||
|
RemoveItem(
|
||||||
|
IndexedDBKeyType, // Key
|
||||||
|
),
|
||||||
|
|
||||||
|
Count(
|
||||||
|
IndexedDBKeyType, // Key
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
|
pub enum SyncOperation {
|
||||||
|
// Upgrades the version of the database
|
||||||
|
UpgradeVersion(
|
||||||
|
IpcSender<IndexedDBThreadReturnType>,
|
||||||
|
ImmutableOrigin,
|
||||||
|
String, // Database
|
||||||
|
u64, // Serial number for the transaction
|
||||||
|
u64, // Version to upgrade to
|
||||||
|
),
|
||||||
|
// Checks if an object store has a key generator, used in e.g. Put
|
||||||
|
HasKeyGenerator(
|
||||||
|
IpcSender<bool>,
|
||||||
|
ImmutableOrigin,
|
||||||
|
String, // Database
|
||||||
|
String, // Store
|
||||||
|
),
|
||||||
|
|
||||||
|
// Commits changes of a transaction to the database
|
||||||
|
Commit(
|
||||||
|
IpcSender<IndexedDBThreadReturnType>,
|
||||||
|
ImmutableOrigin,
|
||||||
|
String, // Database
|
||||||
|
u64, // Transaction serial number
|
||||||
|
),
|
||||||
|
|
||||||
|
// Creates a new store for the database
|
||||||
|
CreateObjectStore(
|
||||||
|
IpcSender<Result<(), ()>>,
|
||||||
|
ImmutableOrigin,
|
||||||
|
String, // Database
|
||||||
|
String, // Store
|
||||||
|
bool,
|
||||||
|
),
|
||||||
|
|
||||||
|
DeleteObjectStore(
|
||||||
|
IpcSender<Result<(), ()>>,
|
||||||
|
ImmutableOrigin,
|
||||||
|
String, // Database
|
||||||
|
String, // Store
|
||||||
|
),
|
||||||
|
|
||||||
|
CloseDatabase(
|
||||||
|
IpcSender<Result<(), ()>>,
|
||||||
|
ImmutableOrigin,
|
||||||
|
String, // Database
|
||||||
|
),
|
||||||
|
|
||||||
|
OpenDatabase(
|
||||||
|
IpcSender<u64>, // Returns the version
|
||||||
|
ImmutableOrigin,
|
||||||
|
String, // Database
|
||||||
|
Option<u64>, // Eventual version
|
||||||
|
),
|
||||||
|
|
||||||
|
// Deletes the database
|
||||||
|
DeleteDatabase(
|
||||||
|
IpcSender<Result<(), ()>>,
|
||||||
|
ImmutableOrigin,
|
||||||
|
String, // Database
|
||||||
|
),
|
||||||
|
|
||||||
|
// Returns an unique identifier that is used to be able to
|
||||||
|
// commit/abort transactions.
|
||||||
|
RegisterNewTxn(
|
||||||
|
IpcSender<u64>,
|
||||||
|
ImmutableOrigin,
|
||||||
|
String, // Database
|
||||||
|
),
|
||||||
|
|
||||||
|
// Starts executing the requests of a transaction
|
||||||
|
// https://www.w3.org/TR/IndexedDB-2/#transaction-start
|
||||||
|
StartTransaction(
|
||||||
|
IpcSender<Result<(), ()>>,
|
||||||
|
ImmutableOrigin,
|
||||||
|
String, // Database
|
||||||
|
u64, // The serial number of the mutating transaction
|
||||||
|
),
|
||||||
|
|
||||||
|
// Returns the version of the database
|
||||||
|
Version(
|
||||||
|
IpcSender<u64>,
|
||||||
|
ImmutableOrigin,
|
||||||
|
String, // Database
|
||||||
|
),
|
||||||
|
|
||||||
|
/// Send a reply when done cleaning up thread resources and then shut it down
|
||||||
|
Exit(IpcSender<IndexedDBThreadReturnType>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
|
pub enum IndexedDBThreadMsg {
|
||||||
|
Sync(SyncOperation),
|
||||||
|
Async(
|
||||||
|
IpcSender<Option<Vec<u8>>>, // Sender to send the result of the async operation
|
||||||
|
ImmutableOrigin,
|
||||||
|
String, // Database
|
||||||
|
String, // ObjectStore
|
||||||
|
u64, // Serial number of the transaction that requests this operation
|
||||||
|
IndexedDBTxnMode,
|
||||||
|
AsyncOperation,
|
||||||
|
),
|
||||||
|
}
|
|
@ -32,6 +32,7 @@ use servo_url::{ImmutableOrigin, ServoUrl};
|
||||||
|
|
||||||
use crate::filemanager_thread::FileManagerThreadMsg;
|
use crate::filemanager_thread::FileManagerThreadMsg;
|
||||||
use crate::http_status::HttpStatus;
|
use crate::http_status::HttpStatus;
|
||||||
|
use crate::indexeddb_thread::IndexedDBThreadMsg;
|
||||||
use crate::request::{Request, RequestBuilder};
|
use crate::request::{Request, RequestBuilder};
|
||||||
use crate::response::{HttpsState, Response, ResponseInit};
|
use crate::response::{HttpsState, Response, ResponseInit};
|
||||||
use crate::storage_thread::StorageThreadMsg;
|
use crate::storage_thread::StorageThreadMsg;
|
||||||
|
@ -40,6 +41,7 @@ pub mod blob_url_store;
|
||||||
pub mod filemanager_thread;
|
pub mod filemanager_thread;
|
||||||
pub mod http_status;
|
pub mod http_status;
|
||||||
pub mod image_cache;
|
pub mod image_cache;
|
||||||
|
pub mod indexeddb_thread;
|
||||||
pub mod mime_classifier;
|
pub mod mime_classifier;
|
||||||
pub mod policy_container;
|
pub mod policy_container;
|
||||||
pub mod pub_domains;
|
pub mod pub_domains;
|
||||||
|
@ -414,13 +416,19 @@ where
|
||||||
pub struct ResourceThreads {
|
pub struct ResourceThreads {
|
||||||
pub core_thread: CoreResourceThread,
|
pub core_thread: CoreResourceThread,
|
||||||
storage_thread: IpcSender<StorageThreadMsg>,
|
storage_thread: IpcSender<StorageThreadMsg>,
|
||||||
|
idb_thread: IpcSender<IndexedDBThreadMsg>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ResourceThreads {
|
impl ResourceThreads {
|
||||||
pub fn new(c: CoreResourceThread, s: IpcSender<StorageThreadMsg>) -> ResourceThreads {
|
pub fn new(
|
||||||
|
c: CoreResourceThread,
|
||||||
|
s: IpcSender<StorageThreadMsg>,
|
||||||
|
i: IpcSender<IndexedDBThreadMsg>,
|
||||||
|
) -> ResourceThreads {
|
||||||
ResourceThreads {
|
ResourceThreads {
|
||||||
core_thread: c,
|
core_thread: c,
|
||||||
storage_thread: s,
|
storage_thread: s,
|
||||||
|
idb_thread: i,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -439,6 +447,16 @@ impl IpcSend<CoreResourceMsg> for ResourceThreads {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl IpcSend<IndexedDBThreadMsg> for ResourceThreads {
|
||||||
|
fn send(&self, msg: IndexedDBThreadMsg) -> IpcSendResult {
|
||||||
|
self.idb_thread.send(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sender(&self) -> IpcSender<IndexedDBThreadMsg> {
|
||||||
|
self.idb_thread.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl IpcSend<StorageThreadMsg> for ResourceThreads {
|
impl IpcSend<StorageThreadMsg> for ResourceThreads {
|
||||||
fn send(&self, msg: StorageThreadMsg) -> IpcSendResult {
|
fn send(&self, msg: StorageThreadMsg) -> IpcSendResult {
|
||||||
self.storage_thread.send(msg)
|
self.storage_thread.send(msg)
|
||||||
|
|
|
@ -111,6 +111,8 @@ pub enum ProfilerCategory {
|
||||||
ScriptPortMessage = 0x7e,
|
ScriptPortMessage = 0x7e,
|
||||||
ScriptWebGPUMsg = 0x7f,
|
ScriptWebGPUMsg = 0x7f,
|
||||||
|
|
||||||
|
ScriptDatabaseAccessEvent = 0x80,
|
||||||
|
|
||||||
/// Web performance metrics.
|
/// Web performance metrics.
|
||||||
TimeToFirstPaint = 0x90,
|
TimeToFirstPaint = 0x90,
|
||||||
TimeToFirstContentfulPaint = 0x91,
|
TimeToFirstContentfulPaint = 0x91,
|
||||||
|
@ -128,6 +130,7 @@ impl ProfilerCategory {
|
||||||
ProfilerCategory::ImageSaving => "ImageSaving",
|
ProfilerCategory::ImageSaving => "ImageSaving",
|
||||||
ProfilerCategory::ScriptAttachLayout => "ScriptAttachLayout",
|
ProfilerCategory::ScriptAttachLayout => "ScriptAttachLayout",
|
||||||
ProfilerCategory::ScriptConstellationMsg => "ScriptConstellationMsg",
|
ProfilerCategory::ScriptConstellationMsg => "ScriptConstellationMsg",
|
||||||
|
ProfilerCategory::ScriptDatabaseAccessEvent => "ScriptDatabaseAccessEvent",
|
||||||
ProfilerCategory::ScriptDevtoolsMsg => "ScriptDevtoolsMsg",
|
ProfilerCategory::ScriptDevtoolsMsg => "ScriptDevtoolsMsg",
|
||||||
ProfilerCategory::ScriptDocumentEvent => "ScriptDocumentEvent",
|
ProfilerCategory::ScriptDocumentEvent => "ScriptDocumentEvent",
|
||||||
ProfilerCategory::ScriptEvaluate => "ScriptEvaluate",
|
ProfilerCategory::ScriptEvaluate => "ScriptEvaluate",
|
||||||
|
|
|
@ -380,6 +380,7 @@ class OpenHarmonyTarget(CrossBuildTarget):
|
||||||
env["HOST_CXXFLAGS"] = ""
|
env["HOST_CXXFLAGS"] = ""
|
||||||
ohos_cflags = [
|
ohos_cflags = [
|
||||||
"-D__MUSL__",
|
"-D__MUSL__",
|
||||||
|
"-DMDB_USE_ROBUST=0",
|
||||||
f" --target={clang_target_triple}",
|
f" --target={clang_target_triple}",
|
||||||
f" --sysroot={ohos_sysroot_posix}",
|
f" --sysroot={ohos_sysroot_posix}",
|
||||||
"-Wno-error=unused-command-line-argument",
|
"-Wno-error=unused-command-line-argument",
|
||||||
|
|
2
tests/wpt/include.ini
vendored
2
tests/wpt/include.ini
vendored
|
@ -178,6 +178,8 @@ skip: true
|
||||||
skip: true
|
skip: true
|
||||||
[import-maps]
|
[import-maps]
|
||||||
skip: false
|
skip: false
|
||||||
|
[indexeddb]
|
||||||
|
skip: false
|
||||||
[intersection-observer]
|
[intersection-observer]
|
||||||
skip: false
|
skip: false
|
||||||
[js]
|
[js]
|
||||||
|
|
1
tests/wpt/meta/indexeddb/__dir__.ini
vendored
Normal file
1
tests/wpt/meta/indexeddb/__dir__.ini
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
prefs: ["dom_indexeddb_enabled:true"]
|
15
tests/wpt/meta/indexeddb/abort-in-initial-upgradeneeded.any.js.ini
vendored
Normal file
15
tests/wpt/meta/indexeddb/abort-in-initial-upgradeneeded.any.js.ini
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
[abort-in-initial-upgradeneeded.any.html]
|
||||||
|
[An abort() in the initial onupgradeneeded sets version back to 0]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[abort-in-initial-upgradeneeded.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[abort-in-initial-upgradeneeded.any.worker.html]
|
||||||
|
[An abort() in the initial onupgradeneeded sets version back to 0]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[abort-in-initial-upgradeneeded.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
3
tests/wpt/meta/indexeddb/back-forward-cache-open-connection.window.js.ini
vendored
Normal file
3
tests/wpt/meta/indexeddb/back-forward-cache-open-connection.window.js.ini
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
[back-forward-cache-open-connection.window.html]
|
||||||
|
[Testing BFCache support for page with open IndexedDB connection, and eviction behavior when receiving versionchange event.]
|
||||||
|
expected: FAIL
|
4
tests/wpt/meta/indexeddb/back-forward-cache-open-transaction.window.js.ini
vendored
Normal file
4
tests/wpt/meta/indexeddb/back-forward-cache-open-transaction.window.js.ini
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
[back-forward-cache-open-transaction.window.html]
|
||||||
|
expected: TIMEOUT
|
||||||
|
[BFCache support test for page with open IndexedDB transaction]
|
||||||
|
expected: TIMEOUT
|
14
tests/wpt/meta/indexeddb/bindings-inject-keys-bypass.any.js.ini
vendored
Normal file
14
tests/wpt/meta/indexeddb/bindings-inject-keys-bypass.any.js.ini
vendored
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
[bindings-inject-keys-bypass.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[bindings-inject-keys-bypass.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[bindings-inject-keys-bypass.any.worker.html]
|
||||||
|
[Returning keys to script should bypass prototype setters]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[bindings-inject-keys-bypass.any.html]
|
||||||
|
[Returning keys to script should bypass prototype setters]
|
||||||
|
expected: FAIL
|
21
tests/wpt/meta/indexeddb/bindings-inject-values-bypass.any.js.ini
vendored
Normal file
21
tests/wpt/meta/indexeddb/bindings-inject-values-bypass.any.js.ini
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
[bindings-inject-values-bypass.any.html]
|
||||||
|
[Returning values to script should bypass prototype chain]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Returning values to script should bypass prototype setters]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[bindings-inject-values-bypass.any.worker.html]
|
||||||
|
[Returning values to script should bypass prototype chain]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Returning values to script should bypass prototype setters]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[bindings-inject-values-bypass.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[bindings-inject-values-bypass.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
14
tests/wpt/meta/indexeddb/blob-composite-blob-reads.any.js.ini
vendored
Normal file
14
tests/wpt/meta/indexeddb/blob-composite-blob-reads.any.js.ini
vendored
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
[blob-composite-blob-reads.any.html]
|
||||||
|
[Composite Blob Handling: Many blobs: fetch-blob-url]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Composite Blob Handling: Many blobs: direct]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[blob-composite-blob-reads.any.worker.html]
|
||||||
|
[Composite Blob Handling: Many blobs: fetch-blob-url]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Composite Blob Handling: Many blobs: direct]
|
||||||
|
expected: FAIL
|
9
tests/wpt/meta/indexeddb/blob-contenttype.any.js.ini
vendored
Normal file
9
tests/wpt/meta/indexeddb/blob-contenttype.any.js.ini
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
[blob-contenttype.any.html]
|
||||||
|
[Ensure that content type round trips when reading blob data]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[blob-contenttype.any.worker.html]
|
||||||
|
[Ensure that content type round trips when reading blob data]
|
||||||
|
expected: FAIL
|
||||||
|
|
9
tests/wpt/meta/indexeddb/blob-delete-objectstore-db.any.js.ini
vendored
Normal file
9
tests/wpt/meta/indexeddb/blob-delete-objectstore-db.any.js.ini
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
[blob-delete-objectstore-db.any.worker.html]
|
||||||
|
[Deleting an object store and a database containing blobs doesn't crash.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[blob-delete-objectstore-db.any.html]
|
||||||
|
[Deleting an object store and a database containing blobs doesn't crash.]
|
||||||
|
expected: FAIL
|
||||||
|
|
9
tests/wpt/meta/indexeddb/blob-valid-after-deletion.any.js.ini
vendored
Normal file
9
tests/wpt/meta/indexeddb/blob-valid-after-deletion.any.js.ini
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
[blob-valid-after-deletion.any.worker.html]
|
||||||
|
[Blobs stay alive after their records are deleted.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[blob-valid-after-deletion.any.html]
|
||||||
|
[Blobs stay alive after their records are deleted.]
|
||||||
|
expected: FAIL
|
||||||
|
|
9
tests/wpt/meta/indexeddb/blob-valid-before-commit.any.js.ini
vendored
Normal file
9
tests/wpt/meta/indexeddb/blob-valid-before-commit.any.js.ini
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
[blob-valid-before-commit.any.worker.html]
|
||||||
|
[Blobs can be read back before their records are committed.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[blob-valid-before-commit.any.html]
|
||||||
|
[Blobs can be read back before their records are committed.]
|
||||||
|
expected: FAIL
|
||||||
|
|
39
tests/wpt/meta/indexeddb/clone-before-keypath-eval.any.js.ini
vendored
Normal file
39
tests/wpt/meta/indexeddb/clone-before-keypath-eval.any.js.ini
vendored
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
[clone-before-keypath-eval.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[clone-before-keypath-eval.any.html]
|
||||||
|
[Key generator and key path validity check operates on a clone]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Failing key path validity check operates on a clone]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Index key path evaluations operate on a clone]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Store and index key path evaluations operate on the same clone]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Cursor update checks and keypath evaluations operate on a clone]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[clone-before-keypath-eval.any.worker.html]
|
||||||
|
[Key generator and key path validity check operates on a clone]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Failing key path validity check operates on a clone]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Index key path evaluations operate on a clone]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Store and index key path evaluations operate on the same clone]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Cursor update checks and keypath evaluations operate on a clone]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[clone-before-keypath-eval.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
13
tests/wpt/meta/indexeddb/close-in-upgradeneeded.any.js.ini
vendored
Normal file
13
tests/wpt/meta/indexeddb/close-in-upgradeneeded.any.js.ini
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
[close-in-upgradeneeded.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[close-in-upgradeneeded.any.html]
|
||||||
|
[When db.close() is called in onupgradeneeded, the db is cleaned up on refresh]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[close-in-upgradeneeded.any.worker.html]
|
||||||
|
expected: CRASH
|
||||||
|
|
||||||
|
[close-in-upgradeneeded.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
13
tests/wpt/meta/indexeddb/cursor-overloads.any.js.ini
vendored
Normal file
13
tests/wpt/meta/indexeddb/cursor-overloads.any.js.ini
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
[cursor-overloads.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[cursor-overloads.any.html]
|
||||||
|
[Validate the overloads of IDBObjectStore.openCursor(), IDBIndex.openCursor() and IDBIndex.openKeyCursor()]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[cursor-overloads.any.worker.html]
|
||||||
|
expected: CRASH
|
||||||
|
|
||||||
|
[cursor-overloads.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
13
tests/wpt/meta/indexeddb/database-names-by-origin.html.ini
vendored
Normal file
13
tests/wpt/meta/indexeddb/database-names-by-origin.html.ini
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
[database-names-by-origin.html]
|
||||||
|
expected: TIMEOUT
|
||||||
|
[open database names don't leak to cross-origin iframe]
|
||||||
|
expected: TIMEOUT
|
||||||
|
|
||||||
|
[open database names don't leak to cross-origin window]
|
||||||
|
expected: NOTRUN
|
||||||
|
|
||||||
|
[closed database names don't leak to cross-origin iframe]
|
||||||
|
expected: NOTRUN
|
||||||
|
|
||||||
|
[closed database names don't leak to cross-origin window]
|
||||||
|
expected: NOTRUN
|
26
tests/wpt/meta/indexeddb/delete-range.any.js.ini
vendored
Normal file
26
tests/wpt/meta/indexeddb/delete-range.any.js.ini
vendored
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
[delete-range.any.worker.html]
|
||||||
|
[Delete range]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Delete range 1]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Delete range 2]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Delete range 3]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[delete-range.any.html]
|
||||||
|
[Delete range]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Delete range 1]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Delete range 2]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Delete range 3]
|
||||||
|
expected: FAIL
|
15
tests/wpt/meta/indexeddb/delete-request-queue.any.js.ini
vendored
Normal file
15
tests/wpt/meta/indexeddb/delete-request-queue.any.js.ini
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
[delete-request-queue.any.worker.html]
|
||||||
|
[Deletes are processed as a FIFO queue]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[delete-request-queue.any.html]
|
||||||
|
[Deletes are processed as a FIFO queue]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[delete-request-queue.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[delete-request-queue.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
14
tests/wpt/meta/indexeddb/error-attributes.any.js.ini
vendored
Normal file
14
tests/wpt/meta/indexeddb/error-attributes.any.js.ini
vendored
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
[error-attributes.any.worker.html]
|
||||||
|
[IDBRequest and IDBTransaction error properties should be DOMExceptions]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[error-attributes.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[error-attributes.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[error-attributes.any.html]
|
||||||
|
[IDBRequest and IDBTransaction error properties should be DOMExceptions]
|
||||||
|
expected: FAIL
|
33
tests/wpt/meta/indexeddb/event-dispatch-active-flag.any.js.ini
vendored
Normal file
33
tests/wpt/meta/indexeddb/event-dispatch-active-flag.any.js.ini
vendored
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
[event-dispatch-active-flag.any.html]
|
||||||
|
[Active during success handlers]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Active during success listeners]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Active during error handlers]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Active during error listeners]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[event-dispatch-active-flag.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[event-dispatch-active-flag.any.worker.html]
|
||||||
|
[Active during success handlers]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Active during success listeners]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Active during error handlers]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Active during error listeners]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[event-dispatch-active-flag.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
111
tests/wpt/meta/indexeddb/fire-error-event-exception.any.js.ini
vendored
Normal file
111
tests/wpt/meta/indexeddb/fire-error-event-exception.any.js.ini
vendored
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
[fire-error-event-exception.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[fire-error-event-exception.any.worker.html]
|
||||||
|
[Exception in error event handler on request]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in error event handler on request, with preventDefault]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in error event listener on request]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in error event listener ("handleEvent" lookup) on request]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in error event listener (non-callable "handleEvent") on request]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in second error event listener on request]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in first error event listener on request, transaction active in second]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in error event handler on transaction]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in error event handler on transaction, with preventDefault]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in error event listener on transaction]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in second error event listener on transaction]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in first error event listener on transaction, transaction active in second]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in error event handler on connection]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in error event handler on connection, with preventDefault]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in error event listener on connection]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in second error event listener on connection]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in first error event listener on connection, transaction active in second]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[fire-error-event-exception.any.html]
|
||||||
|
[Exception in error event handler on request]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in error event handler on request, with preventDefault]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in error event listener on request]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in error event listener ("handleEvent" lookup) on request]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in error event listener (non-callable "handleEvent") on request]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in second error event listener on request]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in first error event listener on request, transaction active in second]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in error event handler on transaction]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in error event handler on transaction, with preventDefault]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in error event listener on transaction]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in second error event listener on transaction]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in first error event listener on transaction, transaction active in second]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in error event handler on connection]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in error event handler on connection, with preventDefault]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in error event listener on connection]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in second error event listener on connection]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in first error event listener on connection, transaction active in second]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[fire-error-event-exception.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
45
tests/wpt/meta/indexeddb/fire-success-event-exception.any.js.ini
vendored
Normal file
45
tests/wpt/meta/indexeddb/fire-success-event-exception.any.js.ini
vendored
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
[fire-success-event-exception.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[fire-success-event-exception.any.worker.html]
|
||||||
|
[Exception in success event handler on request]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in success event listener on request]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in success event listener ("handleEvent" lookup) on request]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in success event listener (non-callable "handleEvent") on request]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in second success event listener on request]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in first success event listener, tx active in second]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[fire-success-event-exception.any.html]
|
||||||
|
[Exception in success event handler on request]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in success event listener on request]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in success event listener ("handleEvent" lookup) on request]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in success event listener (non-callable "handleEvent") on request]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in second success event listener on request]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in first success event listener, tx active in second]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[fire-success-event-exception.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
44
tests/wpt/meta/indexeddb/fire-upgradeneeded-event-exception.any.js.ini
vendored
Normal file
44
tests/wpt/meta/indexeddb/fire-upgradeneeded-event-exception.any.js.ini
vendored
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
[fire-upgradeneeded-event-exception.any.html]
|
||||||
|
[Exception in upgradeneeded handler]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in upgradeneeded listener]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in upgradeneeded "handleEvent" lookup]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in upgradeneeded due to non-callable "handleEvent"]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in second upgradeneeded listener]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in first upgradeneeded listener, tx active in second]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[fire-upgradeneeded-event-exception.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[fire-upgradeneeded-event-exception.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[fire-upgradeneeded-event-exception.any.worker.html]
|
||||||
|
[Exception in upgradeneeded handler]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in upgradeneeded listener]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in upgradeneeded "handleEvent" lookup]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in upgradeneeded due to non-callable "handleEvent"]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in second upgradeneeded listener]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Exception in first upgradeneeded listener, tx active in second]
|
||||||
|
expected: FAIL
|
32
tests/wpt/meta/indexeddb/get-databases.any.js.ini
vendored
Normal file
32
tests/wpt/meta/indexeddb/get-databases.any.js.ini
vendored
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
[get-databases.any.html]
|
||||||
|
[Ensure that databases() returns a promise.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Enumerate one database.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Enumerate multiple databases.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Make sure an empty list is returned for the case of no databases.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Ensure that databases() doesn't pick up changes that haven't commited.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[get-databases.any.worker.html]
|
||||||
|
[Ensure that databases() returns a promise.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Enumerate one database.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Enumerate multiple databases.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Make sure an empty list is returned for the case of no databases.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Ensure that databases() doesn't pick up changes that haven't commited.]
|
||||||
|
expected: FAIL
|
9
tests/wpt/meta/indexeddb/globalscope-indexedDB-SameObject.any.js.ini
vendored
Normal file
9
tests/wpt/meta/indexeddb/globalscope-indexedDB-SameObject.any.js.ini
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
[globalscope-indexedDB-SameObject.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[globalscope-indexedDB-SameObject.any.html]
|
||||||
|
|
||||||
|
[globalscope-indexedDB-SameObject.any.worker.html]
|
||||||
|
|
||||||
|
[globalscope-indexedDB-SameObject.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
36
tests/wpt/meta/indexeddb/historical.any.js.ini
vendored
Normal file
36
tests/wpt/meta/indexeddb/historical.any.js.ini
vendored
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
[historical.any.worker.html]
|
||||||
|
["version" should not be supported on IDBVersionChangeEvent.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
["NEXT" should not be supported on IDBCursor.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
["NEXT_NO_DUPLICATE" should not be supported on IDBCursor.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
["PREV" should not be supported on IDBCursor.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
["PREV_NO_DUPLICATE" should not be supported on IDBCursor.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[historical.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[historical.any.html]
|
||||||
|
["NEXT" should not be supported on IDBCursor.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
["NEXT_NO_DUPLICATE" should not be supported on IDBCursor.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
["PREV" should not be supported on IDBCursor.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
["PREV_NO_DUPLICATE" should not be supported on IDBCursor.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[historical.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
12
tests/wpt/meta/indexeddb/idb-binary-key-detached.htm.ini
vendored
Normal file
12
tests/wpt/meta/indexeddb/idb-binary-key-detached.htm.ini
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
[idb-binary-key-detached.htm]
|
||||||
|
[Detached TypedArray]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Detached ArrayBuffer]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Detached ArrayBuffers must throw DataError when used as a key]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Detached TypedArrays must throw DataError when used as a key]
|
||||||
|
expected: FAIL
|
104
tests/wpt/meta/indexeddb/idb-binary-key-roundtrip.any.js.ini
vendored
Normal file
104
tests/wpt/meta/indexeddb/idb-binary-key-roundtrip.any.js.ini
vendored
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
[idb-binary-key-roundtrip.any.worker.html]
|
||||||
|
[Binary keys can be supplied using the view type Uint8Array]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Binary keys can be supplied using the view type Uint8ClampedArray]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Binary keys can be supplied using the view type Int8Array]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Binary keys can be supplied using the view type Uint16Array]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Binary keys can be supplied using the view type Int16Array]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Binary keys can be supplied using the view type Uint32Array]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Binary keys can be supplied using the view type Int32Array]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Binary keys can be supplied using the view type Float16Array]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Binary keys can be supplied using the view type Float32Array]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Binary keys can be supplied using the view type Float64Array]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[ArrayBuffer can be used to supply a binary key]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[DataView can be used to supply a binary key]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[DataView with explicit offset can be used to supply a binary key]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[DataView with explicit offset and length can be used to supply a binary key]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Uint8Array with explicit offset can be used to supply a binary key]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Uint8Array with explicit offset and length can be used to supply a binary key]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[idb-binary-key-roundtrip.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idb-binary-key-roundtrip.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idb-binary-key-roundtrip.any.html]
|
||||||
|
[Binary keys can be supplied using the view type Uint8Array]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Binary keys can be supplied using the view type Uint8ClampedArray]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Binary keys can be supplied using the view type Int8Array]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Binary keys can be supplied using the view type Uint16Array]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Binary keys can be supplied using the view type Int16Array]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Binary keys can be supplied using the view type Uint32Array]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Binary keys can be supplied using the view type Int32Array]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Binary keys can be supplied using the view type Float16Array]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Binary keys can be supplied using the view type Float32Array]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Binary keys can be supplied using the view type Float64Array]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[ArrayBuffer can be used to supply a binary key]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[DataView can be used to supply a binary key]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[DataView with explicit offset can be used to supply a binary key]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[DataView with explicit offset and length can be used to supply a binary key]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Uint8Array with explicit offset can be used to supply a binary key]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Uint8Array with explicit offset and length can be used to supply a binary key]
|
||||||
|
expected: FAIL
|
9
tests/wpt/meta/indexeddb/idb-explicit-commit-throw.any.js.ini
vendored
Normal file
9
tests/wpt/meta/indexeddb/idb-explicit-commit-throw.any.js.ini
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
[idb-explicit-commit-throw.any.worker.html]
|
||||||
|
[Any errors in callbacks that run after an explicit commit will not stop the commit from being processed.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[idb-explicit-commit-throw.any.html]
|
||||||
|
[Any errors in callbacks that run after an explicit commit will not stop the commit from being processed.]
|
||||||
|
expected: FAIL
|
||||||
|
|
75
tests/wpt/meta/indexeddb/idb-explicit-commit.any.js.ini
vendored
Normal file
75
tests/wpt/meta/indexeddb/idb-explicit-commit.any.js.ini
vendored
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
[idb-explicit-commit.any.worker.html]
|
||||||
|
[commit() on a version change transaction does not cause errors.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Puts issued after commit are not fulfilled.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Explicitly committed data can be read back out.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Calling abort on a committed transaction throws and does not prevent persisting the data.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Calling commit on a committed transaction throws.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Transactions that explicitly commit and have errors should abort.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[A committed transaction becomes inactive immediately.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Transactions with same scope should stay in program order, even if one calls commit.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Calling commit on an aborted transaction throws.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Calling txn.commit() when txn is inactive should throw.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Transactions that handle all errors properly should behave as expected when an explicit commit is called in an onerror handler.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[A committed transaction is inactive in future request callbacks.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[idb-explicit-commit.any.html]
|
||||||
|
[commit() on a version change transaction does not cause errors.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Puts issued after commit are not fulfilled.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Explicitly committed data can be read back out.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Calling abort on a committed transaction throws and does not prevent persisting the data.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Calling commit on a committed transaction throws.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Transactions that explicitly commit and have errors should abort.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[A committed transaction becomes inactive immediately.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Transactions with same scope should stay in program order, even if one calls commit.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Calling commit on an aborted transaction throws.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Calling txn.commit() when txn is inactive should throw.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Transactions that handle all errors properly should behave as expected when an explicit commit is called in an onerror handler.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[A committed transaction is inactive in future request callbacks.]
|
||||||
|
expected: FAIL
|
||||||
|
|
4
tests/wpt/meta/indexeddb/idb-partitioned-basic.sub.html.ini
vendored
Normal file
4
tests/wpt/meta/indexeddb/idb-partitioned-basic.sub.html.ini
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
[idb-partitioned-basic.sub.html]
|
||||||
|
expected: TIMEOUT
|
||||||
|
[Simple test for partitioned IndexedDB]
|
||||||
|
expected: TIMEOUT
|
49
tests/wpt/meta/indexeddb/idb-partitioned-coverage.sub.html.ini
vendored
Normal file
49
tests/wpt/meta/indexeddb/idb-partitioned-coverage.sub.html.ini
vendored
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
[idb-partitioned-coverage.sub.html]
|
||||||
|
expected: ERROR
|
||||||
|
[Deletes are processed in order]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[ - advance]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[ - continue]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[ - fresh advance still async]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[ - fresh continue still async]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Single item get]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Empty object store]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Get all]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Get all with generated keys]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Get all with large values]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[maxCount=10]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBObjectStore.openKeyCursor() - forward iteration]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBObjectStore.openKeyCursor() - reverse iteration]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBObjectStore.openKeyCursor() - forward iteration with range]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBObjectStore.openKeyCursor() - reverse iteration with range]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBObjectStore.openKeyCursor() - invalid inputs]
|
||||||
|
expected: FAIL
|
4
tests/wpt/meta/indexeddb/idb-partitioned-persistence.sub.html.ini
vendored
Normal file
4
tests/wpt/meta/indexeddb/idb-partitioned-persistence.sub.html.ini
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
[idb-partitioned-persistence.sub.html]
|
||||||
|
expected: TIMEOUT
|
||||||
|
[Persistence test for partitioned IndexedDB]
|
||||||
|
expected: TIMEOUT
|
39
tests/wpt/meta/indexeddb/idb_binary_key_conversion.any.js.ini
vendored
Normal file
39
tests/wpt/meta/indexeddb/idb_binary_key_conversion.any.js.ini
vendored
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
[idb_binary_key_conversion.any.worker.html]
|
||||||
|
[Empty ArrayBuffer]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[ArrayBuffer]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[DataView]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[TypedArray(Int8Array)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Array of TypedArray(Int8Array)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[idb_binary_key_conversion.any.html]
|
||||||
|
[Empty ArrayBuffer]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[ArrayBuffer]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[DataView]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[TypedArray(Int8Array)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Array of TypedArray(Int8Array)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[idb_binary_key_conversion.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idb_binary_key_conversion.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
4
tests/wpt/meta/indexeddb/idb_webworkers.htm.ini
vendored
Normal file
4
tests/wpt/meta/indexeddb/idb_webworkers.htm.ini
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
[idb_webworkers.htm]
|
||||||
|
expected: ERROR
|
||||||
|
[IndexedDB inside of a WebWorker ]
|
||||||
|
expected: TIMEOUT
|
32
tests/wpt/meta/indexeddb/idbcursor-advance-continue-async.any.js.ini
vendored
Normal file
32
tests/wpt/meta/indexeddb/idbcursor-advance-continue-async.any.js.ini
vendored
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
[idbcursor-advance-continue-async.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor-advance-continue-async.any.worker.html]
|
||||||
|
[IDBCursor asyncness - advance]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor asyncness - continue]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor asyncness - fresh advance still async]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor asyncness - fresh continue still async]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[idbcursor-advance-continue-async.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor-advance-continue-async.any.html]
|
||||||
|
[IDBCursor asyncness - advance]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor asyncness - continue]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor asyncness - fresh advance still async]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor asyncness - fresh continue still async]
|
||||||
|
expected: FAIL
|
26
tests/wpt/meta/indexeddb/idbcursor-advance-exception-order.any.js.ini
vendored
Normal file
26
tests/wpt/meta/indexeddb/idbcursor-advance-exception-order.any.js.ini
vendored
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
[idbcursor-advance-exception-order.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor-advance-exception-order.any.worker.html]
|
||||||
|
[IDBCursor.advance exception order: TypeError vs. TransactionInactiveError]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.advance exception order: TransactionInactiveError vs. InvalidStateError #1]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.advance exception order: TransactionInactiveError vs. InvalidStateError #2]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[idbcursor-advance-exception-order.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor-advance-exception-order.any.html]
|
||||||
|
[IDBCursor.advance exception order: TypeError vs. TransactionInactiveError]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.advance exception order: TransactionInactiveError vs. InvalidStateError #1]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.advance exception order: TransactionInactiveError vs. InvalidStateError #2]
|
||||||
|
expected: FAIL
|
45
tests/wpt/meta/indexeddb/idbcursor-advance-invalid.any.js.ini
vendored
Normal file
45
tests/wpt/meta/indexeddb/idbcursor-advance-invalid.any.js.ini
vendored
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
[idbcursor-advance-invalid.any.worker.html]
|
||||||
|
[IDBCursor.advance() - invalid - attempt to call advance twice]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.advance() - invalid - pass something other than number]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.advance() - invalid - pass null/undefined]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.advance() - invalid - missing argument]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.advance() - invalid - pass negative numbers]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.advance() - invalid - got value not set on exception]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[idbcursor-advance-invalid.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor-advance-invalid.any.html]
|
||||||
|
[IDBCursor.advance() - invalid - attempt to call advance twice]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.advance() - invalid - pass something other than number]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.advance() - invalid - pass null/undefined]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.advance() - invalid - missing argument]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.advance() - invalid - pass negative numbers]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.advance() - invalid - got value not set on exception]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[idbcursor-advance-invalid.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
44
tests/wpt/meta/indexeddb/idbcursor-advance.any.js.ini
vendored
Normal file
44
tests/wpt/meta/indexeddb/idbcursor-advance.any.js.ini
vendored
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
[idbcursor-advance.any.html]
|
||||||
|
[IDBCursor.advance() - advances]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.advance() - advances backwards]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.advance() - skip far forward]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.advance() - within range]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.advance() - within single key range]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.advance() - within single key range, with several results]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[idbcursor-advance.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor-advance.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor-advance.any.worker.html]
|
||||||
|
[IDBCursor.advance() - advances]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.advance() - advances backwards]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.advance() - skip far forward]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.advance() - within range]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.advance() - within single key range]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.advance() - within single key range, with several results]
|
||||||
|
expected: FAIL
|
26
tests/wpt/meta/indexeddb/idbcursor-continue-exception-order.any.js.ini
vendored
Normal file
26
tests/wpt/meta/indexeddb/idbcursor-continue-exception-order.any.js.ini
vendored
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
[idbcursor-continue-exception-order.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor-continue-exception-order.any.html]
|
||||||
|
[IDBCursor.continue exception order: TransactionInactiveError vs. DataError]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.continue exception order: TransactionInactiveError vs. InvalidStateError]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.continue exception order: InvalidStateError vs. DataError]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[idbcursor-continue-exception-order.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor-continue-exception-order.any.worker.html]
|
||||||
|
[IDBCursor.continue exception order: TransactionInactiveError vs. DataError]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.continue exception order: TransactionInactiveError vs. InvalidStateError]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.continue exception order: InvalidStateError vs. DataError]
|
||||||
|
expected: FAIL
|
45
tests/wpt/meta/indexeddb/idbcursor-continue.any.js.ini
vendored
Normal file
45
tests/wpt/meta/indexeddb/idbcursor-continue.any.js.ini
vendored
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
[idbcursor-continue.any.worker.html]
|
||||||
|
[IDBCursor.continue() - continues]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.continue() - with given key]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.continue() - skip far forward]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.continue() - within range]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.continue() - within single key range]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.continue() - within single key range, with several results]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[idbcursor-continue.any.html]
|
||||||
|
[IDBCursor.continue() - continues]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.continue() - with given key]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.continue() - skip far forward]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.continue() - within range]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.continue() - within single key range]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.continue() - within single key range, with several results]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[idbcursor-continue.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor-continue.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
86
tests/wpt/meta/indexeddb/idbcursor-continuePrimaryKey-exception-order.any.js.ini
vendored
Normal file
86
tests/wpt/meta/indexeddb/idbcursor-continuePrimaryKey-exception-order.any.js.ini
vendored
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
[idbcursor-continuePrimaryKey-exception-order.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor-continuePrimaryKey-exception-order.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor-continuePrimaryKey-exception-order.any.html]
|
||||||
|
[TransactionInactiveError v.s. InvalidStateError(deleted index)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[InvalidStateError(deleted source) v.s. InvalidAccessError(incorrect source)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[InvalidStateError(deleted source) v.s. InvalidAccessError(incorrect direction)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[InvalidAccessError(incorrect direction) v.s. InvalidStateError(iteration complete)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[InvalidAccessError(incorrect direction) v.s. InvalidStateError(iteration ongoing)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[InvalidAccessError(incorrect source) v.s. InvalidStateError(iteration ongoing)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[InvalidAccessError(incorrect source) v.s. InvalidStateError(iteration complete)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[InvalidStateError(iteration ongoing) v.s. DataError(unset key)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[InvalidStateError(iteration complete) v.s. DataError(unset key)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[DataError(unset key)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[DataError(unset primary key)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[DataError(keys are lower then current one) in 'next' direction]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[DataError(keys are larger then current one) in 'prev' direction]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[idbcursor-continuePrimaryKey-exception-order.any.worker.html]
|
||||||
|
[TransactionInactiveError v.s. InvalidStateError(deleted index)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[InvalidStateError(deleted source) v.s. InvalidAccessError(incorrect source)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[InvalidStateError(deleted source) v.s. InvalidAccessError(incorrect direction)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[InvalidAccessError(incorrect direction) v.s. InvalidStateError(iteration complete)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[InvalidAccessError(incorrect direction) v.s. InvalidStateError(iteration ongoing)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[InvalidAccessError(incorrect source) v.s. InvalidStateError(iteration ongoing)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[InvalidAccessError(incorrect source) v.s. InvalidStateError(iteration complete)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[InvalidStateError(iteration ongoing) v.s. DataError(unset key)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[InvalidStateError(iteration complete) v.s. DataError(unset key)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[DataError(unset key)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[DataError(unset primary key)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[DataError(keys are lower then current one) in 'next' direction]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[DataError(keys are larger then current one) in 'prev' direction]
|
||||||
|
expected: FAIL
|
19
tests/wpt/meta/indexeddb/idbcursor-continuePrimaryKey-exceptions.any.js.ini
vendored
Normal file
19
tests/wpt/meta/indexeddb/idbcursor-continuePrimaryKey-exceptions.any.js.ini
vendored
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
[idbcursor-continuePrimaryKey-exceptions.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor-continuePrimaryKey-exceptions.any.worker.html]
|
||||||
|
expected: CRASH
|
||||||
|
|
||||||
|
[idbcursor-continuePrimaryKey-exceptions.any.html]
|
||||||
|
[IDBCursor continuePrimaryKey() on object store cursor]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor continuePrimaryKey() on "nextunique" cursor]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor continuePrimaryKey() on "prevunique" cursor]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[idbcursor-continuePrimaryKey-exceptions.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
14
tests/wpt/meta/indexeddb/idbcursor-continuePrimaryKey.any.js.ini
vendored
Normal file
14
tests/wpt/meta/indexeddb/idbcursor-continuePrimaryKey.any.js.ini
vendored
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
[idbcursor-continuePrimaryKey.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor-continuePrimaryKey.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor-continuePrimaryKey.any.worker.html]
|
||||||
|
[IndexedDB: IDBCursor method continuePrimaryKey()]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[idbcursor-continuePrimaryKey.any.html]
|
||||||
|
[IndexedDB: IDBCursor method continuePrimaryKey()]
|
||||||
|
expected: FAIL
|
27
tests/wpt/meta/indexeddb/idbcursor-delete-exception-order.any.js.ini
vendored
Normal file
27
tests/wpt/meta/indexeddb/idbcursor-delete-exception-order.any.js.ini
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
[idbcursor-delete-exception-order.any.worker.html]
|
||||||
|
[IDBCursor.delete exception order: TransactionInactiveError vs. ReadOnlyError]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.delete exception order: ReadOnlyError vs. InvalidStateError #1]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.delete exception order: ReadOnlyError vs. InvalidStateError #2]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[idbcursor-delete-exception-order.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor-delete-exception-order.any.html]
|
||||||
|
[IDBCursor.delete exception order: TransactionInactiveError vs. ReadOnlyError]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.delete exception order: ReadOnlyError vs. InvalidStateError #1]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.delete exception order: ReadOnlyError vs. InvalidStateError #2]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[idbcursor-delete-exception-order.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
32
tests/wpt/meta/indexeddb/idbcursor-direction-index-keyrange.any.js.ini
vendored
Normal file
32
tests/wpt/meta/indexeddb/idbcursor-direction-index-keyrange.any.js.ini
vendored
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
[idbcursor-direction-index-keyrange.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor-direction-index-keyrange.any.worker.html]
|
||||||
|
[IDBCursor direction - index with keyrange - next]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor direction - index with keyrange - prev]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor direction - index with keyrange - nextunique]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor direction - index with keyrange - prevunique]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[idbcursor-direction-index-keyrange.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor-direction-index-keyrange.any.html]
|
||||||
|
[IDBCursor direction - index with keyrange - next]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor direction - index with keyrange - prev]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor direction - index with keyrange - nextunique]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor direction - index with keyrange - prevunique]
|
||||||
|
expected: FAIL
|
32
tests/wpt/meta/indexeddb/idbcursor-direction-index.any.js.ini
vendored
Normal file
32
tests/wpt/meta/indexeddb/idbcursor-direction-index.any.js.ini
vendored
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
[idbcursor-direction-index.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor-direction-index.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor-direction-index.any.html]
|
||||||
|
[IDBCursor direction - index - next]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor direction - index - prev]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor direction - index - nextunique]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor direction - index - prevunique]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[idbcursor-direction-index.any.worker.html]
|
||||||
|
[IDBCursor direction - index - next]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor direction - index - prev]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor direction - index - nextunique]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor direction - index - prevunique]
|
||||||
|
expected: FAIL
|
32
tests/wpt/meta/indexeddb/idbcursor-direction-objectstore-keyrange.any.js.ini
vendored
Normal file
32
tests/wpt/meta/indexeddb/idbcursor-direction-objectstore-keyrange.any.js.ini
vendored
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
[idbcursor-direction-objectstore-keyrange.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor-direction-objectstore-keyrange.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor-direction-objectstore-keyrange.any.worker.html]
|
||||||
|
[IDBCursor direction - object store with keyrange - next]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor direction - object store with keyrange - prev]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor direction - object store with keyrange - nextunique]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor direction - object store with keyrange - prevunique]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[idbcursor-direction-objectstore-keyrange.any.html]
|
||||||
|
[IDBCursor direction - object store with keyrange - next]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor direction - object store with keyrange - prev]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor direction - object store with keyrange - nextunique]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor direction - object store with keyrange - prevunique]
|
||||||
|
expected: FAIL
|
32
tests/wpt/meta/indexeddb/idbcursor-direction-objectstore.any.js.ini
vendored
Normal file
32
tests/wpt/meta/indexeddb/idbcursor-direction-objectstore.any.js.ini
vendored
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
[idbcursor-direction-objectstore.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor-direction-objectstore.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor-direction-objectstore.any.html]
|
||||||
|
[IDBCursor direction - object store - next]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor direction - object store - prev]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor direction - object store - nextunique]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor direction - object store - prevunique]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[idbcursor-direction-objectstore.any.worker.html]
|
||||||
|
[IDBCursor direction - object store - next]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor direction - object store - prev]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor direction - object store - nextunique]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor direction - object store - prevunique]
|
||||||
|
expected: FAIL
|
26
tests/wpt/meta/indexeddb/idbcursor-direction.any.js.ini
vendored
Normal file
26
tests/wpt/meta/indexeddb/idbcursor-direction.any.js.ini
vendored
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
[idbcursor-direction.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor-direction.any.worker.html]
|
||||||
|
expected: CRASH
|
||||||
|
|
||||||
|
[idbcursor-direction.any.html]
|
||||||
|
expected: ERROR
|
||||||
|
[IDBCursor.direction - undefined]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.direction - next]
|
||||||
|
expected: NOTRUN
|
||||||
|
|
||||||
|
[IDBCursor.direction - prev]
|
||||||
|
expected: NOTRUN
|
||||||
|
|
||||||
|
[IDBCursor.direction - nextunique]
|
||||||
|
expected: NOTRUN
|
||||||
|
|
||||||
|
[IDBCursor.direction - prevunique]
|
||||||
|
expected: NOTRUN
|
||||||
|
|
||||||
|
|
||||||
|
[idbcursor-direction.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
20
tests/wpt/meta/indexeddb/idbcursor-iterating-update.any.js.ini
vendored
Normal file
20
tests/wpt/meta/indexeddb/idbcursor-iterating-update.any.js.ini
vendored
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
[idbcursor-iterating-update.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor-iterating-update.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor-iterating-update.any.worker.html]
|
||||||
|
[Calling (cursor) => cursor.update({}) doesn't affect index iteration]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Calling (cursor) => cursor.delete() doesn't affect index iteration]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[idbcursor-iterating-update.any.html]
|
||||||
|
[Calling (cursor) => cursor.update({}) doesn't affect index iteration]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Calling (cursor) => cursor.delete() doesn't affect index iteration]
|
||||||
|
expected: FAIL
|
18
tests/wpt/meta/indexeddb/idbcursor-key.any.js.ini
vendored
Normal file
18
tests/wpt/meta/indexeddb/idbcursor-key.any.js.ini
vendored
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
[idbcursor-key.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor-key.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor-key.any.worker.html]
|
||||||
|
expected: CRASH
|
||||||
|
|
||||||
|
[idbcursor-key.any.html]
|
||||||
|
[IDBCursor.key]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.key 1]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.key 2]
|
||||||
|
expected: FAIL
|
19
tests/wpt/meta/indexeddb/idbcursor-primarykey.any.js.ini
vendored
Normal file
19
tests/wpt/meta/indexeddb/idbcursor-primarykey.any.js.ini
vendored
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
[idbcursor-primarykey.any.worker.html]
|
||||||
|
expected: CRASH
|
||||||
|
|
||||||
|
[idbcursor-primarykey.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor-primarykey.any.html]
|
||||||
|
[IDBCursor.primaryKey]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.primaryKey 1]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.primaryKey 2]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[idbcursor-primarykey.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
57
tests/wpt/meta/indexeddb/idbcursor-request-source.any.js.ini
vendored
Normal file
57
tests/wpt/meta/indexeddb/idbcursor-request-source.any.js.ini
vendored
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
[idbcursor-request-source.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor-request-source.any.worker.html]
|
||||||
|
[IDBObjectStore::openCursor's request source must be the IDBObjectStore instance that opened the cursor]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBObjectStore::openKeyCursor's request source must be the IDBObjectStore instance that opened the cursor]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBIndex::openCursor's request source must be the IDBIndex instance that opened the cursor]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBIndex::openKeyCursor's request source must be the IDBIndex instance that opened the cursor]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[The source of the request from IDBObjectStore::update() is the cursor itself]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[The source of the request from IDBObjectStore::delete() is the cursor itself]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[The source of the request from IDBIndex::update() is the cursor itself]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[The source of the request from IDBIndex::delete() is the cursor itself]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[idbcursor-request-source.any.html]
|
||||||
|
[IDBObjectStore::openCursor's request source must be the IDBObjectStore instance that opened the cursor]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBObjectStore::openKeyCursor's request source must be the IDBObjectStore instance that opened the cursor]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBIndex::openCursor's request source must be the IDBIndex instance that opened the cursor]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBIndex::openKeyCursor's request source must be the IDBIndex instance that opened the cursor]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[The source of the request from IDBObjectStore::update() is the cursor itself]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[The source of the request from IDBObjectStore::delete() is the cursor itself]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[The source of the request from IDBIndex::update() is the cursor itself]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[The source of the request from IDBIndex::delete() is the cursor itself]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[idbcursor-request-source.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
27
tests/wpt/meta/indexeddb/idbcursor-request.any.js.ini
vendored
Normal file
27
tests/wpt/meta/indexeddb/idbcursor-request.any.js.ini
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
[idbcursor-request.any.html]
|
||||||
|
[cursor.request from IDBIndex.openCursor]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[cursor.request from IDBObjectStore.openKeyCursor]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[cursor.request from IDBIndex.openKeyCursor]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[cursor.request from IDBObjectStore.openCursor]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[idbcursor-request.any.worker.html]
|
||||||
|
[cursor.request from IDBIndex.openCursor]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[cursor.request from IDBObjectStore.openKeyCursor]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[cursor.request from IDBIndex.openKeyCursor]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[cursor.request from IDBObjectStore.openCursor]
|
||||||
|
expected: FAIL
|
||||||
|
|
12
tests/wpt/meta/indexeddb/idbcursor-reused.any.js.ini
vendored
Normal file
12
tests/wpt/meta/indexeddb/idbcursor-reused.any.js.ini
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
[idbcursor-reused.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor-reused.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor-reused.any.worker.html]
|
||||||
|
expected: CRASH
|
||||||
|
|
||||||
|
[idbcursor-reused.any.html]
|
||||||
|
[IDBCursor is reused]
|
||||||
|
expected: FAIL
|
20
tests/wpt/meta/indexeddb/idbcursor-source.any.js.ini
vendored
Normal file
20
tests/wpt/meta/indexeddb/idbcursor-source.any.js.ini
vendored
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
[idbcursor-source.any.html]
|
||||||
|
[IDBCursor.source - IDBObjectStore]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.source - IDBIndex]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[idbcursor-source.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor-source.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor-source.any.worker.html]
|
||||||
|
[IDBCursor.source - IDBObjectStore]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.source - IDBIndex]
|
||||||
|
expected: FAIL
|
32
tests/wpt/meta/indexeddb/idbcursor-update-exception-order.any.js.ini
vendored
Normal file
32
tests/wpt/meta/indexeddb/idbcursor-update-exception-order.any.js.ini
vendored
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
[idbcursor-update-exception-order.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor-update-exception-order.any.html]
|
||||||
|
[IDBCursor.update exception order: TransactionInactiveError vs. ReadOnlyError]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.update exception order: ReadOnlyError vs. InvalidStateError #1]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.update exception order: ReadOnlyError vs. InvalidStateError #2]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.update exception order: InvalidStateError vs. DataError]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[idbcursor-update-exception-order.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor-update-exception-order.any.worker.html]
|
||||||
|
[IDBCursor.update exception order: TransactionInactiveError vs. ReadOnlyError]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.update exception order: ReadOnlyError vs. InvalidStateError #1]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.update exception order: ReadOnlyError vs. InvalidStateError #2]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[IDBCursor.update exception order: InvalidStateError vs. DataError]
|
||||||
|
expected: FAIL
|
34
tests/wpt/meta/indexeddb/idbcursor_advance_index.any.js.ini
vendored
Normal file
34
tests/wpt/meta/indexeddb/idbcursor_advance_index.any.js.ini
vendored
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
[idbcursor_advance_index.any.html]
|
||||||
|
[index - iterate cursor number of times specified by count]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[attempt to pass a count parameter that is not a number]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[index - attempt to advance backwards]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[index - iterate to the next record]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Calling advance() with count argument 0 should throw TypeError.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Calling advance() should throws an exception TransactionInactiveError when the transaction is not active.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Calling advance() should throw DOMException when the cursor is currently being iterated.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[If the cursor's source or effective object store has been deleted, the implementation MUST throw a DOMException of type InvalidStateError]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[idbcursor_advance_index.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor_advance_index.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor_advance_index.any.worker.html]
|
||||||
|
expected: CRASH
|
25
tests/wpt/meta/indexeddb/idbcursor_advance_objectstore.any.js.ini
vendored
Normal file
25
tests/wpt/meta/indexeddb/idbcursor_advance_objectstore.any.js.ini
vendored
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
[idbcursor_advance_objectstore.any.html]
|
||||||
|
[object store - iterate cursor number of times specified by count]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Calling advance() with count argument 0 should throw TypeError.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Calling advance() should throws an exception TransactionInactiveError when the transaction is not active]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Calling advance() should throw DOMException when the cursor is currently being iterated.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[If the cursor's source or effective object store has been deleted, the implementation MUST throw a DOMException of type InvalidStateError]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[idbcursor_advance_objectstore.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor_advance_objectstore.any.worker.html]
|
||||||
|
expected: CRASH
|
||||||
|
|
||||||
|
[idbcursor_advance_objectstore.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
13
tests/wpt/meta/indexeddb/idbcursor_continue_delete_objectstore.any.js.ini
vendored
Normal file
13
tests/wpt/meta/indexeddb/idbcursor_continue_delete_objectstore.any.js.ini
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
[idbcursor_continue_delete_objectstore.any.html]
|
||||||
|
[Object store - remove a record from the object store while iterating cursor]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[idbcursor_continue_delete_objectstore.any.sharedworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor_continue_delete_objectstore.any.serviceworker.html]
|
||||||
|
expected: ERROR
|
||||||
|
|
||||||
|
[idbcursor_continue_delete_objectstore.any.worker.html]
|
||||||
|
expected: CRASH
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue