From ab6eac02ffd02fd72ed298716fa0ff270306c0f9 Mon Sep 17 00:00:00 2001 From: Ali Mohammad Pur Date: Mon, 11 May 2026 15:57:16 +0200 Subject: [PATCH] LibHTTP+RequestServer: Add support for synthetic disk-cache entries This exposes the operation through RequestServer.ipc and RequestClient so the client can create the stub before accessing a content-keyed side-data file. --- Libraries/LibHTTP/Cache/DiskCache.cpp | 19 +++++++++++++++++++ Libraries/LibHTTP/Cache/DiskCache.h | 3 +++ Libraries/LibRequests/RequestClient.cpp | 5 +++++ Libraries/LibRequests/RequestClient.h | 1 + .../RequestServer/ConnectionFromClient.cpp | 13 +++++++++++++ Services/RequestServer/ConnectionFromClient.h | 1 + Services/RequestServer/RequestServer.ipc | 1 + 7 files changed, 43 insertions(+) diff --git a/Libraries/LibHTTP/Cache/DiskCache.cpp b/Libraries/LibHTTP/Cache/DiskCache.cpp index dee87eb7e8..16e68fc405 100644 --- a/Libraries/LibHTTP/Cache/DiskCache.cpp +++ b/Libraries/LibHTTP/Cache/DiskCache.cpp @@ -223,6 +223,25 @@ Variant, DiskCache::CacheHasOpenEntry> DiskCache::op return Optional { *cache_entry_pointer }; } +ErrorOr DiskCache::create_synthetic_entry(URL::URL const& url, StringView method) +{ + auto request_headers = HeaderList::create(); + if (!is_cacheable(method, *request_headers)) + return false; + + auto serialized_url = serialize_url_for_cache_storage(url); + auto cache_key = create_cache_key(serialized_url, method, m_partitioned_cache_key); + constexpr u64 synthetic_vary_key = 0; + + if (m_index.has_entry(cache_key, synthetic_vary_key)) + return true; + + auto response_headers = HeaderList::create(); + auto now = UnixDateTime::now(); + TRY(m_index.create_entry(cache_key, synthetic_vary_key, serialized_url, request_headers, response_headers, 0, now, now)); + return true; +} + ErrorOr DiskCache::store_associated_data(URL::URL const& url, StringView method, HeaderList const& request_headers, Optional vary_key, CacheEntryAssociatedData associated_data, ReadonlyBytes data) { if (!is_cacheable(method, request_headers)) diff --git a/Libraries/LibHTTP/Cache/DiskCache.h b/Libraries/LibHTTP/Cache/DiskCache.h index 9f17ca63c2..1203f94104 100644 --- a/Libraries/LibHTTP/Cache/DiskCache.h +++ b/Libraries/LibHTTP/Cache/DiskCache.h @@ -58,6 +58,9 @@ public: ErrorOr> retrieve_associated_data(URL::URL const&, StringView method, HeaderList const& request_headers, Optional vary_key, CacheEntryAssociatedData); ErrorOr> retrieve_associated_data_file(URL::URL const&, StringView method, HeaderList const& request_headers, Optional vary_key, CacheEntryAssociatedData); + // Ensure an index row exists for url+method so the shelf has something to attach to even if there are no real HTTP requests in flight. + ErrorOr create_synthetic_entry(URL::URL const&, StringView method); + void remove_entries_exceeding_cache_limit(); void set_maximum_disk_cache_size(u64 maximum_disk_cache_size); diff --git a/Libraries/LibRequests/RequestClient.cpp b/Libraries/LibRequests/RequestClient.cpp index 7cbe8d7e05..45a0cfe1aa 100644 --- a/Libraries/LibRequests/RequestClient.cpp +++ b/Libraries/LibRequests/RequestClient.cpp @@ -102,6 +102,11 @@ ErrorOr> RequestClient::retrieve_cache_associate return IPCProxy::retrieve_cache_associated_data(url, method, headers, vary_key, associated_data); } +ErrorOr RequestClient::create_synthetic_cache_entry(URL::URL const& url, ByteString const& method) +{ + return IPCProxy::create_synthetic_cache_entry(url, method); +} + bool RequestClient::stop_request(Badge, Request& request) { if (!m_requests.contains(request.id())) diff --git a/Libraries/LibRequests/RequestClient.h b/Libraries/LibRequests/RequestClient.h index 24e7a5be4e..9c5d6b641d 100644 --- a/Libraries/LibRequests/RequestClient.h +++ b/Libraries/LibRequests/RequestClient.h @@ -46,6 +46,7 @@ public: NonnullRefPtr> estimate_cache_size_accessed_since(UnixDateTime since); ErrorOr store_cache_associated_data(URL::URL const&, ByteString const& method, Optional request_headers, Optional vary_key, HTTP::CacheEntryAssociatedData, ReadonlyBytes); ErrorOr> retrieve_cache_associated_data(URL::URL const&, ByteString const& method, Optional request_headers, Optional vary_key, HTTP::CacheEntryAssociatedData); + ErrorOr create_synthetic_cache_entry(URL::URL const&, ByteString const& method); Function on_retrieve_http_cookie; Function on_request_server_died; diff --git a/Services/RequestServer/ConnectionFromClient.cpp b/Services/RequestServer/ConnectionFromClient.cpp index b4f73bf247..c81ee644b1 100644 --- a/Services/RequestServer/ConnectionFromClient.cpp +++ b/Services/RequestServer/ConnectionFromClient.cpp @@ -491,6 +491,19 @@ Messages::RequestServer::RetrieveCacheAssociatedDataResponse ConnectionFromClien return Optional { buffer.release_value() }; } +Messages::RequestServer::CreateSyntheticCacheEntryResponse ConnectionFromClient::create_synthetic_cache_entry(URL::URL url, ByteString method) +{ + if (!m_disk_cache.has_value()) + return false; + + auto result = m_disk_cache->create_synthetic_entry(url, method); + if (result.is_error()) { + dbgln("Failed to create synthetic cache entry for {}: {}", url, result.error()); + return false; + } + return result.value(); +} + void ConnectionFromClient::websocket_connect(u64 websocket_id, URL::URL url, ByteString origin, Vector protocols, Vector extensions, Vector additional_request_headers) { auto host = url.serialized_host().to_byte_string(); diff --git a/Services/RequestServer/ConnectionFromClient.h b/Services/RequestServer/ConnectionFromClient.h index 946541f738..20f2682b1b 100644 --- a/Services/RequestServer/ConnectionFromClient.h +++ b/Services/RequestServer/ConnectionFromClient.h @@ -68,6 +68,7 @@ private: virtual void remove_cache_entries_accessed_since(UnixDateTime since) override; virtual Messages::RequestServer::StoreCacheAssociatedDataResponse store_cache_associated_data(URL::URL, ByteString method, Vector request_headers, Optional vary_key, HTTP::CacheEntryAssociatedData, Core::AnonymousBuffer) override; virtual Messages::RequestServer::RetrieveCacheAssociatedDataResponse retrieve_cache_associated_data(URL::URL, ByteString method, Vector request_headers, Optional vary_key, HTTP::CacheEntryAssociatedData) override; + virtual Messages::RequestServer::CreateSyntheticCacheEntryResponse create_synthetic_cache_entry(URL::URL, ByteString method) override; virtual void websocket_connect(u64 websocket_id, URL::URL, ByteString, Vector, Vector, Vector) override; virtual void websocket_send(u64 websocket_id, bool, ByteBuffer) override; diff --git a/Services/RequestServer/RequestServer.ipc b/Services/RequestServer/RequestServer.ipc index 42f7a66d34..a127963f8a 100644 --- a/Services/RequestServer/RequestServer.ipc +++ b/Services/RequestServer/RequestServer.ipc @@ -37,6 +37,7 @@ endpoint RequestServer remove_cache_entries_accessed_since(UnixDateTime since) =| store_cache_associated_data(URL::URL url, ByteString method, Vector request_headers, Optional vary_key, HTTP::CacheEntryAssociatedData associated_data, Core::AnonymousBuffer data) => (bool stored) retrieve_cache_associated_data(URL::URL url, ByteString method, Vector request_headers, Optional vary_key, HTTP::CacheEntryAssociatedData associated_data) => (Optional data) + create_synthetic_cache_entry(URL::URL url, ByteString method) => (bool created) // Websocket Connection API websocket_connect(u64 websocket_id, URL::URL url, ByteString origin, Vector protocols, Vector extensions, Vector additional_request_headers) =|