diff --git a/src/cdp/domains/network.zig b/src/cdp/domains/network.zig index 164cc745..f143ff52 100644 --- a/src/cdp/domains/network.zig +++ b/src/cdp/domains/network.zig @@ -203,7 +203,7 @@ fn putAssumeCapacity(headers: *std.ArrayListUnmanaged(std.http.Header), extra: s return true; } -pub fn httpRequestFail(arena: Allocator, bc: anytype, request: *const Notification.RequestFail) !void { +pub fn httpRequestFail(arena: Allocator, bc: anytype, data: *const Notification.RequestFail) !void { // It's possible that the request failed because we aborted when the client // sent Target.closeTarget. In that case, bc.session_id will be cleared // already, and we can skip sending these messages to the client. @@ -215,10 +215,10 @@ pub fn httpRequestFail(arena: Allocator, bc: anytype, request: *const Notificati // We're missing a bunch of fields, but, for now, this seems like enough try bc.cdp.sendEvent("Network.loadingFailed", .{ - .requestId = try std.fmt.allocPrint(arena, "REQ-{d}", .{request.id}), + .requestId = try std.fmt.allocPrint(arena, "REQ-{d}", .{data.request.id.?}), // Seems to be what chrome answers with. I assume it depends on the type of error? .type = "Ping", - .errorText = request.err, + .errorText = data.err, .canceled = false, }, .{ .session_id = session_id }); } diff --git a/src/http/Client.zig b/src/http/Client.zig index 41767772..c72da2ee 100644 --- a/src/http/Client.zig +++ b/src/http/Client.zig @@ -151,7 +151,7 @@ pub fn abort(self: *Client) void { log.err(.http, "get private info", .{ .err = err, .source = "abort" }); continue; }; - transfer.req.error_callback(transfer.ctx, error.Abort); + self.requestFailed(&transfer.req, error.Abort); self.endTransfer(transfer); } std.debug.assert(self.active == 0); @@ -221,6 +221,20 @@ pub fn blockingRequest(self: *Client, req: Request) !void { return self.makeRequest(&self.blocking, req); } +fn requestFailed(self: *Client, req: *Request, err: anyerror) void { + if (req._notified_fail) return; + req._notified_fail = true; + + if (self.notification) |notification| { + notification.dispatch(.http_request_fail, &.{ + .request = req, + .err = err, + }); + } + + req.error_callback(req.ctx, err); +} + // Restrictive since it'll only work if there are no inflight requests. In some // cases, the libcurl documentation is clear that changing settings while a // connection is inflight is undefined. It doesn't say anything about CURLOPT_PROXY, @@ -326,7 +340,6 @@ fn perform(self: *Client, timeout_ms: c_int) !void { const transfer = try Transfer.fromEasy(easy); const ctx = transfer.ctx; const done_callback = transfer.req.done_callback; - const error_callback = transfer.req.error_callback; // release it ASAP so that it's available; some done_callbacks // will load more resources. @@ -336,10 +349,10 @@ fn perform(self: *Client, timeout_ms: c_int) !void { done_callback(ctx) catch |err| { // transfer isn't valid at this point, don't use it. log.err(.http, "done_callback", .{ .err = err }); - error_callback(ctx, err); + self.requestFailed(&transfer.req, err); }; } else |err| { - error_callback(ctx, err); + self.requestFailed(&transfer.req, err); } } } @@ -491,6 +504,8 @@ pub const Request = struct { body: ?[]const u8 = null, cookie_jar: *storage.CookieJar, + _notified_fail: bool = false, + // arbitrary data that can be associated with this request ctx: *anyopaque = undefined, diff --git a/src/notification.zig b/src/notification.zig index e351e9b3..6f2e29c9 100644 --- a/src/notification.zig +++ b/src/notification.zig @@ -103,9 +103,8 @@ pub const Notification = struct { }; pub const RequestFail = struct { - id: usize, - url: *const std.Uri, - err: []const u8, + request: *Request, + err: anyerror, }; pub const RequestComplete = struct {