LibWebView: Add methods to estimate cookie / WebStorage sizes

This commit is contained in:
Timothy Flynn 2025-11-02 13:11:20 -05:00 committed by Tim Flynn
parent 23fb68b5a4
commit c2c269814a
Notes: github-actions[bot] 2025-11-12 14:08:15 +00:00
4 changed files with 72 additions and 3 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021-2024, Tim Flynn <trflynn89@serenityos.org>
* Copyright (c) 2021-2025, Tim Flynn <trflynn89@ladybird.org>
* Copyright (c) 2022, the SerenityOS developers.
* Copyright (c) 2022, Tobias Christiansen <tobyase@serenityos.org>
* Copyright (c) 2023, Jelle Raaijmakers <jelle@ladybird.org>
@ -233,6 +233,11 @@ void CookieJar::expire_cookies_with_time_offset(AK::Duration offset)
m_transient_storage.purge_expired_cookies(offset);
}
Requests::CacheSizes CookieJar::estimate_storage_size_accessed_since(UnixDateTime since) const
{
return m_transient_storage.estimate_storage_size_accessed_since(since);
}
// https://www.ietf.org/archive/id/draft-ietf-httpbis-rfc6265bis-15.html#name-storage-model
void CookieJar::store_cookie(Web::Cookie::ParsedCookie const& parsed_cookie, URL::URL const& url, String canonicalized_domain, Web::Cookie::Source source)
{
@ -647,6 +652,21 @@ void CookieJar::TransientStorage::expire_and_purge_all_cookies()
purge_expired_cookies();
}
Requests::CacheSizes CookieJar::TransientStorage::estimate_storage_size_accessed_since(UnixDateTime since) const
{
Requests::CacheSizes sizes;
for (auto const& [key, value] : m_cookies) {
auto size = key.name.byte_count() + key.domain.byte_count() + key.path.byte_count() + value.value.byte_count();
sizes.total += size;
if (value.last_access_time >= since)
sizes.since_requested_time += size;
}
return sizes;
}
void CookieJar::PersistedStorage::insert_cookie(Web::Cookie::Cookie const& cookie)
{
database.execute_statement(

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021-2024, Tim Flynn <trflynn89@serenityos.org>
* Copyright (c) 2021-2025, Tim Flynn <trflynn89@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -14,6 +14,7 @@
#include <AK/Traits.h>
#include <LibCore/Timer.h>
#include <LibDatabase/Forward.h>
#include <LibRequests/CacheSizes.h>
#include <LibURL/Forward.h>
#include <LibWeb/Cookie/Cookie.h>
#include <LibWeb/Forward.h>
@ -46,6 +47,7 @@ public:
Vector<Web::Cookie::Cookie> get_all_cookies_cookiestore(URL::URL const& url);
Optional<Web::Cookie::Cookie> get_named_cookie(URL::URL const& url, StringView name);
void expire_cookies_with_time_offset(AK::Duration);
Requests::CacheSizes estimate_storage_size_accessed_since(UnixDateTime since) const;
private:
struct Statements {
@ -67,6 +69,8 @@ private:
UnixDateTime purge_expired_cookies(Optional<AK::Duration> offset = {});
void expire_and_purge_all_cookies();
Requests::CacheSizes estimate_storage_size_accessed_since(UnixDateTime since) const;
auto take_dirty_cookies() { return move(m_dirty_cookies); }
template<typename Callback>

View file

@ -60,7 +60,8 @@ ErrorOr<NonnullOwnPtr<StorageJar>> StorageJar::create(Database::Database& databa
statements.update_last_access_time = TRY(database.prepare_statement("UPDATE WebStorage SET last_access_time = ? WHERE storage_endpoint = ? AND storage_key = ? AND bottle_key = ?;"sv));
statements.clear = TRY(database.prepare_statement("DELETE FROM WebStorage WHERE storage_endpoint = ? AND storage_key = ?;"sv));
statements.get_keys = TRY(database.prepare_statement("SELECT bottle_key FROM WebStorage WHERE storage_endpoint = ? AND storage_key = ?;"sv));
statements.calculate_size_excluding_key = TRY(database.prepare_statement("SELECT SUM(LENGTH(bottle_key) + LENGTH(bottle_value)) FROM WebStorage WHERE storage_endpoint = ? AND storage_key = ? AND bottle_key != ?;"sv));
statements.calculate_size_excluding_key = TRY(database.prepare_statement("SELECT SUM(OCTET_LENGTH(bottle_key) + OCTET_LENGTH(bottle_value)) FROM WebStorage WHERE storage_endpoint = ? AND storage_key = ? AND bottle_key != ?;"sv));
statements.estimate_storage_size_accessed_since = TRY(database.prepare_statement("SELECT SUM(OCTET_LENGTH(storage_key)) + SUM(OCTET_LENGTH(bottle_key)) + SUM(OCTET_LENGTH(bottle_value)) FROM WebStorage WHERE last_access_time >= ?;"sv));
return adopt_own(*new StorageJar { PersistedStorage { database, statements } });
}
@ -139,6 +140,13 @@ Vector<String> StorageJar::get_all_keys(StorageEndpointType storage_endpoint, St
return m_transient_storage.get_keys(storage_endpoint, storage_key);
}
Requests::CacheSizes StorageJar::estimate_storage_size_accessed_since(UnixDateTime since) const
{
if (m_persisted_storage.has_value())
return m_persisted_storage->estimate_storage_size_accessed_since(since);
return m_transient_storage.estimate_storage_size_accessed_since(since);
}
Optional<String> StorageJar::TransientStorage::get_item(StorageLocation const& key)
{
if (auto entry = m_storage_items.get(key); entry.has_value()) {
@ -197,6 +205,21 @@ Vector<String> StorageJar::TransientStorage::get_keys(StorageEndpointType storag
return keys;
}
Requests::CacheSizes StorageJar::TransientStorage::estimate_storage_size_accessed_since(UnixDateTime since) const
{
Requests::CacheSizes sizes;
for (auto const& [key, entry] : m_storage_items) {
auto size = key.storage_key.byte_count() + key.bottle_key.byte_count() + entry.value.byte_count();
sizes.total += size;
if (entry.last_access_time >= since)
sizes.since_requested_time += size;
}
return sizes;
}
Optional<String> StorageJar::PersistedStorage::get_item(StorageLocation const& key)
{
Optional<String> result;
@ -285,4 +308,21 @@ Vector<String> StorageJar::PersistedStorage::get_keys(StorageEndpointType storag
return keys;
}
Requests::CacheSizes StorageJar::PersistedStorage::estimate_storage_size_accessed_since(UnixDateTime since) const
{
Requests::CacheSizes sizes;
database.execute_statement(
statements.estimate_storage_size_accessed_since,
[&](auto statement_id) { sizes.since_requested_time = database.result_column<u64>(statement_id, 0); },
since);
database.execute_statement(
statements.estimate_storage_size_accessed_since,
[&](auto statement_id) { sizes.total = database.result_column<u64>(statement_id, 0); },
UnixDateTime::earliest());
return sizes;
}
}

View file

@ -11,6 +11,7 @@
#include <AK/Time.h>
#include <AK/Traits.h>
#include <LibDatabase/Forward.h>
#include <LibRequests/CacheSizes.h>
#include <LibWeb/StorageAPI/StorageEndpoint.h>
#include <LibWebView/Forward.h>
#include <LibWebView/StorageOperationError.h>
@ -42,6 +43,7 @@ public:
void remove_item(StorageEndpointType storage_endpoint, String const& storage_key, String const& key);
void clear_storage_key(StorageEndpointType storage_endpoint, String const& storage_key);
Vector<String> get_all_keys(StorageEndpointType storage_endpoint, String const& storage_key);
Requests::CacheSizes estimate_storage_size_accessed_since(UnixDateTime since) const;
private:
struct Statements {
@ -52,6 +54,7 @@ private:
Database::StatementID clear { 0 };
Database::StatementID get_keys { 0 };
Database::StatementID calculate_size_excluding_key { 0 };
Database::StatementID estimate_storage_size_accessed_since { 0 };
};
class TransientStorage {
@ -61,6 +64,7 @@ private:
void delete_item(StorageLocation const& key);
void clear(StorageEndpointType storage_endpoint, String const& storage_key);
Vector<String> get_keys(StorageEndpointType storage_endpoint, String const& storage_key);
Requests::CacheSizes estimate_storage_size_accessed_since(UnixDateTime since) const;
private:
struct Entry {
@ -77,6 +81,7 @@ private:
void delete_item(StorageLocation const& key);
void clear(StorageEndpointType storage_endpoint, String const& storage_key);
Vector<String> get_keys(StorageEndpointType storage_endpoint, String const& storage_key);
Requests::CacheSizes estimate_storage_size_accessed_since(UnixDateTime since) const;
Database::Database& database;
Statements statements;