diff --git a/Libraries/LibWeb/HTML/Storage.cpp b/Libraries/LibWeb/HTML/Storage.cpp
index 33f0f5ac75d..d8c1d60ff8b 100644
--- a/Libraries/LibWeb/HTML/Storage.cpp
+++ b/Libraries/LibWeb/HTML/Storage.cpp
@@ -1,6 +1,7 @@
/*
* Copyright (c) 2022, Andreas Kling
* Copyright (c) 2023, Luke Wilde
+ * Copyright (c) 2024, Shannon Booth
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@@ -14,13 +15,14 @@ namespace Web::HTML {
GC_DEFINE_ALLOCATOR(Storage);
-GC::Ref Storage::create(JS::Realm& realm)
+GC::Ref Storage::create(JS::Realm& realm, u64 quota_bytes)
{
- return realm.create(realm);
+ return realm.create(realm, quota_bytes);
}
-Storage::Storage(JS::Realm& realm)
+Storage::Storage(JS::Realm& realm, u64 quota_bytes)
: Bindings::PlatformObject(realm)
+ , m_quota_bytes(quota_bytes)
{
m_legacy_platform_object_flags = LegacyPlatformObjectFlags {
.supports_indexed_properties = true,
@@ -78,6 +80,8 @@ Optional Storage::get_item(StringView key) const
// https://html.spec.whatwg.org/multipage/webstorage.html#dom-storage-setitem
WebIDL::ExceptionOr Storage::set_item(String const& key, String const& value)
{
+ auto& realm = this->realm();
+
// 1. Let oldValue be null.
String old_value;
@@ -85,6 +89,7 @@ WebIDL::ExceptionOr Storage::set_item(String const& key, String const& val
bool reorder = true;
// 3. If this's map[key] exists:
+ auto new_size = m_stored_bytes;
if (auto it = m_map.find(key); it != m_map.end()) {
// 1. Set oldValue to this's map[key].
old_value = it->value;
@@ -95,12 +100,18 @@ WebIDL::ExceptionOr Storage::set_item(String const& key, String const& val
// 3. Set reorder to false.
reorder = false;
+ } else {
+ new_size += key.bytes().size();
}
- // FIXME: 4. If value cannot be stored, then throw a "QuotaExceededError" DOMException exception.
+ // 4. If value cannot be stored, then throw a "QuotaExceededError" DOMException exception.
+ new_size += value.bytes().size() - old_value.bytes().size();
+ if (new_size > m_quota_bytes)
+ return WebIDL::QuotaExceededError::create(realm, MUST(String::formatted("Unable to store more than {} bytes in storage"sv, m_quota_bytes)));
// 5. Set this's map[key] to value.
m_map.set(key, value);
+ m_stored_bytes = new_size;
// 6. If reorder is true, then reorder this.
if (reorder)
@@ -126,6 +137,7 @@ void Storage::remove_item(StringView key)
// 3. Remove this's map[key].
m_map.remove(it);
+ m_stored_bytes = m_stored_bytes - key.bytes().size() - old_value.bytes().size();
// 4. Reorder this.
reorder();
diff --git a/Libraries/LibWeb/HTML/Storage.h b/Libraries/LibWeb/HTML/Storage.h
index 33c115d52fb..4dd9a9e18e8 100644
--- a/Libraries/LibWeb/HTML/Storage.h
+++ b/Libraries/LibWeb/HTML/Storage.h
@@ -18,7 +18,7 @@ class Storage : public Bindings::PlatformObject {
GC_DECLARE_ALLOCATOR(Storage);
public:
- [[nodiscard]] static GC::Ref create(JS::Realm&);
+ [[nodiscard]] static GC::Ref create(JS::Realm&, u64 quota_bytes);
~Storage();
size_t length() const;
@@ -33,7 +33,7 @@ public:
void dump() const;
private:
- explicit Storage(JS::Realm&);
+ explicit Storage(JS::Realm&, u64 quota_limit);
virtual void initialize(JS::Realm&) override;
@@ -49,6 +49,8 @@ private:
void broadcast(StringView key, StringView old_value, StringView new_value);
OrderedHashMap m_map;
+ u64 m_quota_bytes { 0 };
+ u64 m_stored_bytes { 0 };
};
}
diff --git a/Libraries/LibWeb/HTML/Window.cpp b/Libraries/LibWeb/HTML/Window.cpp
index a5e29eecb02..47628470802 100644
--- a/Libraries/LibWeb/HTML/Window.cpp
+++ b/Libraries/LibWeb/HTML/Window.cpp
@@ -447,10 +447,13 @@ void Window::fire_a_page_transition_event(FlyString const& event_name, bool pers
// https://html.spec.whatwg.org/multipage/webstorage.html#dom-localstorage
WebIDL::ExceptionOr> Window::local_storage()
{
+ // See table in: https://storage.spec.whatwg.org/#registered-storage-endpoints
+ constexpr u64 quota_bytes = 5 * MiB;
+
// FIXME: Implement according to spec.
static HashMap> local_storage_per_origin;
auto storage = local_storage_per_origin.ensure(associated_document().origin(), [this]() -> GC::Root {
- return Storage::create(realm());
+ return Storage::create(realm(), quota_bytes);
});
return GC::Ref { *storage };
}
@@ -458,10 +461,13 @@ WebIDL::ExceptionOr> Window::local_storage()
// https://html.spec.whatwg.org/multipage/webstorage.html#dom-sessionstorage
WebIDL::ExceptionOr> Window::session_storage()
{
+ // See table in: https://storage.spec.whatwg.org/#registered-storage-endpoints
+ constexpr u64 quota_bytes = 5 * MiB;
+
// FIXME: Implement according to spec.
static HashMap> session_storage_per_origin;
auto storage = session_storage_per_origin.ensure(associated_document().origin(), [this]() -> GC::Root {
- return Storage::create(realm());
+ return Storage::create(realm(), quota_bytes);
});
return GC::Ref { *storage };
}
diff --git a/Tests/LibWeb/Text/expected/wpt-import/webstorage/storage_local_setitem_quotaexceedederr.window.txt b/Tests/LibWeb/Text/expected/wpt-import/webstorage/storage_local_setitem_quotaexceedederr.window.txt
new file mode 100644
index 00000000000..4327c6a04e8
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/wpt-import/webstorage/storage_local_setitem_quotaexceedederr.window.txt
@@ -0,0 +1 @@
+QuotaExceededError: Unable to store more than 5242880 bytes in storage
diff --git a/Tests/LibWeb/Text/expected/wpt-import/webstorage/storage_session_setitem_quotaexceedederr.window.txt b/Tests/LibWeb/Text/expected/wpt-import/webstorage/storage_session_setitem_quotaexceedederr.window.txt
new file mode 100644
index 00000000000..4327c6a04e8
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/wpt-import/webstorage/storage_session_setitem_quotaexceedederr.window.txt
@@ -0,0 +1 @@
+QuotaExceededError: Unable to store more than 5242880 bytes in storage
diff --git a/Tests/LibWeb/Text/input/wpt-import/webstorage/storage_local_setitem_quotaexceedederr.window.html b/Tests/LibWeb/Text/input/wpt-import/webstorage/storage_local_setitem_quotaexceedederr.window.html
new file mode 100644
index 00000000000..f8050e7da1e
--- /dev/null
+++ b/Tests/LibWeb/Text/input/wpt-import/webstorage/storage_local_setitem_quotaexceedederr.window.html
@@ -0,0 +1,22 @@
+
+
diff --git a/Tests/LibWeb/Text/input/wpt-import/webstorage/storage_session_setitem_quotaexceedederr.window.html b/Tests/LibWeb/Text/input/wpt-import/webstorage/storage_session_setitem_quotaexceedederr.window.html
new file mode 100644
index 00000000000..d220c9b99b5
--- /dev/null
+++ b/Tests/LibWeb/Text/input/wpt-import/webstorage/storage_session_setitem_quotaexceedederr.window.html
@@ -0,0 +1,22 @@
+
+