Skip to content

Sqlite Cache Backend - #2631

Open
mookums wants to merge 22 commits into
mainfrom
sqlite-cache
Open

Sqlite Cache Backend#2631
mookums wants to merge 22 commits into
mainfrom
sqlite-cache

Conversation

@mookums

@mookums mookums commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

This is a new SQLite backend for the Cache. This is built off of the Cache Revalidation PR (#2570)

@mookums
mookums marked this pull request as ready for review June 22, 2026 14:14
Comment thread src/network/cache/Cache.zig Outdated
Comment thread src/network/Network.zig Outdated
.{trimmed_dir},
0,
);
defer allocator.free(cache_path);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about moving this logic into config directly? We could create something like config.httpCacheSqlitePath() returning an nullable path name? I would remove this code from Network which is not really its place and maybe allow us to have a config flag to customize this path.

Comment thread src/storage/sqlite/Sqlite.zig Outdated
Comment thread src/storage/sqlite/Sqlite.zig Outdated
Comment thread src/storage/sqlite/Sqlite.zig Outdated
Comment thread src/network/Network.zig
.path = cache_path,
.err = e,
});
return e;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we could show an error + disable the cache in case of error to avoid process hard stop?
but I'm not sure it's a good thing 🤔

Comment thread src/network/cache/SqliteCache.zig Outdated
const body_entry = try conn.row(
"select data from body where url = $1",
.{url},
) orelse @panic("valid metadata must have a body");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

idk about that one. I would prefer logging an error and return a null body instead.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about assert then to get the crash report at least?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this comment has not been addressed AFAIK


var lower_name: [256]u8 = undefined;
for (meta.headers) |h| {
const name = std.ascii.lowerString(lower_name[0..h.name.len], h.name);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we handle h.name.len > 256 ?

);
}
for (meta.vary_headers) |h| {
const name = std.ascii.lowerString(lower_name[0..h.name.len], h.name);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same about h.name length

Comment thread src/storage/sqlite/Sqlite.zig Outdated
self.pool.deinit(allocator);
}

pub fn Migrations(comptime migrations: []const [:0]const u8) type {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we keep src/storage/sqlite/migrations.zig?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I see the reason for this to be a generic, nor what the hash provides. What case does the hash protect against? The DB getting corrupted? The developer (us) making a build-time mistake? Also, it isn't cryptographic, so whatever it does, it only does sometimes.

It might not matter for a small/simple DB schema, but I think migrations should be code, not text. There are some migrations that simply require pulling data into code.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We no longer track hash and we also support either just SQL or code as the migration.

@krichprollsch

krichprollsch commented Jun 23, 2026

Copy link
Copy Markdown
Member

This is nice to be able to use duckdb CLI to explore the cache data :)

cache D select * from metadata where must_revalidate != 0;
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬────────┬────────────┬──────────────┬─────────┬─────────────────┬──────────────────────────────────────┬───────────────────────────────┐
│                                                         url                                                         │ status │ stored_at  │ age_at_store │ max_age │ must_revalidate │                 etag                 │         last_modified         │
│                                                       varchar                                                       │ int64  │   int64    │    int64     │  int64  │      int64      │               varchar                │            varchar            │
├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼────────┼────────────┼──────────────┼─────────┼─────────────────┼──────────────────────────────────────┼───────────────────────────────┤
│ https://improving.duckduckgo.com/t/page_home_tagline_impression?2117232&b=unknown&d=d&l=en&p=other                  │    200 │ 1782224467 │            0 │       0 │               1 │ NULL                                 │ Mon, 28 Sep 1970 06:00:00 GMT │
│ https://improving.duckduckgo.com/t/page_home_searchbox_ai_impression?3479694&b=unknown&d=d&l=en&p=other&atb=v539-7… │    200 │ 1782224467 │            0 │       0 │               1 │ NULL                                 │ Mon, 28 Sep 1970 06:00:00 GMT │
│ https://improving.duckduckgo.com/t/page_home_impression?8744613&theme=light&b=unknown&d=d&l=en&p=other&atb=v539-7&… │    200 │ 1782224467 │            0 │       0 │               1 │ NULL                                 │ Mon, 28 Sep 1970 06:00:00 GMT │
│ https://duckduckgo.com/t.js?q=lightpanda&l=us-en&p=1&s=0&dl=en&ct=FR&bing_market=en-US&p_ent=&dp=xXvfRl5mggeuTWh4h… │    200 │ 1782224476 │            0 │       0 │               1 │ NULL                                 │ NULL                          │
│ https://hn.algolia.com/public/main-6e634771f729331a3c3c.js                                                          │    200 │ 1782226454 │            0 │       0 │               1 │ "1755549896.0-2608202-407047307"     │ Mon, 18 Aug 2025 20:44:56 GMT │
│ https://js.driftt.com/include/1782224700000/6nmy7z65gsxc.js                                                         │    200 │ 1782224599 │            0 │       0 │               1 │ W/"d45d26b9900d0bece786bd59b23c5006" │ Thu, 26 Mar 2026 08:37:12 GMT │
│ https://config.gorgias.chat/gorgias-chat-bundle-loader.js?applicationId=15954                                       │    200 │ 1782226616 │         3537 │       0 │               1 │ W/"71a-vOzeu8cLY+IjFLWstPX9XvL10zs"  │ NULL                          │
│ https://www.googleadservices.com/pagead/conversion/971805850/?random=1782224689183&cv=11&fst=1782224689183&fmt=7&b… │    200 │ 1782224690 │            0 │       0 │               1 │ NULL                                 │ NULL                          │
│ https://config.gorgias.chat/bundle-loader/01GYCCC51FF4CA6RW7XJH50SCK?source=shopify1click&shop=kit-and-ace.myshopi… │    200 │ 1782226638 │         3557 │       0 │               1 │ W/"74d-X+O5AqWK9m1LWrn+UvfhH5u8pSY"  │ NULL                          │
│ https://www.googleadservices.com/pagead/conversion/971805850/?random=1782224718058&cv=11&fst=1782224718058&fmt=7&b… │    200 │ 1782224719 │            0 │       0 │               1 │ NULL                                 │ NULL                          │
│ https://www.googleadservices.com/pagead/conversion/971805850/?random=1782224718143&cv=11&fst=1782224718143&fmt=7&b… │    200 │ 1782224720 │            0 │       0 │               1 │ NULL                                 │ NULL                          │
│ https://www.googleadservices.com/pagead/conversion/971805850/?random=1782224755238&cv=11&fst=1782224755238&fmt=7&b… │    200 │ 1782224756 │            0 │       0 │               1 │ NULL                                 │ NULL                          │
│ https://www.googleadservices.com/pagead/conversion/971805850/?random=1782224755314&cv=11&fst=1782224755314&fmt=7&b… │    200 │ 1782224756 │            0 │       0 │               1 │ NULL                                 │ NULL                          │
│ https://improving.duckduckgo.com/t/page_home_tagline_impression?9740447&b=unknown&d=d&l=en&p=other                  │    200 │ 1782225829 │            0 │       0 │               1 │ NULL                                 │ Mon, 28 Sep 1970 06:00:00 GMT │
│ https://improving.duckduckgo.com/t/page_home_searchbox_ai_impression?5392774&b=unknown&d=d&l=en&p=other&atb=v539-7… │    200 │ 1782225829 │            0 │       0 │               1 │ NULL                                 │ Mon, 28 Sep 1970 06:00:00 GMT │
│ https://improving.duckduckgo.com/t/page_home_impression?1190434&theme=light&b=unknown&d=d&l=en&p=other&atb=v539-7&… │    200 │ 1782225829 │            0 │       0 │               1 │ NULL                                 │ Mon, 28 Sep 1970 06:00:00 GMT │
│ https://improving.duckduckgo.com/t/page_home_tagline_impression?8429873&b=unknown&d=d&l=en&p=other                  │    200 │ 1782226412 │            0 │       0 │               1 │ NULL                                 │ Mon, 28 Sep 1970 06:00:00 GMT │
│ https://improving.duckduckgo.com/t/page_home_searchbox_ai_impression?9690011&b=unknown&d=d&l=en&p=other&atb=v539-7… │    200 │ 1782226412 │            0 │       0 │               1 │ NULL                                 │ Mon, 28 Sep 1970 06:00:00 GMT │
│ https://duckduckgo.com                                                                                              │    200 │ 1782226421 │            0 │       0 │               1 │ "6a3a9d36-9c21"                      │ NULL                          │
│ https://improving.duckduckgo.com/t/page_home_tagline_impression?7683633&b=unknown&d=d&l=en&p=other                  │    200 │ 1782226424 │            0 │       0 │               1 │ NULL                                 │ Mon, 28 Sep 1970 06:00:00 GMT │
│ https://improving.duckduckgo.com/t/page_home_searchbox_ai_impression?8002091&b=unknown&d=d&l=en&p=other&atb=v539-7… │    200 │ 1782226424 │            0 │       0 │               1 │ NULL                                 │ Mon, 28 Sep 1970 06:00:00 GMT │
│ https://improving.duckduckgo.com/t/page_home_impression?585745&theme=light&b=unknown&d=d&l=en&p=other&atb=v539-7&p… │    200 │ 1782226424 │            0 │       0 │               1 │ NULL                                 │ Mon, 28 Sep 1970 06:00:00 GMT │
│ https://duckduckgo.com/ac/?q=light&kl=wt-wt&vertical=homepage                                                       │    200 │ 1782226427 │            0 │       0 │               1 │ NULL                                 │ NULL                          │
│ https://duckduckgo.com/ac/?q=lightp&kl=wt-wt&vertical=homepage                                                      │    200 │ 1782226427 │            0 │       0 │               1 │ NULL                                 │ NULL                          │
│ https://duckduckgo.com/ac/?q=lightpa&kl=wt-wt&vertical=homepage                                                     │    200 │ 1782226428 │            0 │       0 │               1 │ NULL                                 │ NULL                          │
│ https://duckduckgo.com/ac/?q=lightpan&kl=wt-wt&vertical=homepage                                                    │    200 │ 1782226428 │            0 │       0 │               1 │ NULL                                 │ NULL                          │
│ https://duckduckgo.com/ac/?q=lightpand&kl=wt-wt&vertical=homepage                                                   │    200 │ 1782226429 │            0 │       0 │               1 │ NULL                                 │ NULL                          │
│ https://duckduckgo.com/ac/?q=lightpanda&kl=wt-wt&vertical=homepage                                                  │    200 │ 1782226429 │            0 │       0 │               1 │ NULL                                 │ NULL                          │
│ https://duckduckgo.com/t.js?q=lightpanda&l=us-en&s=0&dl=en&ct=FR&bing_market=en-US&p_ent=&ex=-1&dp=J9gRog2IaKXlQqQ… │    200 │ 1782226432 │            0 │       0 │               1 │ NULL                                 │ NULL                          │
│ https://duckduckgo.com/post3.html                                                                                   │    200 │ 1782226432 │            0 │       0 │               1 │ "6a3a9d69-88"                        │ NULL                          │
│ https://www.amazon.com/s/ref=nb_sb_noss?url=search-alias%3Daps&field-keywords=ces+jours+qui+disparaissent           │    200 │ 1782226530 │            0 │       0 │               1 │ NULL                                 │ NULL                          │
│ https://js.driftt.com/include/1782226800000/6nmy7z65gsxc.js                                                         │    200 │ 1782226539 │            0 │       0 │               1 │ W/"d45d26b9900d0bece786bd59b23c5006" │ Thu, 26 Mar 2026 08:37:12 GMT │
│ https://www.googleadservices.com/pagead/conversion/971805850/?random=1782226623304&cv=11&fst=1782226623304&fmt=7&b… │    200 │ 1782226624 │            0 │       0 │               1 │ NULL                                 │ NULL                          │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴────────┴────────────┴──────────────┴─────────┴─────────────────┴──────────────────────────────────────┴───────────────────────────────┘
  33 rows


const SqliteCacheMigrations = Migrations(&.{
\\ create table metadata (
\\ url text not null primary key,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if using the same hash as migration as primary key wouldn't be better?

Comment thread src/network/Network.zig Outdated

const cache = if (config.httpCacheDir()) |cache_dir_path|
Cache{
const cache = if (config.httpCacheDir()) |cache_dir_path| blk: {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think there should be this much caching logic in Network.zig.

Comment thread src/storage/sqlite/Sqlite.zig Outdated
self.pool.deinit(allocator);
}

pub fn Migrations(comptime migrations: []const [:0]const u8) type {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I see the reason for this to be a generic, nor what the hash provides. What case does the hash protect against? The DB getting corrupted? The developer (us) making a build-time mistake? Also, it isn't cryptographic, so whatever it does, it only does sometimes.

It might not matter for a small/simple DB schema, but I think migrations should be code, not text. There are some migrations that simply require pulling data into code.

\\ foreign key (url) references metadata(url) on delete cascade
\\ )
,
\\ create table header (

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about:

create table cache (
  url text not null primary key,
  vary bool not null,
  response text not null,
  body blob not null
)

Only url and varyare queried. response can be a JSON representation of the cache. body is extracted from response to avoid the base64 bloating of any binary data.

@krichprollsch

Copy link
Copy Markdown
Member

If we want to cleanup the db at some point, for example to reduce its size, do we have an SQL request to do it easily?

@krichprollsch

Copy link
Copy Markdown
Member

I had a crash with integration tests + warmup cache (and a rebased branch)

Segmentation fault at address 0x77bc847ab930
/home/pierre/wrk/browser-claude/src/network/cache/Cache.zig:218:42: 0x47343c9 in deinit (lightpanda)
    pub fn deinit(self: CachedData) void {
                                         ^
/home/pierre/wrk/browser-claude/src/network/layer/CacheLayer.zig:203:29: 0x481d669 in serveFromCache (lightpanda)
    defer cached.data.deinit();
                            ^
/home/pierre/wrk/browser-claude/src/network/layer/CacheLayer.zig:84:35: 0x4733cee in run (lightpanda)
                    serveFromCache(t, c) catch |err| {
                                  ^
/home/pierre/wrk/browser-claude/src/browser/HttpClient.zig:508:16: 0x38218ff in drainNextTickQueue (lightpanda)
        ntn.run(transfer, ntn.ctx);
               ^
/home/pierre/wrk/browser-claude/src/browser/HttpClient.zig:456:32: 0x38229ab in tick (lightpanda)
    try self.drainNextTickQueue();
                               ^
/home/pierre/wrk/browser-claude/src/browser/Runner.zig:302:29: 0x44afd00 in _tick__anon_516032 (lightpanda)
        try http_client.tick(@intCast(ms_to_wait), .all);
                            ^
/home/pierre/wrk/browser-claude/src/browser/Runner.zig:150:39: 0x44b00a2 in _wait__anon_516026 (lightpanda)
        const tick_result = self._tick(is_cdp, 200, conditions) catch |err| {
                                      ^
/home/pierre/wrk/browser-claude/src/browser/Runner.zig:75:23: 0x44b050b in waitForFrameCDP (lightpanda)
    _ = try self._wait(true, timeout_ms, &conditions);
                      ^
/home/pierre/wrk/browser-claude/src/cdp/CDP.zig:269:34: 0x44b0685 in pageWait (lightpanda)
    return runner.waitForFrameCDP(page.frame_id, ms, .done);
                                 ^
/home/pierre/wrk/browser-claude/src/cdp/CDP.zig:246:18: 0x44b077b in tick (lightpanda)
    self.pageWait(wait_ms) catch |wait_err| switch (wait_err) {
                 ^
/home/pierre/wrk/browser-claude/src/Server.zig:259:30: 0x435828d in handleConnection (lightpanda)
        const next = cdp.tick() catch |err| {
                             ^
/usr/local/zig-0.15.2/lib/std/Thread.zig:509:13: 0x41f4890 in callFn__anon_441681 (lightpanda)
            @call(.auto, f, args);
            ^
/usr/local/zig-0.15.2/lib/std/Thread.zig:781:30: 0x40e1cc3 in entryFn (lightpanda)
                return callFn(f, args_ptr.*);
                             ^
./nptl/pthread_create.c:447:8: 0x77bd0d69caa3 in start_thread (pthread_create.c)
../sysdeps/unix/sysv/linux/x86_64/clone3.S:78:0: 0x77bd0d729c6b in __clone3 (../sysdeps/unix/sysv/linux/x86_64/clone3.S)
???:?:?: 0x0 in ??? (???)
run
└─ run exe lightpanda failure
error: the following command terminated unexpectedly:
./.zig-cache/o/cdeffea3ddf78e9d9796e5606def3d0f/lightpanda serve --http-cache-dir /tmp/lp-cache

Build Summary: 30/32 steps succeeded; 1 failed
run transitive failure
└─ run exe lightpanda failure

error: the following build command failed with exit code 1:
.zig-cache/o/d20cc142e18b434fc8b7b6f062898d2d/build /usr/local/zig-0.15.2/zig /usr/local/zig-0.15.2/lib /home/pierre/wrk/browser-claude .zig-cache /home/pierre/.cache/zig --seed 0x8ae37990 -Zc4c25bdb8f119cba run -- serve --http-cache-dir /tmp/lp-cache

@mookums
mookums force-pushed the sqlite-cache branch 2 times, most recently from 8413ec9 to 470f713 Compare July 3, 2026 15:12
@mookums
mookums force-pushed the sqlite-cache branch 5 times, most recently from 09b854f to fffa038 Compare July 20, 2026 13:44
Comment thread src/network/cache/SqliteCache.zig Outdated
const body_entry = try conn.row(
"select data from body where url = $1",
.{url},
) orelse @panic("valid metadata must have a body");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this comment has not been addressed AFAIK

Comment thread src/network/cache/SqliteCache.zig Outdated
\\ name text not null,
\\ value text not null,
\\ vary bool not null,
\\ primary key (url, name),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using url + header name as PK is a problem for response containing the same header multiple time.

Comment thread src/network/HttpClient.zig Outdated
const req_headers = try iter.collect(arena);

const cached = cache.get(arena, .{
const cached = try cache.get(arena, .{

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should maybe catch the error and return a missing cache + a log instead of propagating the error.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We catch where it would be missing and handle that separately within the SqliteCache impll. The error being propagated here would be something going wrong with Sqlite.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which still isn't a reason to fail the request

Comment thread src/Config.zig Outdated
Comment thread src/Config.zig Outdated
Comment thread src/network/cache/SqliteCache.zig Outdated

fn insertMetadata(conn: Conn, meta: CachedMetadata, body: []const u8) !void {
try conn.exec(
\\ insert or replace into metadata

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude complaints the FK w/ headers depends on pragma foreign_keys=on conn:

 4. put correctness rests on an implicit REPLACE→FK-cascade interaction. insert or replace
  into metadata (:173) only clears the old body/header rows if pragma foreign_keys=on took
  effect on that connection; otherwise the plain insert into body (:188) hits a PK
  conflict. Make it explicit — delete from metadata where url = $1 first — rather than
  depending on a subtle corner of SQLite semantics.

@karlseguin

karlseguin commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

On an expired cache hit, we pull the meta data (dupe from sqlite), pull the body (dupe from sqlite), then detect that it's expired and free everything. Because it's an arena, this may or may not be freed, so in the end we're 2x peak memory (the expired body we discarded + the new body we fetch).

This is just the most extreme example, but there are others:
1 - Same applies to header as applies to body
2 - No need to collect the request headers if the URL isn't even in the DB
3 - I don' think there's ever a need to dupe the metadata
4 - renew in particular doesn't need to fetch the metadata (with duping) just to update the row

I think there's a few more. There's a hint of more tightly coupled and more efficient code with the early exit around 'vary mismatch', but even this has duped every header by the time it's checked.

Aside from that, there's still some unused .file references and renew does a select, followed by update within the same transaction. This is a recipe for an BUSY error. Should probably use begin immediate

Comment thread src/network/cache/SqliteCache.zig Outdated
Comment thread src/network/cache/SqliteCache.zig Outdated
Comment thread src/network/cache/SqliteCache.zig
Comment thread src/network/HttpClient.zig Outdated
const req_headers = try iter.collect(arena);

const cached = cache.get(arena, .{
const cached = try cache.get(arena, .{

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which still isn't a reason to fail the request

Comment thread src/network/cache/SqliteCache.zig Outdated
const conn = try self.pool.acquire();
defer self.pool.release(conn);

try conn.begin(.immediate);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Serializes all all cache access. In renew, it made sense because you always turned it into an write (and, ideally, writes are less common than reads). Here, the write is the edge-case. It's better to commit the expired read, and then issue the write under a distinct transaction. You can guard against another thread updating the row by changing the delete to included stored_at = $2 and passing the read stored_at.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just split it back to how it was where get is meant just to get and it now returns an enum where we evict after if needed.

Comment thread src/network/cache/SqliteCache.zig Outdated
"select data from body where url = $1",
.{req.url},
) orelse {
log.debug(.cache, "miss", .{ .url = req.url, .reason = "missing body " });

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But the metadata row remains. This makes my previous comment about using a more concurrent-friendly transaction more complicated to implement (since deleting the metadata here would introduce a 2nd (but still very infrequent, write path). Still possible to clean this up AND have tighter transactions, but not if that end result ends up too spaghetti.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merged the body into the other row so they're just colocated together now. This should prevent this issue of one existing while the other doesn't.

Comment thread src/Config.zig Outdated
Comment thread src/network/cache/SqliteCache.zig Outdated
@mookums
mookums force-pushed the sqlite-cache branch 2 times, most recently from a28a026 to 246aa9e Compare July 23, 2026 19:33
@mookums

mookums commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

Will fail integration tests until #3044 is merged.

mookums and others added 5 commits July 31, 2026 16:27
Huge max-age/Age header values previously either panicked in the
i64 casts when storing metadata, or were silently truncated to their
first 8 digits by the fixed-size lowercase buffer in
CacheControl.parse. Cap them at 2^31 as RFC 9111 §1.2.2 prescribes
and compare directives case-insensitively without truncation.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants