Skip to content

Emit http_request_fail notification #771

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/browser/page.zig
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,8 @@ pub const Page = struct {
.content_type = content_type,
.charset = mime.charset,
.url = request_url,
.method = opts.method,
.reason = opts.reason,
});

if (!mime.isHTML()) {
Expand Down Expand Up @@ -597,6 +599,10 @@ pub const Page = struct {
// The page.arena is safe to use here, but the transfer_arena exists
// specifically for this type of lifetime.
pub fn navigateFromWebAPI(self: *Page, url: []const u8, opts: NavigateOpts) !void {
log.debug(.browser, "delayed navigation", .{
.url = url,
.reason = opts.reason,
});
self.delayed_navigation = true;
const arena = self.session.transfer_arena;
const navi = try arena.create(DelayedNavigation);
Expand Down
12 changes: 10 additions & 2 deletions src/browser/xhr/xhr.zig
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,11 @@ pub const XMLHttpRequest = struct {
// dispatch request event.
// errors are logged only.
fn dispatchEvt(self: *XMLHttpRequest, typ: []const u8) void {
log.debug(.script_event, "dispatch event", .{ .type = typ, .source = "xhr" });
log.debug(.script_event, "dispatch event", .{
.type = typ,
.source = "xhr",
.url = self.url,
});
self._dispatchEvt(typ) catch |err| {
log.err(.app, "dispatch event error", .{ .err = err, .type = typ, .source = "xhr" });
};
Expand All @@ -358,7 +362,11 @@ pub const XMLHttpRequest = struct {
typ: []const u8,
opts: ProgressEvent.EventInit,
) void {
log.debug(.script_event, "dispatch progress event", .{ .type = typ, .source = "xhr" });
log.debug(.script_event, "dispatch progress event", .{
.type = typ,
.source = "xhr",
.url = self.url,
});
self._dispatchProgressEvent(typ, opts) catch |err| {
log.err(.app, "dispatch progress event error", .{ .err = err, .type = typ, .source = "xhr" });
};
Expand Down
8 changes: 8 additions & 0 deletions src/cdp/cdp.zig
Original file line number Diff line number Diff line change
Expand Up @@ -412,11 +412,13 @@ pub fn BrowserContext(comptime CDP_T: type) type {
}

pub fn networkEnable(self: *Self) !void {
try self.cdp.browser.notification.register(.http_request_fail, self, onHttpRequestFail);
try self.cdp.browser.notification.register(.http_request_start, self, onHttpRequestStart);
try self.cdp.browser.notification.register(.http_request_complete, self, onHttpRequestComplete);
}

pub fn networkDisable(self: *Self) void {
self.cdp.browser.notification.unregister(.http_request_fail, self);
self.cdp.browser.notification.unregister(.http_request_start, self);
self.cdp.browser.notification.unregister(.http_request_complete, self);
}
Expand Down Expand Up @@ -448,6 +450,12 @@ pub fn BrowserContext(comptime CDP_T: type) type {
return @import("domains/network.zig").httpRequestStart(self.notification_arena, self, data);
}

pub fn onHttpRequestFail(ctx: *anyopaque, data: *const Notification.RequestFail) !void {
const self: *Self = @alignCast(@ptrCast(ctx));
defer self.resetNotificationArena();
return @import("domains/network.zig").httpRequestFail(self.notification_arena, self, data);
}

pub fn onHttpRequestComplete(ctx: *anyopaque, data: *const Notification.RequestComplete) !void {
const self: *Self = @alignCast(@ptrCast(ctx));
defer self.resetNotificationArena();
Expand Down
18 changes: 18 additions & 0 deletions src/cdp/domains/network.zig
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,24 @@ fn putAssumeCapacity(headers: *std.ArrayListUnmanaged(std.http.Header), extra: s
return true;
}

pub fn httpRequestFail(arena: Allocator, bc: anytype, request: *const Notification.RequestFail) !void {
// Isn't possible to do a network request within a Browser (which our
// notification is tied to), without a page.
std.debug.assert(bc.session.page != null);

// all unreachable because we _have_ to have a page.
const session_id = bc.session_id orelse unreachable;

// 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}),
// Seems to be what chrome answers with. I assume it depends on the type of error?
.type = "Ping",
.errorText = request.err,
.canceled = false,
}, .{ .session_id = session_id });
}

pub fn httpRequestStart(arena: Allocator, bc: anytype, request: *const Notification.RequestStart) !void {
// Isn't possible to do a network request within a Browser (which our
// notification is tied to), without a page.
Expand Down
22 changes: 22 additions & 0 deletions src/http/client.zig
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@ pub const Request = struct {
// Because of things like redirects and error handling, it is possible for
// the notification functions to be called multiple times, so we guard them
// with these booleans
_notified_fail: bool,
_notified_start: bool,
_notified_complete: bool,

Expand Down Expand Up @@ -414,6 +415,7 @@ pub const Request = struct {
._keepalive = false,
._redirect_count = 0,
._has_host_header = false,
._notified_fail = false,
._notified_start = false,
._notified_complete = false,
._connection_from_keepalive = false,
Expand All @@ -428,6 +430,7 @@ pub const Request = struct {
}

pub fn abort(self: *Request) void {
self.requestFailed("aborted");
const aborter = self._aborter orelse {
self.deinit();
return;
Expand Down Expand Up @@ -555,6 +558,10 @@ pub const Request = struct {
}

fn doSendSync(self: *Request, use_pool: bool) anyerror!Response {
// https://github.com/ziglang/zig/issues/20369
// errdefer |err| self.requestFailed(@errorName(err));
errdefer self.requestFailed("network error");

if (use_pool) {
if (self.findExistingConnection(true)) |connection| {
self._connection = connection;
Expand Down Expand Up @@ -847,6 +854,19 @@ pub const Request = struct {
});
}

fn requestFailed(self: *Request, err: []const u8) void {
const notification = self.notification orelse return;
if (self._notified_fail) {
return;
}
self._notified_fail = true;
notification.dispatch(.http_request_fail, &.{
.id = self.id,
.err = err,
.url = self.request_uri,
});
}

fn requestCompleted(self: *Request, response: ResponseHeader) void {
const notification = self.notification orelse return;
if (self._notified_complete) {
Expand Down Expand Up @@ -1290,6 +1310,8 @@ fn AsyncHandler(comptime H: type, comptime L: type) type {
self.handler.onHttpResponse(err) catch {};
// just to be safe
self.request._keepalive = false;

self.request.requestFailed(@errorName(err));
self.request.deinit();
}

Expand Down
8 changes: 8 additions & 0 deletions src/notification.zig
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ pub const Notification = struct {
page_created: List = .{},
page_navigate: List = .{},
page_navigated: List = .{},
http_request_fail: List = .{},
http_request_start: List = .{},
http_request_complete: List = .{},
notification_created: List = .{},
Expand All @@ -69,6 +70,7 @@ pub const Notification = struct {
page_created: *page.Page,
page_navigate: *const PageNavigate,
page_navigated: *const PageNavigated,
http_request_fail: *const RequestFail,
http_request_start: *const RequestStart,
http_request_complete: *const RequestComplete,
notification_created: *Notification,
Expand Down Expand Up @@ -97,6 +99,12 @@ pub const Notification = struct {
has_body: bool,
};

pub const RequestFail = struct {
id: usize,
url: *const std.Uri,
err: []const u8,
};

pub const RequestComplete = struct {
id: usize,
url: *const std.Uri,
Expand Down
2 changes: 0 additions & 2 deletions src/runtime/loop.zig
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,6 @@ pub const Loop = struct {
}
}


// JS callbacks APIs
// -----------------

Expand Down Expand Up @@ -255,7 +254,6 @@ pub const Loop = struct {
}
}.onConnect;


const callback = try self.event_callback_pool.create();
errdefer self.event_callback_pool.destroy(callback);
callback.* = .{ .loop = self, .ctx = ctx };
Expand Down