Skip to content

Commit 21bbbac

Browse files
committed
LibHTTP+RequestServer: Move the HTTP cache implementation to LibHTTP
We currently have two ongoing implementations of RFC 9111, HTTP caching. In order to consolidate these, this patch moves the implementation from RequestServer to LibHTTP for re-use within LibWeb.
1 parent 1f8a42c commit 21bbbac

File tree

18 files changed

+242
-205
lines changed

18 files changed

+242
-205
lines changed

Libraries/LibHTTP/CMakeLists.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
set(SOURCES
2+
Cache/CacheEntry.cpp
3+
Cache/CacheIndex.cpp
4+
Cache/DiskCache.cpp
5+
Cache/Utilities.cpp
26
Header.cpp
37
HeaderList.cpp
48
HTTP.cpp
@@ -7,4 +11,4 @@ set(SOURCES
711
)
812

913
ladybird_lib(LibHTTP http)
10-
target_link_libraries(LibHTTP PRIVATE LibCompress LibCore LibIPC LibRegex LibTextCodec LibTLS LibURL)
14+
target_link_libraries(LibHTTP PRIVATE LibCompress LibCore LibCrypto LibDatabase LibFileSystem LibIPC LibRegex LibTextCodec LibTLS LibURL)

Services/RequestServer/Cache/CacheEntry.cpp renamed to Libraries/LibHTTP/Cache/CacheEntry.cpp

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,14 @@
66

77
#include <AK/HashFunctions.h>
88
#include <AK/ScopeGuard.h>
9-
#include <LibCore/Notifier.h>
109
#include <LibCore/System.h>
1110
#include <LibFileSystem/FileSystem.h>
12-
#include <RequestServer/Cache/CacheEntry.h>
13-
#include <RequestServer/Cache/CacheIndex.h>
14-
#include <RequestServer/Cache/DiskCache.h>
15-
#include <RequestServer/Cache/Utilities.h>
11+
#include <LibHTTP/Cache/CacheEntry.h>
12+
#include <LibHTTP/Cache/CacheIndex.h>
13+
#include <LibHTTP/Cache/DiskCache.h>
14+
#include <LibHTTP/Cache/Utilities.h>
1615

17-
namespace RequestServer {
16+
namespace HTTP {
1817

1918
ErrorOr<CacheHeader> CacheHeader::read_from_stream(Stream& stream)
2019
{
@@ -117,7 +116,7 @@ CacheEntryWriter::CacheEntryWriter(DiskCache& disk_cache, CacheIndex& index, u64
117116
{
118117
}
119118

120-
ErrorOr<void> CacheEntryWriter::write_status_and_reason(u32 status_code, Optional<String> reason_phrase, HTTP::HeaderList const& response_headers)
119+
ErrorOr<void> CacheEntryWriter::write_status_and_reason(u32 status_code, Optional<String> reason_phrase, HeaderList const& response_headers)
121120
{
122121
if (m_marked_for_deletion) {
123122
close_and_destroy_cache_entry();
@@ -183,7 +182,7 @@ ErrorOr<void> CacheEntryWriter::write_data(ReadonlyBytes data)
183182
return {};
184183
}
185184

186-
ErrorOr<void> CacheEntryWriter::flush(NonnullRefPtr<HTTP::HeaderList> response_headers)
185+
ErrorOr<void> CacheEntryWriter::flush(NonnullRefPtr<HeaderList> response_headers)
187186
{
188187
ScopeGuard guard { [&]() { close_and_destroy_cache_entry(); } };
189188

@@ -205,7 +204,7 @@ ErrorOr<void> CacheEntryWriter::flush(NonnullRefPtr<HTTP::HeaderList> response_h
205204
return {};
206205
}
207206

208-
ErrorOr<NonnullOwnPtr<CacheEntryReader>> CacheEntryReader::create(DiskCache& disk_cache, CacheIndex& index, u64 cache_key, NonnullRefPtr<HTTP::HeaderList> response_headers, u64 data_size)
207+
ErrorOr<NonnullOwnPtr<CacheEntryReader>> CacheEntryReader::create(DiskCache& disk_cache, CacheIndex& index, u64 cache_key, NonnullRefPtr<HeaderList> response_headers, u64 data_size)
209208
{
210209
auto path = path_for_cache_key(disk_cache.cache_directory(), cache_key);
211210

@@ -253,7 +252,7 @@ ErrorOr<NonnullOwnPtr<CacheEntryReader>> CacheEntryReader::create(DiskCache& dis
253252
return adopt_own(*new CacheEntryReader { disk_cache, index, cache_key, move(url), move(path), move(file), fd, cache_header, move(reason_phrase), move(response_headers), data_offset, data_size });
254253
}
255254

256-
CacheEntryReader::CacheEntryReader(DiskCache& disk_cache, CacheIndex& index, u64 cache_key, String url, LexicalPath path, NonnullOwnPtr<Core::File> file, int fd, CacheHeader cache_header, Optional<String> reason_phrase, NonnullRefPtr<HTTP::HeaderList> response_headers, u64 data_offset, u64 data_size)
255+
CacheEntryReader::CacheEntryReader(DiskCache& disk_cache, CacheIndex& index, u64 cache_key, String url, LexicalPath path, NonnullOwnPtr<Core::File> file, int fd, CacheHeader cache_header, Optional<String> reason_phrase, NonnullRefPtr<HeaderList> response_headers, u64 data_offset, u64 data_size)
257256
: CacheEntry(disk_cache, index, cache_key, move(url), move(path), cache_header)
258257
, m_file(move(file))
259258
, m_fd(fd)
@@ -264,7 +263,7 @@ CacheEntryReader::CacheEntryReader(DiskCache& disk_cache, CacheIndex& index, u64
264263
{
265264
}
266265

267-
void CacheEntryReader::revalidation_succeeded(HTTP::HeaderList const& response_headers)
266+
void CacheEntryReader::revalidation_succeeded(HeaderList const& response_headers)
268267
{
269268
dbgln("\033[34;1mCache revalidation succeeded for\033[0m {}", m_url);
270269

Services/RequestServer/Cache/CacheEntry.h renamed to Libraries/LibHTTP/Cache/CacheEntry.h

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@
1313
#include <AK/Time.h>
1414
#include <AK/Types.h>
1515
#include <LibCore/File.h>
16+
#include <LibCore/Notifier.h>
17+
#include <LibHTTP/Cache/Version.h>
18+
#include <LibHTTP/Forward.h>
1619
#include <LibHTTP/HeaderList.h>
17-
#include <RequestServer/Cache/Version.h>
18-
#include <RequestServer/Forward.h>
1920

20-
namespace RequestServer {
21+
namespace HTTP {
2122

2223
struct CacheHeader {
2324
static ErrorOr<CacheHeader> read_from_stream(Stream&);
@@ -87,9 +88,9 @@ class CacheEntryWriter : public CacheEntry {
8788
static ErrorOr<NonnullOwnPtr<CacheEntryWriter>> create(DiskCache&, CacheIndex&, u64 cache_key, String url, UnixDateTime request_time, AK::Duration current_time_offset_for_testing);
8889
virtual ~CacheEntryWriter() override = default;
8990

90-
ErrorOr<void> write_status_and_reason(u32 status_code, Optional<String> reason_phrase, HTTP::HeaderList const&);
91+
ErrorOr<void> write_status_and_reason(u32 status_code, Optional<String> reason_phrase, HeaderList const&);
9192
ErrorOr<void> write_data(ReadonlyBytes);
92-
ErrorOr<void> flush(NonnullRefPtr<HTTP::HeaderList>);
93+
ErrorOr<void> flush(NonnullRefPtr<HeaderList>);
9394

9495
private:
9596
CacheEntryWriter(DiskCache&, CacheIndex&, u64 cache_key, String url, LexicalPath, NonnullOwnPtr<Core::OutputBufferedFile>, CacheHeader, UnixDateTime request_time, AK::Duration current_time_offset_for_testing);
@@ -104,24 +105,24 @@ class CacheEntryWriter : public CacheEntry {
104105

105106
class CacheEntryReader : public CacheEntry {
106107
public:
107-
static ErrorOr<NonnullOwnPtr<CacheEntryReader>> create(DiskCache&, CacheIndex&, u64 cache_key, NonnullRefPtr<HTTP::HeaderList>, u64 data_size);
108+
static ErrorOr<NonnullOwnPtr<CacheEntryReader>> create(DiskCache&, CacheIndex&, u64 cache_key, NonnullRefPtr<HeaderList>, u64 data_size);
108109
virtual ~CacheEntryReader() override = default;
109110

110111
bool must_revalidate() const { return m_must_revalidate; }
111112
void set_must_revalidate() { m_must_revalidate = true; }
112113

113-
void revalidation_succeeded(HTTP::HeaderList const&);
114+
void revalidation_succeeded(HeaderList const&);
114115
void revalidation_failed();
115116

116117
void pipe_to(int pipe_fd, Function<void(u64 bytes_piped)> on_complete, Function<void(u64 bytes_piped)> on_error);
117118

118119
u32 status_code() const { return m_cache_header.status_code; }
119120
Optional<String> const& reason_phrase() const { return m_reason_phrase; }
120-
HTTP::HeaderList& response_headers() { return m_response_headers; }
121-
HTTP::HeaderList const& response_headers() const { return m_response_headers; }
121+
HeaderList& response_headers() { return m_response_headers; }
122+
HeaderList const& response_headers() const { return m_response_headers; }
122123

123124
private:
124-
CacheEntryReader(DiskCache&, CacheIndex&, u64 cache_key, String url, LexicalPath, NonnullOwnPtr<Core::File>, int fd, CacheHeader, Optional<String> reason_phrase, NonnullRefPtr<HTTP::HeaderList>, u64 data_offset, u64 data_size);
125+
CacheEntryReader(DiskCache&, CacheIndex&, u64 cache_key, String url, LexicalPath, NonnullOwnPtr<Core::File>, int fd, CacheHeader, Optional<String> reason_phrase, NonnullRefPtr<HeaderList>, u64 data_offset, u64 data_size);
125126

126127
void pipe_without_blocking();
127128
void pipe_complete();
@@ -140,7 +141,7 @@ class CacheEntryReader : public CacheEntry {
140141
u64 m_bytes_piped { 0 };
141142

142143
Optional<String> m_reason_phrase;
143-
NonnullRefPtr<HTTP::HeaderList> m_response_headers;
144+
NonnullRefPtr<HeaderList> m_response_headers;
144145

145146
bool m_must_revalidate { false };
146147

Services/RequestServer/Cache/CacheIndex.cpp renamed to Libraries/LibHTTP/Cache/CacheIndex.cpp

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@
55
*/
66

77
#include <AK/StringBuilder.h>
8-
#include <RequestServer/Cache/CacheIndex.h>
9-
#include <RequestServer/Cache/Utilities.h>
10-
#include <RequestServer/Cache/Version.h>
8+
#include <LibHTTP/Cache/CacheIndex.h>
9+
#include <LibHTTP/Cache/Utilities.h>
10+
#include <LibHTTP/Cache/Version.h>
1111

12-
namespace RequestServer {
12+
namespace HTTP {
1313

1414
static constexpr u32 CACHE_METADATA_KEY = 12389u;
1515

16-
static ByteString serialize_headers(HTTP::HeaderList const& headers)
16+
static ByteString serialize_headers(HeaderList const& headers)
1717
{
1818
StringBuilder builder;
1919

@@ -27,9 +27,9 @@ static ByteString serialize_headers(HTTP::HeaderList const& headers)
2727
return builder.to_byte_string();
2828
}
2929

30-
static NonnullRefPtr<HTTP::HeaderList> deserialize_headers(StringView serialized_headers)
30+
static NonnullRefPtr<HeaderList> deserialize_headers(StringView serialized_headers)
3131
{
32-
auto headers = HTTP::HeaderList::create();
32+
auto headers = HeaderList::create();
3333

3434
serialized_headers.for_each_split_view('\n', SplitBehavior::Nothing, [&](StringView serialized_header) {
3535
auto index = serialized_header.find(':');
@@ -110,7 +110,7 @@ CacheIndex::CacheIndex(Database::Database& database, Statements statements)
110110
{
111111
}
112112

113-
void CacheIndex::create_entry(u64 cache_key, String url, NonnullRefPtr<HTTP::HeaderList> response_headers, u64 data_size, UnixDateTime request_time, UnixDateTime response_time)
113+
void CacheIndex::create_entry(u64 cache_key, String url, NonnullRefPtr<HeaderList> response_headers, u64 data_size, UnixDateTime request_time, UnixDateTime response_time)
114114
{
115115
auto now = UnixDateTime::now();
116116

@@ -133,36 +133,36 @@ void CacheIndex::create_entry(u64 cache_key, String url, NonnullRefPtr<HTTP::Hea
133133
.last_access_time = now,
134134
};
135135

136-
m_database.execute_statement(m_statements.insert_entry, {}, entry.cache_key, entry.url, serialize_headers(entry.response_headers), entry.data_size, entry.request_time, entry.response_time, entry.last_access_time);
136+
m_database->execute_statement(m_statements.insert_entry, {}, entry.cache_key, entry.url, serialize_headers(entry.response_headers), entry.data_size, entry.request_time, entry.response_time, entry.last_access_time);
137137
m_entries.set(cache_key, move(entry));
138138
}
139139

140140
void CacheIndex::remove_entry(u64 cache_key)
141141
{
142-
m_database.execute_statement(m_statements.remove_entry, {}, cache_key);
142+
m_database->execute_statement(m_statements.remove_entry, {}, cache_key);
143143
m_entries.remove(cache_key);
144144
}
145145

146146
void CacheIndex::remove_entries_accessed_since(UnixDateTime since, Function<void(u64 cache_key)> on_entry_removed)
147147
{
148-
m_database.execute_statement(
148+
m_database->execute_statement(
149149
m_statements.remove_entries_accessed_since,
150150
[&](auto statement_id) {
151-
auto cache_key = m_database.result_column<u64>(statement_id, 0);
151+
auto cache_key = m_database->result_column<u64>(statement_id, 0);
152152
m_entries.remove(cache_key);
153153

154154
on_entry_removed(cache_key);
155155
},
156156
since);
157157
}
158158

159-
void CacheIndex::update_response_headers(u64 cache_key, NonnullRefPtr<HTTP::HeaderList> response_headers)
159+
void CacheIndex::update_response_headers(u64 cache_key, NonnullRefPtr<HeaderList> response_headers)
160160
{
161161
auto entry = m_entries.get(cache_key);
162162
if (!entry.has_value())
163163
return;
164164

165-
m_database.execute_statement(m_statements.update_response_headers, {}, serialize_headers(response_headers), cache_key);
165+
m_database->execute_statement(m_statements.update_response_headers, {}, serialize_headers(response_headers), cache_key);
166166
entry->response_headers = move(response_headers);
167167
}
168168

@@ -174,7 +174,7 @@ void CacheIndex::update_last_access_time(u64 cache_key)
174174

175175
auto now = UnixDateTime::now();
176176

177-
m_database.execute_statement(m_statements.update_last_access_time, {}, now, cache_key);
177+
m_database->execute_statement(m_statements.update_last_access_time, {}, now, cache_key);
178178
entry->last_access_time = now;
179179
}
180180

@@ -183,17 +183,17 @@ Optional<CacheIndex::Entry&> CacheIndex::find_entry(u64 cache_key)
183183
if (auto entry = m_entries.get(cache_key); entry.has_value())
184184
return entry;
185185

186-
m_database.execute_statement(
186+
m_database->execute_statement(
187187
m_statements.select_entry, [&](auto statement_id) {
188188
int column = 0;
189189

190-
auto cache_key = m_database.result_column<u64>(statement_id, column++);
191-
auto url = m_database.result_column<String>(statement_id, column++);
192-
auto response_headers = m_database.result_column<ByteString>(statement_id, column++);
193-
auto data_size = m_database.result_column<u64>(statement_id, column++);
194-
auto request_time = m_database.result_column<UnixDateTime>(statement_id, column++);
195-
auto response_time = m_database.result_column<UnixDateTime>(statement_id, column++);
196-
auto last_access_time = m_database.result_column<UnixDateTime>(statement_id, column++);
190+
auto cache_key = m_database->result_column<u64>(statement_id, column++);
191+
auto url = m_database->result_column<String>(statement_id, column++);
192+
auto response_headers = m_database->result_column<ByteString>(statement_id, column++);
193+
auto data_size = m_database->result_column<u64>(statement_id, column++);
194+
auto request_time = m_database->result_column<UnixDateTime>(statement_id, column++);
195+
auto response_time = m_database->result_column<UnixDateTime>(statement_id, column++);
196+
auto last_access_time = m_database->result_column<UnixDateTime>(statement_id, column++);
197197

198198
Entry entry { cache_key, move(url), deserialize_headers(response_headers), data_size, request_time, response_time, last_access_time };
199199
m_entries.set(cache_key, move(entry));
@@ -203,18 +203,18 @@ Optional<CacheIndex::Entry&> CacheIndex::find_entry(u64 cache_key)
203203
return m_entries.get(cache_key);
204204
}
205205

206-
Requests::CacheSizes CacheIndex::estimate_cache_size_accessed_since(UnixDateTime since) const
206+
Requests::CacheSizes CacheIndex::estimate_cache_size_accessed_since(UnixDateTime since)
207207
{
208208
Requests::CacheSizes sizes;
209209

210-
m_database.execute_statement(
210+
m_database->execute_statement(
211211
m_statements.estimate_cache_size_accessed_since,
212-
[&](auto statement_id) { sizes.since_requested_time = m_database.result_column<u64>(statement_id, 0); },
212+
[&](auto statement_id) { sizes.since_requested_time = m_database->result_column<u64>(statement_id, 0); },
213213
since);
214214

215-
m_database.execute_statement(
215+
m_database->execute_statement(
216216
m_statements.estimate_cache_size_accessed_since,
217-
[&](auto statement_id) { sizes.total = m_database.result_column<u64>(statement_id, 0); },
217+
[&](auto statement_id) { sizes.total = m_database->result_column<u64>(statement_id, 0); },
218218
UnixDateTime::earliest());
219219

220220
return sizes;

Services/RequestServer/Cache/CacheIndex.h renamed to Libraries/LibHTTP/Cache/CacheIndex.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@
88

99
#include <AK/Error.h>
1010
#include <AK/HashMap.h>
11+
#include <AK/NonnullRawPtr.h>
1112
#include <AK/Time.h>
1213
#include <AK/Types.h>
1314
#include <LibDatabase/Database.h>
1415
#include <LibHTTP/HeaderList.h>
1516
#include <LibRequests/CacheSizes.h>
1617

17-
namespace RequestServer {
18+
namespace HTTP {
1819

1920
// The cache index is a SQL database containing metadata about each cache entry. An entry in the index is created once
2021
// the entire cache entry has been successfully written to disk.
@@ -23,7 +24,7 @@ class CacheIndex {
2324
u64 cache_key { 0 };
2425

2526
String url;
26-
NonnullRefPtr<HTTP::HeaderList> response_headers;
27+
NonnullRefPtr<HeaderList> response_headers;
2728
u64 data_size { 0 };
2829

2930
UnixDateTime request_time;
@@ -34,16 +35,16 @@ class CacheIndex {
3435
public:
3536
static ErrorOr<CacheIndex> create(Database::Database&);
3637

37-
void create_entry(u64 cache_key, String url, NonnullRefPtr<HTTP::HeaderList>, u64 data_size, UnixDateTime request_time, UnixDateTime response_time);
38+
void create_entry(u64 cache_key, String url, NonnullRefPtr<HeaderList>, u64 data_size, UnixDateTime request_time, UnixDateTime response_time);
3839
void remove_entry(u64 cache_key);
3940
void remove_entries_accessed_since(UnixDateTime, Function<void(u64 cache_key)> on_entry_removed);
4041

4142
Optional<Entry&> find_entry(u64 cache_key);
4243

43-
void update_response_headers(u64 cache_key, NonnullRefPtr<HTTP::HeaderList>);
44+
void update_response_headers(u64 cache_key, NonnullRefPtr<HeaderList>);
4445
void update_last_access_time(u64 cache_key);
4546

46-
Requests::CacheSizes estimate_cache_size_accessed_since(UnixDateTime since) const;
47+
Requests::CacheSizes estimate_cache_size_accessed_since(UnixDateTime since);
4748

4849
private:
4950
struct Statements {
@@ -58,7 +59,7 @@ class CacheIndex {
5859

5960
CacheIndex(Database::Database&, Statements);
6061

61-
Database::Database& m_database;
62+
NonnullRawPtr<Database::Database> m_database;
6263
Statements m_statements;
6364

6465
HashMap<u32, Entry> m_entries;
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright (c) 2025, Tim Flynn <trflynn89@ladybird.org>
3+
*
4+
* SPDX-License-Identifier: BSD-2-Clause
5+
*/
6+
7+
#pragma once
8+
9+
#include <AK/Badge.h>
10+
#include <AK/Optional.h>
11+
#include <AK/Weakable.h>
12+
#include <LibHTTP/Forward.h>
13+
14+
namespace HTTP {
15+
16+
class CacheRequest : public Weakable<CacheRequest> {
17+
public:
18+
virtual ~CacheRequest() = default;
19+
20+
virtual void notify_request_unblocked(Badge<DiskCache>) = 0;
21+
22+
protected:
23+
enum class CacheStatus : u8 {
24+
Unknown,
25+
NotCached,
26+
WrittenToCache,
27+
ReadFromCache,
28+
};
29+
30+
Optional<CacheEntryReader&> m_cache_entry_reader;
31+
Optional<CacheEntryWriter&> m_cache_entry_writer;
32+
CacheStatus m_cache_status { CacheStatus::Unknown };
33+
};
34+
35+
}

0 commit comments

Comments
 (0)