From ad226b6fb1bdfe5f30c3a9e0cd50cc91c84a49f7 Mon Sep 17 00:00:00 2001 From: Pierre Tachoire Date: Thu, 26 Feb 2026 15:30:32 +0100 Subject: [PATCH 1/3] implement storage size limit per origin --- src/browser/webapi/storage/storage.zig | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/browser/webapi/storage/storage.zig b/src/browser/webapi/storage/storage.zig index 64dfae23..752ef1d3 100644 --- a/src/browser/webapi/storage/storage.zig +++ b/src/browser/webapi/storage/storage.zig @@ -60,6 +60,9 @@ pub const Bucket = struct { local: Lookup = .{}, session: Lookup = .{} }; pub const Lookup = struct { _data: std.StringHashMapUnmanaged([]const u8) = .empty, + _size: usize = 0, + + const max_size = 5 * 1024 * 1024; pub fn getItem(self: *const Lookup, key_: ?[]const u8) ?[]const u8 { const k = key_ orelse return null; @@ -69,6 +72,11 @@ pub const Lookup = struct { pub fn setItem(self: *Lookup, key_: ?[]const u8, value: []const u8, page: *Page) !void { const k = key_ orelse return; + if (self._size + value.len > max_size) { + return error.QuotaExceeded; + } + defer self._size += value.len; + const key_owned = try page.dupeString(k); const value_owned = try page.dupeString(value); @@ -112,7 +120,7 @@ pub const Lookup = struct { pub const length = bridge.accessor(Lookup.getLength, null, .{}); pub const getItem = bridge.function(Lookup.getItem, .{}); - pub const setItem = bridge.function(Lookup.setItem, .{}); + pub const setItem = bridge.function(Lookup.setItem, .{ .dom_exception = true }); pub const removeItem = bridge.function(Lookup.removeItem, .{}); pub const clear = bridge.function(Lookup.clear, .{}); pub const key = bridge.function(Lookup.key, .{}); From c61eda0d241b73ae7fa89d9f8f8fb1b5854bec70 Mon Sep 17 00:00:00 2001 From: Pierre Tachoire Date: Thu, 26 Feb 2026 15:51:01 +0100 Subject: [PATCH 2/3] crypto: use dom exception to return QuotaExceededError --- src/browser/webapi/Crypto.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/browser/webapi/Crypto.zig b/src/browser/webapi/Crypto.zig index 89324695..a79fbc40 100644 --- a/src/browser/webapi/Crypto.zig +++ b/src/browser/webapi/Crypto.zig @@ -32,7 +32,7 @@ pub fn getRandomValues(_: *const Crypto, js_obj: js.Object) !js.Object { var into = try js_obj.toZig(RandomValues); const buf = into.asBuffer(); if (buf.len > 65_536) { - return error.QuotaExceededError; + return error.QuotaExceeded; } std.crypto.random.bytes(buf); return js_obj; @@ -82,7 +82,7 @@ pub const JsApi = struct { pub const empty_with_no_proto = true; }; - pub const getRandomValues = bridge.function(Crypto.getRandomValues, .{}); + pub const getRandomValues = bridge.function(Crypto.getRandomValues, .{ .dom_exception = true }); pub const randomUUID = bridge.function(Crypto.randomUUID, .{}); pub const subtle = bridge.accessor(Crypto.getSubtle, null, .{}); }; From ef6a7a6904d865e3b86232535260731641a005fa Mon Sep 17 00:00:00 2001 From: Pierre Tachoire Date: Fri, 27 Feb 2026 08:51:22 +0100 Subject: [PATCH 3/3] storage: maintain Lookup size correctly --- src/browser/tests/storage.html | 9 +++++++++ src/browser/webapi/storage/storage.zig | 6 +++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/browser/tests/storage.html b/src/browser/tests/storage.html index 7633293b..cb41bb3d 100644 --- a/src/browser/tests/storage.html +++ b/src/browser/tests/storage.html @@ -88,3 +88,12 @@ localStorage.clear(); testing.expectEqual(0, localStorage.length) + + diff --git a/src/browser/webapi/storage/storage.zig b/src/browser/webapi/storage/storage.zig index 752ef1d3..1787dfee 100644 --- a/src/browser/webapi/storage/storage.zig +++ b/src/browser/webapi/storage/storage.zig @@ -86,11 +86,15 @@ pub const Lookup = struct { pub fn removeItem(self: *Lookup, key_: ?[]const u8) void { const k = key_ orelse return; - _ = self._data.remove(k); + if (self._data.get(k)) |value| { + self._size -= value.len; + _ = self._data.remove(k); + } } pub fn clear(self: *Lookup) void { self._data.clearRetainingCapacity(); + self._size = 0; } pub fn key(self: *const Lookup, index: u32) ?[]const u8 {