add basic caching support

This commit is contained in:
Muki Kiboigo
2026-03-19 18:59:46 -07:00
parent 5213287f38
commit 00e0c22a76

View File

@@ -292,7 +292,62 @@ pub fn request(self: *Client, req: Request) !void {
return self.fetchRobotsThenProcessRequest(robots_url, req);
}
fn serveFromCache(allocator: std.mem.Allocator, req: Request, cached: *const CachedResponse) !void {
const response = Response.fromCached(req.ctx, cached);
defer cached.metadata.deinit(allocator);
if (req.start_callback) |cb| {
try cb(response);
}
const proceed = try req.header_callback(response);
if (!proceed) {
req.error_callback(req.ctx, error.Abort);
return;
}
switch (cached.data) {
.buffer => |data| {
if (data.len > 0) {
try req.data_callback(response, data);
}
},
.file => |file| {
var buf: [1024]u8 = undefined;
var file_reader = file.reader(&buf);
const reader = &file_reader.interface;
var read_buf: [1024]u8 = undefined;
while (true) {
const curr = try reader.readSliceShort(&read_buf);
if (curr == 0) break;
try req.data_callback(response, read_buf[0..curr]);
}
},
}
try req.done_callback(req.ctx);
}
fn processRequest(self: *Client, req: Request) !void {
if (self.network.cache) |*cache| {
if (req.method == .GET) {
if (cache.get(self.allocator, req.url)) |cached| {
log.debug(.browser, "http.cache.get", .{
.url = req.url,
.found = true,
.metadata = cached.metadata,
});
defer req.headers.deinit();
return serveFromCache(self.allocator, req, &cached);
} else {
log.debug(.browser, "http.cache.get", .{ .url = req.url, .found = false });
}
}
}
const transfer = try self.makeTransfer(req);
transfer.req.notification.dispatch(.http_request_start, &.{ .transfer = transfer });
@@ -886,6 +941,32 @@ fn processMessages(self: *Client) !bool {
continue;
};
if (self.network.cache) |*cache| {
var headers = &transfer.response_header.?;
if (transfer.req.method == .GET and headers.status == 200) {
cache.put(
transfer.req.url,
.{
.url = transfer.req.url,
.content_type = headers.contentType() orelse "application/octet-stream",
.status = headers.status,
.stored_at = std.time.timestamp(),
.age_at_store = 0,
.max_age = 3600,
.etag = null,
.last_modified = null,
.must_revalidate = false,
.no_cache = false,
.immutable = false,
.vary = null,
},
transfer.body.items,
) catch |err| log.warn(.http, "cache put failed", .{ .err = err });
log.debug(.browser, "http.cache.put", .{ .url = transfer.req.url });
}
}
transfer.req.notification.dispatch(.http_request_done, &.{
.transfer = transfer,
});
@@ -1081,6 +1162,7 @@ pub const LiveTransfer = struct {
// total bytes received in the response, including the response status line,
// the headers, and the [encoded] body.
bytes_received: usize = 0,
body: std.ArrayListUnmanaged(u8) = .empty,
aborted: bool = false,
@@ -1507,6 +1589,11 @@ pub const LiveTransfer = struct {
}
const chunk = buffer[0..chunk_len];
transfer.body.appendSlice(transfer.arena.allocator(), chunk) catch |err| {
log.err(.http, "cache body append", .{ .err = err, .req = transfer });
return Net.writefunc_error;
};
transfer.req.data_callback(Response.fromLive(transfer), chunk) catch |err| {
log.err(.http, "data_callback", .{ .err = err, .req = transfer });
return Net.writefunc_error;