Compare commits

...

6 Commits

Author SHA1 Message Date
Muki Kiboigo
6688f69ba1 fix crashes on cached file from script manager 2026-04-01 15:57:56 -07:00
Muki Kiboigo
648af43f8a add format to CachedMetadata 2026-04-01 08:52:55 -07:00
Muki Kiboigo
ebb8c3f11c assign headers and vary headers before possible move 2026-04-01 08:52:47 -07:00
Muki Kiboigo
9214fba85e put in cache before releasing conn 2026-04-01 08:52:26 -07:00
Muki Kiboigo
d707a61646 dupe url in tryCache 2026-04-01 08:20:01 -07:00
Muki Kiboigo
600f2909fc update cacheDir config option 2026-04-01 08:16:21 -07:00
4 changed files with 46 additions and 18 deletions

View File

@@ -394,6 +394,11 @@ pub fn printUsageAndExit(self: *const Config, success: bool) void {
\\ \\
\\--web-bot-auth-domain \\--web-bot-auth-domain
\\ Your domain e.g. yourdomain.com \\ Your domain e.g. yourdomain.com
\\
\\--cache-dir
\\ Path to a directory to use as a Filesystem Cache for network resources.
\\ Omitting this will result is no caching.
\\ Defaults to no caching.
; ;
// MAX_HELP_LEN| // MAX_HELP_LEN|
@@ -1055,9 +1060,9 @@ fn parseCommonArg(
return true; return true;
} }
if (std.mem.eql(u8, "--cache_dir", opt)) { if (std.mem.eql(u8, "--cache-dir", opt)) {
const str = args.next() orelse { const str = args.next() orelse {
log.fatal(.app, "missing argument value", .{ .arg = "--cache_dir" }); log.fatal(.app, "missing argument value", .{ .arg = "--cache-dir" });
return error.InvalidArgument; return error.InvalidArgument;
}; };
common.cache_dir = try allocator.dupe(u8, str); common.cache_dir = try allocator.dupe(u8, str);

View File

@@ -970,25 +970,22 @@ fn processOneMessage(self: *Client, msg: http.Handles.MultiMessage, transfer: *T
} }
} }
// release conn ASAP so that it's available; some done_callbacks
// will load more resources.
transfer.releaseConn();
try transfer.req.done_callback(transfer.req.ctx);
if (transfer._pending_cache_metadata) |metadata| { if (transfer._pending_cache_metadata) |metadata| {
const cache = &self.network.cache.?; const cache = &self.network.cache.?;
log.debug(.browser, "http cache", .{ .url = transfer.req.url, .metadata = metadata });
// TODO: Support Vary Keying
const cache_key = transfer.req.url;
log.debug(.browser, "http cache", .{ .key = cache_key, .metadata = metadata });
cache.put(metadata, body) catch |err| { cache.put(metadata, body) catch |err| {
log.warn(.http, "cache put failed", .{ .err = err }); log.warn(.http, "cache put failed", .{ .err = err });
}; };
log.debug(.browser, "http.cache.put", .{ .url = transfer.req.url }); log.debug(.browser, "http.cache.put", .{ .url = transfer.req.url });
} }
// release conn ASAP so that it's available; some done_callbacks
// will load more resources.
transfer.releaseConn();
try transfer.req.done_callback(transfer.req.ctx);
transfer.req.notification.dispatch(.http_request_done, &.{ transfer.req.notification.dispatch(.http_request_done, &.{
.transfer = transfer, .transfer = transfer,
}); });
@@ -1572,12 +1569,9 @@ pub const Transfer = struct {
); );
if (maybe_cm) |cm| { if (maybe_cm) |cm| {
transfer._pending_cache_metadata = cm;
var iter = transfer.responseHeaderIterator(); var iter = transfer.responseHeaderIterator();
var header_list = try iter.collect(allocator); var header_list = try iter.collect(allocator);
const end_of_response = header_list.items.len; const end_of_response = header_list.items.len;
transfer._pending_cache_metadata.?.headers = header_list.items[0..end_of_response];
if (vary) |vary_str| { if (vary) |vary_str| {
var req_it = transfer.req.headers.iterator(); var req_it = transfer.req.headers.iterator();
@@ -1595,9 +1589,11 @@ pub const Transfer = struct {
} }
} }
} }
transfer._pending_cache_metadata.?.vary_headers = header_list.items[end_of_response..];
} }
transfer._pending_cache_metadata = cm;
transfer._pending_cache_metadata.?.headers = header_list.items[0..end_of_response];
transfer._pending_cache_metadata.?.vary_headers = header_list.items[end_of_response..];
} }
} }

View File

@@ -273,6 +273,10 @@ pub fn addFromElement(self: *ScriptManager, comptime from_parser: bool, script_e
// Let the outer errdefer handle releasing the arena if client.request fails // Let the outer errdefer handle releasing the arena if client.request fails
} }
// If we return synchronously (like from cache), we would call evaluate() immediately.
const was_evaluating = self.is_evaluating;
self.is_evaluating = true;
try self.client.request(.{ try self.client.request(.{
.url = url, .url = url,
.ctx = script, .ctx = script,
@@ -290,6 +294,9 @@ pub fn addFromElement(self: *ScriptManager, comptime from_parser: bool, script_e
.done_callback = Script.doneCallback, .done_callback = Script.doneCallback,
.error_callback = Script.errorCallback, .error_callback = Script.errorCallback,
}); });
self.is_evaluating = was_evaluating;
handover = true; handover = true;
if (comptime IS_DEBUG) { if (comptime IS_DEBUG) {

View File

@@ -103,6 +103,26 @@ pub const CachedMetadata = struct {
/// These are Request Headers used by Vary. /// These are Request Headers used by Vary.
vary_headers: []const Http.Header, vary_headers: []const Http.Header,
pub fn format(self: CachedMetadata, writer: *std.Io.Writer) !void {
try writer.print("url={s} | status={d} | content_type={s} | max_age={d} | vary=[", .{
self.url,
self.status,
self.content_type,
self.cache_control.max_age,
});
// Logging all headers gets pretty verbose...
// so we just log the Vary ones that matter for caching.
if (self.vary_headers.len > 0) {
for (self.vary_headers, 0..) |hdr, i| {
if (i > 0) try writer.print(", ", .{});
try writer.print("{s}: {s}", .{ hdr.name, hdr.value });
}
}
try writer.print("]", .{});
}
}; };
pub const CacheRequest = struct { pub const CacheRequest = struct {
@@ -144,7 +164,7 @@ pub fn tryCache(
const cc = CacheControl.parse(cache_control orelse return null) orelse return null; const cc = CacheControl.parse(cache_control orelse return null) orelse return null;
return .{ return .{
.url = url, .url = try arena.dupeZ(u8, url),
.content_type = if (content_type) |ct| try arena.dupe(u8, ct) else "application/octet-stream", .content_type = if (content_type) |ct| try arena.dupe(u8, ct) else "application/octet-stream",
.status = status, .status = status,
.stored_at = timestamp, .stored_at = timestamp,