Requests now use arenas from the arena pool

This commit is contained in:
Muki Kiboigo
2026-04-26 22:59:11 -07:00
parent 175c2cc288
commit bb9e238f6c
4 changed files with 32 additions and 35 deletions

View File

@@ -400,7 +400,10 @@ pub fn request(self: *Client, req: Request) !void {
// Assign Request Id.
var our_req = req;
our_req.params.request_id = self.incrReqId();
our_req.params.arena = ArenaAllocator.init(self.allocator);
const arena = try self.network.app.arena_pool.acquire(.small, "Request.arena");
errdefer self.network.app.arena_pool.release(arena);
our_req.params.arena = arena;
return self.entry_layer.request(self, our_req);
}
@@ -854,7 +857,7 @@ fn ensureNoActiveConnection(self: *const Client) !void {
pub const RequestParams = struct {
/// This is unsafe to access until you pass it to `Client.request()` where it gets assigned.
arena: ArenaAllocator = undefined,
arena: Allocator = undefined,
/// This is unsafe to access until you pass it to `Client.request()` where it gets assigned.
request_id: u32 = undefined,
@@ -893,7 +896,6 @@ pub const RequestParams = struct {
pub fn deinit(self: *const RequestParams) void {
self.headers.deinit();
self.arena.deinit();
}
};
@@ -918,7 +920,7 @@ pub const Request = struct {
pub fn getCookieString(self: *Request) !?[:0]const u8 {
const jar = self.params.cookie_jar orelse return null;
var aw: std.Io.Writer.Allocating = .init(self.params.arena.allocator());
var aw: std.Io.Writer.Allocating = .init(self.params.arena);
try jar.forRequest(self.params.url, &aw.writer, .{
.is_http = true,
.origin_url = self.params.cookie_origin,
@@ -1102,7 +1104,7 @@ pub const Transfer = struct {
self._conn = null;
}
self.req.deinit();
self.client.deinitRequest(self.req);
self.client.transfer_pool.destroy(self);
}
@@ -1266,7 +1268,7 @@ pub const Transfer = struct {
fn handleRedirect(transfer: *Transfer) !void {
const req = &transfer.req;
const conn = transfer._conn.?;
const arena = transfer.req.params.arena.allocator();
const arena = transfer.req.params.arena;
transfer._redirect_count += 1;
if (transfer._redirect_count > transfer.client.network.config.httpMaxRedirects()) {
@@ -1443,7 +1445,7 @@ pub const Transfer = struct {
transfer._callback_error = error.ResponseTooLarge;
return http.writefunc_error;
}
transfer._stream_buffer.ensureTotalCapacity(transfer.req.params.arena.allocator(), cl) catch {};
transfer._stream_buffer.ensureTotalCapacity(transfer.req.params.arena, cl) catch {};
}
}
@@ -1456,7 +1458,7 @@ pub const Transfer = struct {
}
const chunk = buffer[0..chunk_len];
transfer._stream_buffer.appendSlice(transfer.req.params.arena.allocator(), chunk) catch |err| {
transfer._stream_buffer.appendSlice(transfer.req.params.arena, chunk) catch |err| {
transfer._callback_error = err;
return http.writefunc_error;
};
@@ -1568,6 +1570,11 @@ pub fn continueTransfer(self: *Client, transfer: *Transfer) !void {
return self.process(transfer);
}
pub fn deinitRequest(self: *Client, req: Request) void {
req.deinit();
self.network.app.arena_pool.release(req.params.arena);
}
const Noop = struct {
fn headerCallback(_: Response) !bool {
return true;

View File

@@ -255,7 +255,7 @@ fn continueRequest(cmd: *CDP.Command) !void {
.new_url = params.url,
});
const arena = request.params.arena.allocator();
const arena = request.params.arena;
// Update the request with the new parameters
if (params.url) |url| {
request.params.url = try arena.dupeZ(u8, url);
@@ -313,7 +313,7 @@ fn continueWithAuth(cmd: *CDP.Command) !void {
const request_id = try idFromRequestId(params.requestId);
const pending = intercept_state.remove(request_id) orelse return error.RequestNotFound;
const transfer = pending.transfer;
var request = transfer.req;
const request = transfer.req;
log.debug(.cdp, "request intercept", .{
.state = "continue with auth",
@@ -331,7 +331,7 @@ fn continueWithAuth(cmd: *CDP.Command) !void {
// cancel the request, deinit the transfer on error.
errdefer transfer.abortAuthChallenge();
const arena = request.params.arena.allocator();
const arena = request.params.arena;
transfer.updateCredentials(try std.fmt.allocPrintSentinel(
arena,
"{s}:{s}",
@@ -380,7 +380,7 @@ fn fulfillRequest(cmd: *CDP.Command) !void {
var body: ?[]const u8 = null;
if (params.body) |b| {
const decoder = std.base64.standard.Decoder;
const buf = try request.params.arena.allocator().alloc(u8, try decoder.calcSizeForSlice(b));
const buf = try request.params.arena.alloc(u8, try decoder.calcSizeForSlice(b));
try decoder.decode(buf, b);
body = buf;
}

View File

@@ -209,14 +209,12 @@ pub fn continueRequest(self: *InterceptionLayer, client: *Client, req: Request)
}
pub fn abortRequest(self: *InterceptionLayer, client: *Client, req: Request) void {
_ = client;
if (comptime IS_DEBUG) {
log.debug(.http, "abort transfer", .{ .intercepted = self.intercepted });
}
self.intercepted -= 1;
defer req.deinit();
defer client.deinitRequest(req);
req.error_callback(req.ctx, error.Abort);
}
@@ -253,7 +251,7 @@ fn fulfillInner(
pub fn fulfillRequest(
self: *InterceptionLayer,
_: *Client,
client: *Client,
req: Request,
status: u16,
headers: []const http.Header,
@@ -264,21 +262,10 @@ pub fn fulfillRequest(
}
self.intercepted -= 1;
defer req.deinit();
defer client.deinitRequest(req);
fulfillInner(req, status, headers, body) catch |err| {
req.error_callback(req.ctx, err);
return err;
};
}
pub fn abortAuthChallenge(self: *InterceptionLayer, req: Request) void {
if (comptime IS_DEBUG) {
log.debug(.http, "abort auth transfer", .{ .intercepted = self.intercepted });
}
self.intercepted -= 1;
defer req.deinit();
req.error_callback(req.ctx, error.AbortAuthChallenge);
return;
}

View File

@@ -66,7 +66,7 @@ fn request(ptr: *anyopaque, client: *Client, req: Request) anyerror!void {
const path = URL.getPathname(req.params.url);
if (!robots.isAllowed(path)) {
defer req.deinit();
defer client.deinitRequest(req);
log.warn(.http, "blocked by robots", .{ .url = req.params.url });
req.error_callback(req.ctx, error.RobotsBlocked);
@@ -108,11 +108,14 @@ fn fetchRobotsThenRequest(
const headers = try client.newHeaders();
log.debug(.browser, "fetching robots.txt", .{ .robots_url = robots_url });
const new_arena = try client.network.app.arena_pool.acquire(.small, "RobotsLayer.fetchRobots");
errdefer client.network.app.arena_pool.release(new_arena);
try self.next.request(client, .{
.ctx = robots_ctx,
.params = .{
// We have to do this ourselves because we are not going through the top level `request`.
.arena = std.heap.ArenaAllocator.init(client.allocator),
.arena = new_arena,
.request_id = client.incrReqId(),
.url = robots_url,
.method = .GET,
@@ -145,24 +148,24 @@ fn flushPending(self: *RobotsLayer, client: *Client, robots_url: [:0]const u8, a
for (queued.value.items) |queued_req| {
if (!allowed) {
log.warn(.http, "blocked by robots", .{ .url = queued_req.params.url });
defer queued_req.deinit();
defer client.deinitRequest(queued_req);
queued_req.error_callback(queued_req.ctx, error.RobotsBlocked);
} else {
self.next.request(client, queued_req) catch |e| {
defer queued_req.deinit();
defer client.deinitRequest(queued_req);
queued_req.error_callback(queued_req.ctx, e);
};
}
}
}
fn flushPendingShutdown(self: *RobotsLayer, robots_url: [:0]const u8) void {
fn flushPendingShutdown(self: *RobotsLayer, robots_url: [:0]const u8, client: *Client) void {
var queued = self.pending.fetchRemove(robots_url) orelse
@panic("RobotsLayer.flushPendingShutdown: missing queue");
defer queued.value.deinit(self.allocator);
for (queued.value.items) |queued_req| {
defer queued_req.deinit();
defer client.deinitRequest(queued_req);
if (queued_req.shutdown_callback) |cb| cb(queued_req.ctx);
}
}
@@ -265,6 +268,6 @@ const RobotsContext = struct {
defer client.network.app.arena_pool.release(self.arena);
log.debug(.http, "robots fetch shutdown", .{});
l.flushPendingShutdown(robots_url);
l.flushPendingShutdown(robots_url, client);
}
};