mirror of
https://github.com/lexmount/moli.git
synced 2026-11-13 08:08:10 +00:00
fix(storage): exclude Web Storage from quota-managed usage
Align StorageManager.estimate and CDP Storage.getUsageAndQuota with Chromium's quota clients. Report IndexedDB, Cache Storage, and OPFS by backend, including named and implicit-default bucket data, without touching local/sessionStorage. Keep Web Storage's independent per-area quota unchanged. Cover Web Storage exclusion, an unopened or closed SQLite localStorage backend, default and named OPFS data, bucket attribution, and command-session isolation.
This commit is contained in:
@@ -6,7 +6,7 @@ pub use moli_renderer_v8::{
|
||||
};
|
||||
pub use moli_storage_service::{
|
||||
DEFAULT_ORIGIN_STORAGE_QUOTA_BYTES, SharedStorageBucketStore, StorageBucketIdentity,
|
||||
complete_storage_bucket_deletion, new_shared_json_storage_bucket_store,
|
||||
StorageBucketLocator, complete_storage_bucket_deletion, new_shared_json_storage_bucket_store,
|
||||
new_shared_json_storage_bucket_store_with_cache_root,
|
||||
new_shared_json_storage_bucket_store_with_cache_root_and_indexed_db_manager,
|
||||
new_shared_storage_bucket_store, new_shared_storage_bucket_store_with_indexed_db_manager,
|
||||
|
||||
@@ -136,9 +136,9 @@ pub(crate) struct BrowserContextPageStorageHandles {
|
||||
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||
pub(crate) struct BrowserContextOriginStorageUsage {
|
||||
pub(crate) local_storage_usage: u64,
|
||||
pub(crate) indexed_db_usage: u64,
|
||||
pub(crate) storage_buckets_usage: u64,
|
||||
pub(crate) cache_storage_usage: u64,
|
||||
pub(crate) file_system_usage: u64,
|
||||
pub(crate) total_usage: u64,
|
||||
}
|
||||
|
||||
@@ -367,10 +367,6 @@ impl std::fmt::Debug for BrowserContext {
|
||||
}
|
||||
}
|
||||
|
||||
fn usize_to_u64_saturating(value: usize) -> u64 {
|
||||
u64::try_from(value).unwrap_or(u64::MAX)
|
||||
}
|
||||
|
||||
impl BrowserContext {
|
||||
pub(crate) fn active_page_target(&self) -> &PageTargetHost {
|
||||
self.page_targets
|
||||
@@ -771,52 +767,59 @@ impl BrowserContext {
|
||||
&self,
|
||||
serialized_origin: &str,
|
||||
) -> Result<BrowserContextOriginStorageUsage, String> {
|
||||
let local_storage_usage = {
|
||||
let store = self.storage_partition.web_storage_store();
|
||||
usize_to_u64_saturating(
|
||||
store
|
||||
.try_usage_bytes_for_origin_areas(serialized_origin)
|
||||
.map_err(|error| error.to_string())?,
|
||||
)
|
||||
};
|
||||
let indexed_db_usage = moli_core::storage::indexed_db_origins_with_prefix_usage_bytes(
|
||||
// Web Storage has its own per-area limit and is not a QuotaManager client.
|
||||
let mut indexed_db_usage = moli_core::storage::indexed_db_origins_with_prefix_usage_bytes(
|
||||
self.storage_partition.indexed_db_manager(),
|
||||
&moli_storage_key::storage_key_prefix_for_origin(serialized_origin),
|
||||
)?;
|
||||
let storage_buckets_usage = self.storage_bucket_usage_for_origin(serialized_origin)?;
|
||||
Ok(BrowserContextOriginStorageUsage {
|
||||
local_storage_usage,
|
||||
indexed_db_usage,
|
||||
storage_buckets_usage,
|
||||
total_usage: local_storage_usage
|
||||
.saturating_add(indexed_db_usage)
|
||||
.saturating_add(storage_buckets_usage),
|
||||
})
|
||||
}
|
||||
|
||||
fn storage_bucket_usage_for_origin(&self, serialized_origin: &str) -> Result<u64, String> {
|
||||
let (bucket_identities, cache_usage, storage_service) = {
|
||||
let (bucket_identities, default_keys, cache_storage_usage, storage_service) = {
|
||||
let store = self.storage_partition.storage_bucket_store().lock();
|
||||
(
|
||||
store.bucket_identities_for_origin_areas(serialized_origin),
|
||||
store.keys_for_origin_areas(serialized_origin),
|
||||
store.cache_usage_for_origin_areas(serialized_origin),
|
||||
store.storage_service(),
|
||||
)
|
||||
};
|
||||
let mut usage = cache_usage;
|
||||
let mut default_keys = default_keys
|
||||
.into_iter()
|
||||
.map(|(key, _)| key)
|
||||
.collect::<BTreeSet<_>>();
|
||||
// OPFS can use the implicit default bucket before any CacheStorage or
|
||||
// named-bucket metadata exists. Do not make its usage depend on that registry.
|
||||
let url = url::Url::parse(serialized_origin).map_err(|error| error.to_string())?;
|
||||
default_keys.insert(
|
||||
moli_storage_key::MoliStorageKey::first_party_from_url(&url, None)
|
||||
.serialized_storage_key(),
|
||||
);
|
||||
let mut file_system_usage = 0u64;
|
||||
for key in default_keys {
|
||||
let locator = moli_core::storage::StorageBucketLocator::default_bucket(key);
|
||||
file_system_usage = file_system_usage.saturating_add(
|
||||
storage_service
|
||||
.opfs_usage(&locator)
|
||||
.map_err(|error| format!("FailedToReadStorageBucketOpfsUsage: {error}"))?,
|
||||
);
|
||||
}
|
||||
for identity in bucket_identities {
|
||||
let indexed_db_usage = moli_core::storage::indexed_db_origin_usage_bytes(
|
||||
let bucket_indexed_db_usage = moli_core::storage::indexed_db_origin_usage_bytes(
|
||||
self.storage_partition.indexed_db_manager(),
|
||||
&identity.indexed_db_storage_key(),
|
||||
)?;
|
||||
let opfs_usage = storage_service
|
||||
.opfs_usage(&identity.locator())
|
||||
.map_err(|error| format!("FailedToReadStorageBucketOpfsUsage: {error}"))?;
|
||||
usage = usage
|
||||
.saturating_add(indexed_db_usage)
|
||||
.saturating_add(opfs_usage);
|
||||
indexed_db_usage = indexed_db_usage.saturating_add(bucket_indexed_db_usage);
|
||||
file_system_usage = file_system_usage.saturating_add(opfs_usage);
|
||||
}
|
||||
Ok(usage)
|
||||
Ok(BrowserContextOriginStorageUsage {
|
||||
indexed_db_usage,
|
||||
cache_storage_usage,
|
||||
file_system_usage,
|
||||
total_usage: indexed_db_usage
|
||||
.saturating_add(cache_storage_usage)
|
||||
.saturating_add(file_system_usage),
|
||||
})
|
||||
}
|
||||
|
||||
fn complete_storage_bucket_deletions(
|
||||
|
||||
@@ -450,7 +450,7 @@ fn browser_context_cookie_snapshot_and_delete_use_storage_partition_cookie_handl
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn browser_context_storage_usage_reads_storage_partition_owner() {
|
||||
fn browser_context_quota_usage_excludes_web_storage() {
|
||||
let browser_context = BrowserContext::new("BID-storage-usage".to_owned());
|
||||
let origin = Url::parse("https://usage.example/app")
|
||||
.unwrap()
|
||||
@@ -468,10 +468,10 @@ fn browser_context_storage_usage_reads_storage_partition_owner() {
|
||||
.storage_usage_for_origin(&origin)
|
||||
.expect("storage usage should be readable");
|
||||
|
||||
assert_eq!(usage.local_storage_usage, "owner".len() as u64);
|
||||
assert_eq!(usage.indexed_db_usage, 0);
|
||||
assert_eq!(usage.storage_buckets_usage, 0);
|
||||
assert_eq!(usage.total_usage, usage.local_storage_usage);
|
||||
assert_eq!(usage.cache_storage_usage, 0);
|
||||
assert_eq!(usage.file_system_usage, 0);
|
||||
assert_eq!(usage.total_usage, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -422,16 +422,20 @@ fn get_usage_and_quota_command_output_plan(
|
||||
"overrideActive": override_active,
|
||||
"usageBreakdown": [
|
||||
{
|
||||
"storageType": "local_storage",
|
||||
"usage": usage.local_storage_usage as f64,
|
||||
"storageType": "file_systems",
|
||||
"usage": usage.file_system_usage as f64,
|
||||
},
|
||||
{
|
||||
"storageType": "indexeddb",
|
||||
"usage": usage.indexed_db_usage as f64,
|
||||
},
|
||||
{
|
||||
"storageType": "storage_buckets",
|
||||
"usage": usage.storage_buckets_usage as f64,
|
||||
"storageType": "cache_storage",
|
||||
"usage": usage.cache_storage_usage as f64,
|
||||
},
|
||||
{
|
||||
"storageType": "service_workers",
|
||||
"usage": 0,
|
||||
}
|
||||
]
|
||||
}))
|
||||
|
||||
@@ -2510,7 +2510,7 @@ async fn storage_clear_data_for_partitioned_storage_key_clears_exact_partition_o
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn storage_get_usage_and_quota_reports_local_storage_usage_for_origin() {
|
||||
async fn storage_get_usage_and_quota_excludes_web_storage_for_origin() {
|
||||
let mut ctx = TestContext::new();
|
||||
{
|
||||
let fixture_value = Some(BrowserContext::new_with_page_for_test(
|
||||
@@ -2559,22 +2559,29 @@ async fn storage_get_usage_and_quota_reports_local_storage_usage_for_origin() {
|
||||
.await;
|
||||
|
||||
let result = take_result_by_id(&mut ctx, 12_528);
|
||||
assert_eq!(json_number_as_u64(&result["usage"]), 5);
|
||||
assert_eq!(json_number_as_u64(&result["usage"]), 0);
|
||||
assert_eq!(
|
||||
json_number_as_u64(&result["quota"]),
|
||||
moli_core::storage::DEFAULT_ORIGIN_STORAGE_QUOTA_BYTES
|
||||
);
|
||||
assert_eq!(result["overrideActive"], json!(false));
|
||||
assert_eq!(usage_breakdown_value(&result, "local_storage"), 5);
|
||||
assert_eq!(usage_breakdown_value(&result, "indexeddb"), 0);
|
||||
assert_eq!(usage_breakdown_value(&result, "storage_buckets"), 0);
|
||||
assert!(
|
||||
assert_eq!(usage_breakdown_value(&result, "cache_storage"), 0);
|
||||
assert_eq!(usage_breakdown_value(&result, "file_systems"), 0);
|
||||
assert_eq!(usage_breakdown_value(&result, "service_workers"), 0);
|
||||
assert_eq!(
|
||||
result["usageBreakdown"]
|
||||
.as_array()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.all(|entry| entry["storageType"].as_str() != Some("session_storage")),
|
||||
"CDP StorageType has no session_storage token"
|
||||
.map(|entry| entry["storageType"].as_str().unwrap())
|
||||
.collect::<Vec<_>>(),
|
||||
[
|
||||
"file_systems",
|
||||
"indexeddb",
|
||||
"cache_storage",
|
||||
"service_workers"
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2649,7 +2656,8 @@ async fn storage_get_usage_and_quota_reports_indexed_db_usage_for_origin() {
|
||||
indexed_db_usage > 0,
|
||||
"IndexedDB metadata and record bytes should be reported"
|
||||
);
|
||||
assert_eq!(usage_breakdown_value(&result, "local_storage"), 0);
|
||||
assert_eq!(usage_breakdown_value(&result, "cache_storage"), 0);
|
||||
assert_eq!(usage_breakdown_value(&result, "file_systems"), 0);
|
||||
assert_eq!(json_number_as_u64(&result["usage"]), indexed_db_usage);
|
||||
}
|
||||
|
||||
@@ -2764,21 +2772,28 @@ async fn storage_get_usage_and_quota_reports_storage_bucket_usage_for_origin() {
|
||||
};
|
||||
let opfs_usage = {
|
||||
let storage_service = storage_bucket_store.lock().storage_service();
|
||||
let locator = bucket_a_identity.locator();
|
||||
let bucket_key = moli_storage_service::StorageService::opfs_bucket_key(&locator)
|
||||
.expect("bucket OPFS key should derive");
|
||||
let root = storage_service
|
||||
.ensure_opfs_root(&locator)
|
||||
.expect("bucket OPFS root should open");
|
||||
let file = storage_service
|
||||
.with_opfs(|opfs| opfs.get_file(&bucket_key, &root, "usage.txt", true))
|
||||
.expect("bucket OPFS file should open");
|
||||
storage_service
|
||||
.with_opfs(|opfs| opfs.write_file(&bucket_key, &file, b"opfs usage", None))
|
||||
.expect("bucket OPFS file should write");
|
||||
storage_service
|
||||
.opfs_usage(&locator)
|
||||
.expect("bucket OPFS usage should load")
|
||||
[
|
||||
bucket_a_identity.locator(),
|
||||
moli_storage_service::StorageBucketLocator::default_bucket(&storage_key),
|
||||
]
|
||||
.iter()
|
||||
.map(|locator| {
|
||||
let bucket_key = moli_storage_service::StorageService::opfs_bucket_key(locator)
|
||||
.expect("bucket OPFS key should derive");
|
||||
let root = storage_service
|
||||
.ensure_opfs_root(locator)
|
||||
.expect("bucket OPFS root should open");
|
||||
let file = storage_service
|
||||
.with_opfs(|opfs| opfs.get_file(&bucket_key, &root, "usage.txt", true))
|
||||
.expect("bucket OPFS file should open");
|
||||
storage_service
|
||||
.with_opfs(|opfs| opfs.write_file(&bucket_key, &file, b"opfs usage", None))
|
||||
.expect("bucket OPFS file should write");
|
||||
storage_service
|
||||
.opfs_usage(locator)
|
||||
.expect("bucket OPFS usage should load")
|
||||
})
|
||||
.sum::<u64>()
|
||||
};
|
||||
|
||||
{
|
||||
@@ -2801,7 +2816,6 @@ async fn storage_get_usage_and_quota_reports_storage_bucket_usage_for_origin() {
|
||||
.await;
|
||||
|
||||
let result = take_result_by_id(&mut ctx, 12_533);
|
||||
let bucket_usage = usage_breakdown_value(&result, "storage_buckets");
|
||||
let (bucket_a_usage, bucket_b_usage) = ctx.with_fixture(|conn| {
|
||||
let bc = conn.browser_context.as_ref().unwrap();
|
||||
let bucket_a_usage = moli_core::storage::indexed_db_origin_usage_bytes(
|
||||
@@ -2817,15 +2831,59 @@ async fn storage_get_usage_and_quota_reports_storage_bucket_usage_for_origin() {
|
||||
(bucket_a_usage, bucket_b_usage)
|
||||
});
|
||||
assert_eq!(
|
||||
bucket_usage,
|
||||
json_number_as_u64(&result["usage"]),
|
||||
bucket_a_usage
|
||||
.saturating_add(bucket_b_usage)
|
||||
.saturating_add(cache_usage)
|
||||
.saturating_add(opfs_usage)
|
||||
);
|
||||
assert_eq!(usage_breakdown_value(&result, "local_storage"), 0);
|
||||
assert_eq!(
|
||||
usage_breakdown_value(&result, "indexeddb"),
|
||||
bucket_a_usage.saturating_add(bucket_b_usage)
|
||||
);
|
||||
assert_eq!(usage_breakdown_value(&result, "cache_storage"), cache_usage);
|
||||
assert_eq!(usage_breakdown_value(&result, "file_systems"), opfs_usage);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn storage_get_usage_and_quota_reports_default_opfs_without_bucket_registry_entries() {
|
||||
let mut ctx = TestContext::new();
|
||||
let origin = "https://opfs-only-usage.test";
|
||||
let key = first_party_storage_key_for_origin(origin);
|
||||
let expected = ctx.with_fixture(|conn| {
|
||||
conn.browser_context = Some(BrowserContext::new("BID-usage-opfs-only".into()));
|
||||
let store = conn
|
||||
.browser_context
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.storage_bucket_store_for_test()
|
||||
.lock();
|
||||
assert!(store.keys_for_origin_areas(origin).is_empty());
|
||||
let service = store.storage_service();
|
||||
drop(store);
|
||||
let locator = moli_core::storage::StorageBucketLocator::default_bucket(key);
|
||||
let bucket_key = moli_storage_service::StorageService::opfs_bucket_key(&locator).unwrap();
|
||||
let root = service.ensure_opfs_root(&locator).unwrap();
|
||||
let file = service
|
||||
.with_opfs(|opfs| opfs.get_file(&bucket_key, &root, "only-opfs.txt", true))
|
||||
.unwrap();
|
||||
service
|
||||
.with_opfs(|opfs| opfs.write_file(&bucket_key, &file, b"quota-managed bytes", None))
|
||||
.unwrap();
|
||||
service.opfs_usage(&locator).unwrap()
|
||||
});
|
||||
assert!(expected > 0);
|
||||
ctx.process_async(json!({
|
||||
"id": 12_534,
|
||||
"method": "Storage.getUsageAndQuota",
|
||||
"params": {"origin": origin}
|
||||
}))
|
||||
.await;
|
||||
let result = take_result_by_id(&mut ctx, 12_534);
|
||||
assert_eq!(usage_breakdown_value(&result, "file_systems"), expected);
|
||||
assert_eq!(usage_breakdown_value(&result, "cache_storage"), 0);
|
||||
assert_eq!(usage_breakdown_value(&result, "indexeddb"), 0);
|
||||
assert_eq!(json_number_as_u64(&result["usage"]), bucket_usage);
|
||||
assert_eq!(json_number_as_u64(&result["usage"]), expected);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
@@ -2851,6 +2909,13 @@ async fn storage_get_usage_and_quota_targets_command_session_browser_context() {
|
||||
let store = inactive.web_storage_store_for_test();
|
||||
assert!(store.set_item(&storage_key, "local", "bbbb"));
|
||||
}
|
||||
seed_indexed_db_usage(inactive.indexed_db_manager_for_test(), &storage_key);
|
||||
let expected_usage = moli_core::storage::indexed_db_origin_usage_bytes(
|
||||
inactive.indexed_db_manager_for_test(),
|
||||
&storage_key,
|
||||
)
|
||||
.expect("inactive context IndexedDB usage");
|
||||
assert!(expected_usage > 0);
|
||||
|
||||
ctx.with_fixture(|conn| conn.install_browser_context_fixture_for_test(active));
|
||||
ctx.with_fixture(|conn| conn.push_inactive_browser_context_fixture_for_test(inactive));
|
||||
@@ -2870,8 +2935,8 @@ async fn storage_get_usage_and_quota_targets_command_session_browser_context() {
|
||||
let result = response
|
||||
.get("result")
|
||||
.expect("response should include result");
|
||||
assert_eq!(json_number_as_u64(&result["usage"]), 4);
|
||||
assert_eq!(usage_breakdown_value(result, "local_storage"), 4);
|
||||
assert_eq!(json_number_as_u64(&result["usage"]), expected_usage);
|
||||
assert_eq!(usage_breakdown_value(result, "indexeddb"), expected_usage);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
|
||||
@@ -483,9 +483,6 @@ enum StorageBucketCachedResponseMaterialization<'scope> {
|
||||
|
||||
struct StorageManagerOwnerContext {
|
||||
storage_key: String,
|
||||
area_key: Option<String>,
|
||||
host_ptr: Option<*mut crate::native_bridge::JsContextHost>,
|
||||
popup_id: Option<u64>,
|
||||
}
|
||||
|
||||
#[derive(webidl::WebIdlArgs)]
|
||||
@@ -706,18 +703,7 @@ pub(in crate::context_bootstrap) fn navigator_storage_estimate_callback<'s>(
|
||||
else {
|
||||
return;
|
||||
};
|
||||
let usage = match storage_manager_usage_bytes(scope, &context) {
|
||||
Ok(usage) => usage,
|
||||
Err(error) => {
|
||||
let error = crate::context_bootstrap::new_dom_exception_value(
|
||||
scope,
|
||||
&error.to_string(),
|
||||
"UnknownError",
|
||||
);
|
||||
let _ = resolver.reject(scope, error);
|
||||
return;
|
||||
}
|
||||
};
|
||||
let usage = storage_manager_usage_bytes(scope, &context);
|
||||
let estimate = build_storage_estimate_object_with_quota(
|
||||
scope,
|
||||
usage.total,
|
||||
@@ -830,9 +816,6 @@ fn storage_manager_owner_context<'s>(
|
||||
let storage_context = host.storage_context_for_lightweight_popup(popup_id)?;
|
||||
return Some(StorageManagerOwnerContext {
|
||||
storage_key: storage_context.storage_key().serialized_storage_key(),
|
||||
area_key: Some(storage_context.web_storage_area_key().to_owned()),
|
||||
host_ptr: Some(host_ptr),
|
||||
popup_id: Some(popup_id),
|
||||
});
|
||||
} else {
|
||||
host.top_document_storage_context()
|
||||
@@ -840,19 +823,11 @@ fn storage_manager_owner_context<'s>(
|
||||
};
|
||||
return Some(StorageManagerOwnerContext {
|
||||
storage_key: context.storage_key().serialized_storage_key(),
|
||||
area_key: Some(context.web_storage_area_key().to_owned()),
|
||||
host_ptr: Some(host_ptr),
|
||||
popup_id: None,
|
||||
});
|
||||
}
|
||||
let storage_key = crate::worker::worker_storage_key(scope)?;
|
||||
let storage_key = storage_key.serialized_storage_key();
|
||||
Some(StorageManagerOwnerContext {
|
||||
storage_key,
|
||||
area_key: None,
|
||||
host_ptr: None,
|
||||
popup_id: None,
|
||||
})
|
||||
Some(StorageManagerOwnerContext { storage_key })
|
||||
}
|
||||
|
||||
fn storage_manager_child_handle<'s>(
|
||||
@@ -875,23 +850,7 @@ fn storage_manager_popup_id<'s>(
|
||||
fn storage_manager_usage_bytes(
|
||||
scope: &mut v8::PinScope<'_, '_>,
|
||||
context: &StorageManagerOwnerContext,
|
||||
) -> Result<StorageUsageSnapshot, moli_web_storage::WebStorageMutationError> {
|
||||
let web_storage_usage =
|
||||
if let Some((host_ptr, area_key)) = context.host_ptr.zip(context.area_key.as_deref()) {
|
||||
let host = unsafe { &*host_ptr };
|
||||
let local = host.web_storage_store().try_usage_bytes(area_key)?;
|
||||
let session = if let Some(popup_id) = context.popup_id {
|
||||
host.lightweight_popup_session_storage_store(popup_id)
|
||||
.map(|store| store.try_usage_bytes(area_key))
|
||||
.transpose()?
|
||||
.unwrap_or(0)
|
||||
} else {
|
||||
host.session_storage_store().try_usage_bytes(area_key)?
|
||||
};
|
||||
local.saturating_add(session) as u64
|
||||
} else {
|
||||
0
|
||||
};
|
||||
) -> StorageUsageSnapshot {
|
||||
let locator = moli_storage_service::StorageBucketLocator::default_bucket(&context.storage_key);
|
||||
let bucket_usage = storage_bucket_quota_owner_for_locator(scope, &locator)
|
||||
.and_then(|owner| owner.usage_snapshot().ok());
|
||||
@@ -912,16 +871,15 @@ fn storage_manager_usage_bytes(
|
||||
0,
|
||||
)
|
||||
});
|
||||
Ok(StorageUsageSnapshot {
|
||||
total: web_storage_usage
|
||||
.saturating_add(indexed_db_usage)
|
||||
StorageUsageSnapshot {
|
||||
total: indexed_db_usage
|
||||
.saturating_add(cache_storage_usage)
|
||||
.saturating_add(opfs_usage),
|
||||
quota,
|
||||
indexed_db: indexed_db_usage,
|
||||
cache_storage: cache_storage_usage,
|
||||
opfs: opfs_usage,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(in crate::context_bootstrap) fn storage_bucket_manager_open_callback<'s>(
|
||||
|
||||
@@ -140,6 +140,29 @@ async fn retained_popup_storage_managers_use_bound_popup_owner() {
|
||||
"https://popup-storage-owner.test/page.html",
|
||||
&loader,
|
||||
);
|
||||
// Seed quota-managed bytes for the popup's origin independently of the
|
||||
// retained JS receiver. Reading through the opener's owner would report 0.
|
||||
{
|
||||
let host = vm.context_host_weak_for_test().upgrade().unwrap();
|
||||
let store = host.borrow().storage_bucket_store();
|
||||
let service = store.lock().storage_service();
|
||||
let key = moli_storage_key::MoliStorageKey::first_party_from_url(
|
||||
&url::Url::parse("https://popup-storage-owner-child.test").unwrap(),
|
||||
None,
|
||||
)
|
||||
.serialized_storage_key();
|
||||
let locator = moli_storage_service::StorageBucketLocator::default_bucket(key);
|
||||
let bucket_key = moli_storage_service::StorageService::opfs_bucket_key(&locator).unwrap();
|
||||
let root = service.ensure_opfs_root(&locator).unwrap();
|
||||
let file = service
|
||||
.with_opfs(|opfs| opfs.get_file(&bucket_key, &root, "popup-usage.txt", true))
|
||||
.unwrap();
|
||||
service
|
||||
.with_opfs(|opfs| {
|
||||
opfs.write_file(&bucket_key, &file, b"popup quota-managed data", None)
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
vm.exec(
|
||||
r#"
|
||||
@@ -647,7 +670,7 @@ fn window_open_lightweight_popup_clones_and_isolates_session_storage() {
|
||||
);
|
||||
}
|
||||
#[tokio::test]
|
||||
async fn storage_manager_estimate_uses_lightweight_popup_session_storage_owner() {
|
||||
async fn storage_manager_estimate_excludes_lightweight_popup_session_storage() {
|
||||
let loader = ResourceRequestClient::new(&moli_fetch::FetchConfig::default()).expect("loader");
|
||||
let mut vm = new_page_task_executor_test_vm_with_loader("https://example.com/", &loader);
|
||||
|
||||
@@ -698,7 +721,7 @@ async fn storage_manager_estimate_uses_lightweight_popup_session_storage_owner()
|
||||
assert_eq!(
|
||||
vm.eval("__popupStorageEstimateMessages[0]")
|
||||
.expect("popup StorageManager estimate message should evaluate"),
|
||||
r#"{"usage":16,"indexedDB":null,"topValue":"AAAAA","popupValue":"BBBBBBBBBBB"}"#
|
||||
r#"{"usage":0,"indexedDB":null,"topValue":"AAAAA","popupValue":"BBBBBBBBBBB"}"#
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
|
||||
@@ -2740,7 +2740,7 @@ fn navigator_storage_estimate_usage_tracks_current_origin_storage() {
|
||||
|
||||
assert_eq!(
|
||||
result,
|
||||
"0||7||true|number|true|true|true|true|true|true|indexedDB,caches,fileSystem|1073741824"
|
||||
"0||0||true|number|true|true|true|true|true|true|indexedDB,caches,fileSystem|1073741824"
|
||||
);
|
||||
|
||||
let other_page_url = format!("https://storage-estimate-other-{nonce}.test/");
|
||||
|
||||
@@ -1,5 +1,36 @@
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn storage_estimate_does_not_open_local_storage_or_depend_on_its_connection() {
|
||||
for closed in [false, true] {
|
||||
let directory = tempfile::tempdir().unwrap();
|
||||
let path = directory.path().join("unused/localstorage.sqlite");
|
||||
let runtime = moli_sqlite::Runtime::new().unwrap();
|
||||
let (local, owner) = moli_web_storage::new_lazy_sqlite_web_storage_store(
|
||||
path.clone(),
|
||||
moli_sqlite::OpenMode::Create,
|
||||
runtime.handle(),
|
||||
)
|
||||
.unwrap();
|
||||
let handles =
|
||||
crate::RendererWebStorageHandles::new(local, crate::new_shared_web_storage_store());
|
||||
let mut vm =
|
||||
new_storage_page_task_executor_test_vm("https://quota-without-webstorage.test/");
|
||||
vm.set_web_storage_handles(&handles);
|
||||
if closed {
|
||||
owner.close().unwrap();
|
||||
}
|
||||
vm.eval("globalThis.estimateResult = 'pending'; navigator.storage.estimate().then(value => {estimateResult = JSON.stringify([value.usage, typeof value.quota]);}, error => {estimateResult = error.name;});").unwrap();
|
||||
assert_eq!(
|
||||
vm.eval_after_selected_page_tasks("estimateResult").unwrap(),
|
||||
"[0,\"number\"]"
|
||||
);
|
||||
assert!(!path.parent().unwrap().exists());
|
||||
drop(vm);
|
||||
owner.close().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sqlite_storage_wrappers_share_utf16_data_without_sharing_session_storage() {
|
||||
let directory = tempfile::tempdir().unwrap();
|
||||
|
||||
Reference in New Issue
Block a user