mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-12-14 15:28:57 +00:00
cdp: dispatch Page.navigate response after navigation
This commit is contained in:
@@ -83,6 +83,7 @@ pub const Page = struct {
|
||||
|
||||
// indicates intention to navigate to another page on the next loop execution.
|
||||
delayed_navigation: bool = false,
|
||||
navigated_options: ?NavigatedOpts = null,
|
||||
|
||||
state_pool: *std.heap.MemoryPool(State),
|
||||
|
||||
@@ -574,6 +575,11 @@ pub const Page = struct {
|
||||
});
|
||||
|
||||
self.session.browser.notification.dispatch(.page_navigated, &.{
|
||||
.opts = .{
|
||||
.cdp_id = opts.cdp_id,
|
||||
.reason = opts.reason,
|
||||
.method = opts.method,
|
||||
},
|
||||
.url = request_url,
|
||||
.timestamp = timestamp(),
|
||||
});
|
||||
@@ -584,6 +590,12 @@ pub const Page = struct {
|
||||
const owned_url = try self.arena.dupeZ(u8, request_url);
|
||||
self.url = try URL.parse(owned_url, null);
|
||||
|
||||
self.navigated_options = .{
|
||||
.cdp_id = opts.cdp_id,
|
||||
.reason = opts.reason,
|
||||
.method = opts.method,
|
||||
};
|
||||
|
||||
var headers = try self.http_client.newHeaders();
|
||||
if (opts.header) |hdr| try headers.add(hdr);
|
||||
try self.requestCookie(.{ .is_navigation = true }).headersForRequest(self.arena, owned_url, &headers);
|
||||
@@ -656,7 +668,9 @@ pub const Page = struct {
|
||||
log.err(.browser, "document is complete", .{ .err = err });
|
||||
};
|
||||
|
||||
std.debug.assert(self.navigated_options != null);
|
||||
self.session.browser.notification.dispatch(.page_navigated, &.{
|
||||
.opts = self.navigated_options.?,
|
||||
.url = self.url.raw,
|
||||
.timestamp = timestamp(),
|
||||
});
|
||||
@@ -1264,6 +1278,12 @@ pub const NavigateOpts = struct {
|
||||
force: bool = false,
|
||||
};
|
||||
|
||||
pub const NavigatedOpts = struct {
|
||||
cdp_id: ?i64 = null,
|
||||
reason: NavigateReason = .address_bar,
|
||||
method: Http.Method = .GET,
|
||||
};
|
||||
|
||||
const IdleNotification = union(enum) {
|
||||
// hasn't started yet.
|
||||
init,
|
||||
|
||||
@@ -545,13 +545,13 @@ pub fn BrowserContext(comptime CDP_T: type) type {
|
||||
|
||||
pub fn onPageNavigate(ctx: *anyopaque, msg: *const Notification.PageNavigate) !void {
|
||||
const self: *Self = @ptrCast(@alignCast(ctx));
|
||||
defer self.resetNotificationArena();
|
||||
return @import("domains/page.zig").pageNavigate(self.notification_arena, self, msg);
|
||||
return @import("domains/page.zig").pageNavigate(self, msg);
|
||||
}
|
||||
|
||||
pub fn onPageNavigated(ctx: *anyopaque, msg: *const Notification.PageNavigated) !void {
|
||||
const self: *Self = @ptrCast(@alignCast(ctx));
|
||||
return @import("domains/page.zig").pageNavigated(self, msg);
|
||||
defer self.resetNotificationArena();
|
||||
return @import("domains/page.zig").pageNavigated(self.notification_arena, self, msg);
|
||||
}
|
||||
|
||||
pub fn onPageNetworkIdle(ctx: *anyopaque, msg: *const Notification.PageNetworkIdle) !void {
|
||||
|
||||
@@ -184,7 +184,7 @@ fn navigate(cmd: anytype) !void {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn pageNavigate(arena: Allocator, bc: anytype, event: *const Notification.PageNavigate) !void {
|
||||
pub fn pageNavigate(bc: anytype, event: *const Notification.PageNavigate) !void {
|
||||
// detachTarget could be called, in which case, we still have a page doing
|
||||
// things, but no session.
|
||||
const session_id = bc.session_id orelse return;
|
||||
@@ -234,6 +234,30 @@ pub fn pageNavigate(arena: Allocator, bc: anytype, event: *const Notification.Pa
|
||||
try cdp.sendEvent("Page.frameStartedLoading", .{
|
||||
.frameId = target_id,
|
||||
}, .{ .session_id = session_id });
|
||||
}
|
||||
|
||||
pub fn pageRemove(bc: anytype) !void {
|
||||
// The main page is going to be removed, we need to remove contexts from other worlds first.
|
||||
for (bc.isolated_worlds.items) |*isolated_world| {
|
||||
try isolated_world.removeContext();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pageCreated(bc: anytype, page: *Page) !void {
|
||||
for (bc.isolated_worlds.items) |*isolated_world| {
|
||||
try isolated_world.createContextAndLoadPolyfills(bc.arena, page);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pageNavigated(arena: Allocator, bc: anytype, event: *const Notification.PageNavigated) !void {
|
||||
// detachTarget could be called, in which case, we still have a page doing
|
||||
// things, but no session.
|
||||
const session_id = bc.session_id orelse return;
|
||||
const loader_id = bc.loader_id;
|
||||
const target_id = bc.target_id orelse unreachable;
|
||||
const timestamp = event.timestamp;
|
||||
|
||||
var cdp = bc.cdp;
|
||||
|
||||
// Drivers are sensitive to the order of events. Some more than others.
|
||||
// The result for the Page.navigate seems like it _must_ come after
|
||||
@@ -260,6 +284,17 @@ pub fn pageNavigate(arena: Allocator, bc: anytype, event: *const Notification.Pa
|
||||
}, .{ .session_id = session_id });
|
||||
}
|
||||
|
||||
const reason_: ?[]const u8 = switch (event.opts.reason) {
|
||||
.anchor => "anchorClick",
|
||||
.script, .history, .navigation => "scriptInitiated",
|
||||
.form => switch (event.opts.method) {
|
||||
.GET => "formSubmissionGet",
|
||||
.POST => "formSubmissionPost",
|
||||
else => unreachable,
|
||||
},
|
||||
.address_bar => null,
|
||||
};
|
||||
|
||||
if (reason_ != null) {
|
||||
try cdp.sendEvent("Page.frameClearedScheduledNavigation", .{
|
||||
.frameId = target_id,
|
||||
@@ -293,30 +328,7 @@ pub fn pageNavigate(arena: Allocator, bc: anytype, event: *const Notification.Pa
|
||||
false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pageRemove(bc: anytype) !void {
|
||||
// The main page is going to be removed, we need to remove contexts from other worlds first.
|
||||
for (bc.isolated_worlds.items) |*isolated_world| {
|
||||
try isolated_world.removeContext();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pageCreated(bc: anytype, page: *Page) !void {
|
||||
for (bc.isolated_worlds.items) |*isolated_world| {
|
||||
try isolated_world.createContextAndLoadPolyfills(bc.arena, page);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pageNavigated(bc: anytype, event: *const Notification.PageNavigated) !void {
|
||||
// detachTarget could be called, in which case, we still have a page doing
|
||||
// things, but no session.
|
||||
const session_id = bc.session_id orelse return;
|
||||
const loader_id = bc.loader_id;
|
||||
const target_id = bc.target_id orelse unreachable;
|
||||
const timestamp = event.timestamp;
|
||||
|
||||
var cdp = bc.cdp;
|
||||
// frameNavigated event
|
||||
try cdp.sendEvent("Page.frameNavigated", .{
|
||||
.type = "Navigation",
|
||||
|
||||
@@ -98,6 +98,7 @@ pub const Notification = struct {
|
||||
pub const PageNavigated = struct {
|
||||
timestamp: u32,
|
||||
url: []const u8,
|
||||
opts: page.NavigatedOpts,
|
||||
};
|
||||
|
||||
pub const PageNetworkIdle = struct {
|
||||
@@ -326,7 +327,7 @@ test "Notification" {
|
||||
.url = undefined,
|
||||
.opts = .{},
|
||||
});
|
||||
notifier.dispatch(.page_navigated, &.{ .timestamp = 6, .url = undefined });
|
||||
notifier.dispatch(.page_navigated, &.{ .timestamp = 6, .url = undefined, .opts = .{} });
|
||||
try testing.expectEqual(14, tc.page_navigate);
|
||||
try testing.expectEqual(6, tc.page_navigated);
|
||||
|
||||
@@ -336,7 +337,7 @@ test "Notification" {
|
||||
.url = undefined,
|
||||
.opts = .{},
|
||||
});
|
||||
notifier.dispatch(.page_navigated, &.{ .timestamp = 100, .url = undefined });
|
||||
notifier.dispatch(.page_navigated, &.{ .timestamp = 100, .url = undefined, .opts = .{} });
|
||||
try testing.expectEqual(14, tc.page_navigate);
|
||||
try testing.expectEqual(6, tc.page_navigated);
|
||||
|
||||
@@ -345,26 +346,26 @@ test "Notification" {
|
||||
try notifier.register(.page_navigate, &tc, TestClient.pageNavigate);
|
||||
try notifier.register(.page_navigated, &tc, TestClient.pageNavigated);
|
||||
notifier.dispatch(.page_navigate, &.{ .timestamp = 100, .url = undefined, .opts = .{} });
|
||||
notifier.dispatch(.page_navigated, &.{ .timestamp = 1000, .url = undefined });
|
||||
notifier.dispatch(.page_navigated, &.{ .timestamp = 1000, .url = undefined, .opts = .{} });
|
||||
try testing.expectEqual(114, tc.page_navigate);
|
||||
try testing.expectEqual(1006, tc.page_navigated);
|
||||
|
||||
notifier.unregister(.page_navigate, &tc);
|
||||
notifier.dispatch(.page_navigate, &.{ .timestamp = 100, .url = undefined, .opts = .{} });
|
||||
notifier.dispatch(.page_navigated, &.{ .timestamp = 1000, .url = undefined });
|
||||
notifier.dispatch(.page_navigated, &.{ .timestamp = 1000, .url = undefined, .opts = .{} });
|
||||
try testing.expectEqual(114, tc.page_navigate);
|
||||
try testing.expectEqual(2006, tc.page_navigated);
|
||||
|
||||
notifier.unregister(.page_navigated, &tc);
|
||||
notifier.dispatch(.page_navigate, &.{ .timestamp = 100, .url = undefined, .opts = .{} });
|
||||
notifier.dispatch(.page_navigated, &.{ .timestamp = 1000, .url = undefined });
|
||||
notifier.dispatch(.page_navigated, &.{ .timestamp = 1000, .url = undefined, .opts = .{} });
|
||||
try testing.expectEqual(114, tc.page_navigate);
|
||||
try testing.expectEqual(2006, tc.page_navigated);
|
||||
|
||||
// already unregistered, try anyways
|
||||
notifier.unregister(.page_navigated, &tc);
|
||||
notifier.dispatch(.page_navigate, &.{ .timestamp = 100, .url = undefined, .opts = .{} });
|
||||
notifier.dispatch(.page_navigated, &.{ .timestamp = 1000, .url = undefined });
|
||||
notifier.dispatch(.page_navigated, &.{ .timestamp = 1000, .url = undefined, .opts = .{} });
|
||||
try testing.expectEqual(114, tc.page_navigate);
|
||||
try testing.expectEqual(2006, tc.page_navigated);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user