diff --git a/cli/tests/unit/webstorage_test.ts b/cli/tests/unit/webstorage_test.ts index 25813ac037..e6ca5bb880 100644 --- a/cli/tests/unit/webstorage_test.ts +++ b/cli/tests/unit/webstorage_test.ts @@ -1,7 +1,7 @@ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. // deno-lint-ignore-file no-explicit-any -import { assert } from "./test_util.ts"; +import { assert, assertThrows } from "./test_util.ts"; Deno.test({ permissions: "none" }, function webStoragesReassignable() { // Can reassign to web storages @@ -11,3 +11,32 @@ Deno.test({ permissions: "none" }, function webStoragesReassignable() { assert(globalThis.localStorage instanceof globalThis.Storage); assert(globalThis.sessionStorage instanceof globalThis.Storage); }); + +Deno.test(function webstorageSizeLimit() { + localStorage.clear(); + assertThrows( + () => { + localStorage.setItem("k", "v".repeat(15 * 1024 * 1024)); + }, + Error, + "Exceeded maximum storage size", + ); + assert(localStorage.getItem("k") === null); + assertThrows( + () => { + localStorage.setItem("k".repeat(15 * 1024 * 1024), "v"); + }, + Error, + "Exceeded maximum storage size", + ); + assertThrows( + () => { + localStorage.setItem( + "k".repeat(5 * 1024 * 1024), + "v".repeat(5 * 1024 * 1024), + ); + }, + Error, + "Exceeded maximum storage size", + ); +}); diff --git a/ext/webstorage/lib.rs b/ext/webstorage/lib.rs index e98b5da411..ca96b01bc1 100644 --- a/ext/webstorage/lib.rs +++ b/ext/webstorage/lib.rs @@ -19,7 +19,7 @@ pub use rusqlite; #[derive(Clone)] struct OriginStorageDir(PathBuf); -const MAX_STORAGE_BYTES: u32 = 10 * 1024 * 1024; +const MAX_STORAGE_BYTES: usize = 10 * 1024 * 1024; pub fn init(origin_storage_dir: Option) -> Extension { Extension::builder_with_deps(env!("CARGO_PKG_NAME"), &["deno_webidl"]) @@ -133,6 +133,20 @@ pub fn op_webstorage_key( Ok(key) } +#[inline] +fn size_check(input: usize) -> Result<(), AnyError> { + if input >= MAX_STORAGE_BYTES { + return Err( + deno_web::DomExceptionQuotaExceededError::new( + "Exceeded maximum storage size", + ) + .into(), + ); + } + + Ok(()) +} + #[op] pub fn op_webstorage_set( state: &mut OpState, @@ -142,18 +156,13 @@ pub fn op_webstorage_set( ) -> Result<(), AnyError> { let conn = get_webstorage(state, persistent)?; + size_check(key.len() + value.len())?; + let mut stmt = conn .prepare_cached("SELECT SUM(pgsize) FROM dbstat WHERE name = 'data'")?; let size: u32 = stmt.query_row(params![], |row| row.get(0))?; - if size >= MAX_STORAGE_BYTES { - return Err( - deno_web::DomExceptionQuotaExceededError::new( - "Exceeded maximum storage size", - ) - .into(), - ); - } + size_check(size as usize)?; let mut stmt = conn .prepare_cached("INSERT OR REPLACE INTO data (key, value) VALUES (?, ?)")?;