move InterceptionLayer under CacheLayer

This commit is contained in:
Muki Kiboigo
2026-04-29 08:48:17 -07:00
parent c12107ef0f
commit f1fdfd1348
3 changed files with 58 additions and 36 deletions

View File

@@ -203,12 +203,12 @@ pub fn init(allocator: Allocator, network: *Network) !*Client {
next = layerWith(&client.robots_layer, next);
}
next = layerWith(&client.interception_layer, next);
if (network.config.httpCacheDir() != null) {
next = layerWith(&client.cache_layer, next);
}
next = layerWith(&client.interception_layer, next);
if (network.config.webBotAuth() != null) {
next = layerWith(&client.web_bot_auth_layer, next);
}

View File

@@ -22,7 +22,6 @@ const log = lp.log;
const http = @import("../http.zig");
const Client = @import("../../browser/HttpClient.zig").Client;
const Transfer = @import("../../browser/HttpClient.zig").Transfer;
const Request = @import("../../browser/HttpClient.zig").Request;
const Response = @import("../../browser/HttpClient.zig").Response;
const Layer = @import("../../browser/HttpClient.zig").Layer;
@@ -46,9 +45,10 @@ pub fn layer(self: *CacheLayer) Layer {
};
}
fn request(ptr: *anyopaque, client: *Client, req: Request) anyerror!void {
fn request(ptr: *anyopaque, client: *Client, in_req: Request) anyerror!void {
const self: *CacheLayer = @ptrCast(@alignCast(ptr));
const network = client.network;
var req = in_req;
if (req.params.method != .GET or !self.enabled) {
return self.next.request(client, req);
@@ -64,8 +64,16 @@ fn request(ptr: *anyopaque, client: *Client, req: Request) anyerror!void {
.timestamp = std.time.timestamp(),
.request_headers = req_header_list.items,
})) |cached| {
req.params.notification.dispatch(
.http_request_served_from_cache,
&.{
.request = &req,
},
);
try serveFromCache(req, &cached);
client.deinitRequest(req);
return;
}
@@ -82,8 +90,8 @@ fn request(ptr: *anyopaque, client: *Client, req: Request) anyerror!void {
req,
cache_ctx,
.{
.start = CacheContext.startCallback,
.header = CacheContext.headerCallback,
.data = CacheContext.dataCallback,
.done = CacheContext.doneCallback,
.shutdown = CacheContext.shutdownCallback,
.err = CacheContext.errorCallback,
@@ -97,7 +105,9 @@ pub fn setEnabled(self: *CacheLayer, enabled: bool) void {
self.enabled = enabled;
}
fn serveFromCache(req: Request, cached: *const CachedResponse) !void {
fn serveFromCache(in_req: Request, cached: *const CachedResponse) !void {
var req = in_req;
const response = Response.fromCached(req.ctx, cached);
defer switch (cached.data) {
.buffer => |_| {},
@@ -113,6 +123,12 @@ fn serveFromCache(req: Request, cached: *const CachedResponse) !void {
return error.Abort;
}
// This dispatches the Network.responseReceived that we should send.
req.params.notification.dispatch(.http_response_header_done, &.{
.request = &req,
.response = &response,
});
switch (cached.data) {
.buffer => |data| {
if (data.len > 0) {
@@ -143,45 +159,47 @@ fn serveFromCache(req: Request, cached: *const CachedResponse) !void {
const CacheContext = struct {
arena: std.mem.Allocator,
client: *Client,
transfer: ?*Transfer = null,
forward: Forward,
req_url: [:0]const u8,
req_headers: http.Headers,
pending_metadata: ?*CachedMetadata = null,
fn startCallback(response: Response) anyerror!void {
const self: *CacheContext = @ptrCast(@alignCast(response.ctx));
self.transfer = response.inner.transfer;
return self.forward.forwardStart(response);
}
body_buffer: std.ArrayList(u8) = .empty,
fn headerCallback(response: Response) anyerror!bool {
const self: *CacheContext = @ptrCast(@alignCast(response.ctx));
const allocator = self.arena;
const transfer = response.inner.transfer;
var rh = &transfer.response_header.?;
var vary: ?[]const u8 = null;
var cache_control: ?[]const u8 = null;
var age: ?[]const u8 = null;
var has_set_cookie = false;
var has_authorization = false;
const conn = transfer._conn.?;
const vary = if (conn.getResponseHeader("vary", 0)) |h| h.value else null;
var iter = response.headerIterator();
while (iter.next()) |h| {
if (std.ascii.eqlIgnoreCase(h.name, "vary")) vary = h.value;
if (std.ascii.eqlIgnoreCase(h.name, "cache-control")) cache_control = h.value;
if (std.ascii.eqlIgnoreCase(h.name, "age")) age = h.value;
if (std.ascii.eqlIgnoreCase(h.name, "set-cookie")) has_set_cookie = true;
if (std.ascii.eqlIgnoreCase(h.name, "authorization")) has_authorization = true;
}
const maybe_cm = try Cache.tryCache(
allocator,
std.time.timestamp(),
transfer.url,
rh.status,
rh.contentType(),
if (conn.getResponseHeader("cache-control", 0)) |h| h.value else null,
response.url(),
response.status() orelse @panic("Response must have status"),
response.contentType(),
cache_control,
vary,
if (conn.getResponseHeader("age", 0)) |h| h.value else null,
conn.getResponseHeader("set-cookie", 0) != null,
conn.getResponseHeader("authorization", 0) != null,
age,
has_set_cookie,
has_authorization,
);
if (maybe_cm) |cm| {
var iter = transfer.responseHeaderIterator();
var header_list = try iter.collect(allocator);
var cache_iter = response.headerIterator();
var header_list = try cache_iter.collect(allocator);
const end_of_response = header_list.items.len;
if (vary) |vary_str| {
@@ -205,20 +223,31 @@ const CacheContext = struct {
metadata.headers = header_list.items[0..end_of_response];
metadata.vary_headers = header_list.items[end_of_response..];
self.pending_metadata = metadata;
if (response.contentLength()) |len| {
try self.body_buffer.ensureTotalCapacity(self.arena, len);
}
}
return self.forward.forwardHeader(response);
}
fn dataCallback(response: Response, data: []const u8) anyerror!void {
const self: *CacheContext = @ptrCast(@alignCast(response.ctx));
if (self.pending_metadata != null) {
try self.body_buffer.appendSlice(self.arena, data);
}
return self.forward.forwardData(response, data);
}
fn doneCallback(ctx: *anyopaque) anyerror!void {
const self: *CacheContext = @ptrCast(@alignCast(ctx));
const transfer = self.transfer orelse @panic("Start Callback didn't set CacheLayer.transfer");
if (self.pending_metadata) |metadata| {
const cache = &self.client.network.cache.?;
log.debug(.browser, "http cache", .{ .key = self.req_url, .metadata = metadata });
cache.put(metadata.*, transfer._stream_buffer.items) catch |err| {
cache.put(metadata.*, self.body_buffer.items) catch |err| {
log.warn(.http, "cache put failed", .{ .err = err });
};
log.debug(.browser, "http.cache.put", .{ .url = self.req_url });

View File

@@ -109,13 +109,6 @@ pub const InterceptContext = struct {
fn startCallback(response: Response) anyerror!void {
const self: *InterceptContext = @ptrCast(@alignCast(response.ctx));
log.debug(.http, "intercept start", .{ .url = self.request.params.url });
if (response.inner == .cached) {
self.request.params.notification.dispatch(.http_request_served_from_cache, &.{
.request = &self.request,
});
}
return self.forward.forwardStart(response);
}