mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-12-15 15:58: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.
|
// indicates intention to navigate to another page on the next loop execution.
|
||||||
delayed_navigation: bool = false,
|
delayed_navigation: bool = false,
|
||||||
|
navigated_options: ?NavigatedOpts = null,
|
||||||
|
|
||||||
state_pool: *std.heap.MemoryPool(State),
|
state_pool: *std.heap.MemoryPool(State),
|
||||||
|
|
||||||
@@ -574,6 +575,11 @@ pub const Page = struct {
|
|||||||
});
|
});
|
||||||
|
|
||||||
self.session.browser.notification.dispatch(.page_navigated, &.{
|
self.session.browser.notification.dispatch(.page_navigated, &.{
|
||||||
|
.opts = .{
|
||||||
|
.cdp_id = opts.cdp_id,
|
||||||
|
.reason = opts.reason,
|
||||||
|
.method = opts.method,
|
||||||
|
},
|
||||||
.url = request_url,
|
.url = request_url,
|
||||||
.timestamp = timestamp(),
|
.timestamp = timestamp(),
|
||||||
});
|
});
|
||||||
@@ -584,6 +590,12 @@ pub const Page = struct {
|
|||||||
const owned_url = try self.arena.dupeZ(u8, request_url);
|
const owned_url = try self.arena.dupeZ(u8, request_url);
|
||||||
self.url = try URL.parse(owned_url, null);
|
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();
|
var headers = try self.http_client.newHeaders();
|
||||||
if (opts.header) |hdr| try headers.add(hdr);
|
if (opts.header) |hdr| try headers.add(hdr);
|
||||||
try self.requestCookie(.{ .is_navigation = true }).headersForRequest(self.arena, owned_url, &headers);
|
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 });
|
log.err(.browser, "document is complete", .{ .err = err });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std.debug.assert(self.navigated_options != null);
|
||||||
self.session.browser.notification.dispatch(.page_navigated, &.{
|
self.session.browser.notification.dispatch(.page_navigated, &.{
|
||||||
|
.opts = self.navigated_options.?,
|
||||||
.url = self.url.raw,
|
.url = self.url.raw,
|
||||||
.timestamp = timestamp(),
|
.timestamp = timestamp(),
|
||||||
});
|
});
|
||||||
@@ -1264,6 +1278,12 @@ pub const NavigateOpts = struct {
|
|||||||
force: bool = false,
|
force: bool = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const NavigatedOpts = struct {
|
||||||
|
cdp_id: ?i64 = null,
|
||||||
|
reason: NavigateReason = .address_bar,
|
||||||
|
method: Http.Method = .GET,
|
||||||
|
};
|
||||||
|
|
||||||
const IdleNotification = union(enum) {
|
const IdleNotification = union(enum) {
|
||||||
// hasn't started yet.
|
// hasn't started yet.
|
||||||
init,
|
init,
|
||||||
|
|||||||
@@ -545,13 +545,13 @@ pub fn BrowserContext(comptime CDP_T: type) type {
|
|||||||
|
|
||||||
pub fn onPageNavigate(ctx: *anyopaque, msg: *const Notification.PageNavigate) !void {
|
pub fn onPageNavigate(ctx: *anyopaque, msg: *const Notification.PageNavigate) !void {
|
||||||
const self: *Self = @ptrCast(@alignCast(ctx));
|
const self: *Self = @ptrCast(@alignCast(ctx));
|
||||||
defer self.resetNotificationArena();
|
return @import("domains/page.zig").pageNavigate(self, msg);
|
||||||
return @import("domains/page.zig").pageNavigate(self.notification_arena, self, msg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn onPageNavigated(ctx: *anyopaque, msg: *const Notification.PageNavigated) !void {
|
pub fn onPageNavigated(ctx: *anyopaque, msg: *const Notification.PageNavigated) !void {
|
||||||
const self: *Self = @ptrCast(@alignCast(ctx));
|
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 {
|
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
|
// detachTarget could be called, in which case, we still have a page doing
|
||||||
// things, but no session.
|
// things, but no session.
|
||||||
const session_id = bc.session_id orelse return;
|
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", .{
|
try cdp.sendEvent("Page.frameStartedLoading", .{
|
||||||
.frameId = target_id,
|
.frameId = target_id,
|
||||||
}, .{ .session_id = session_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.
|
// Drivers are sensitive to the order of events. Some more than others.
|
||||||
// The result for the Page.navigate seems like it _must_ come after
|
// 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 });
|
}, .{ .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) {
|
if (reason_ != null) {
|
||||||
try cdp.sendEvent("Page.frameClearedScheduledNavigation", .{
|
try cdp.sendEvent("Page.frameClearedScheduledNavigation", .{
|
||||||
.frameId = target_id,
|
.frameId = target_id,
|
||||||
@@ -293,30 +328,7 @@ pub fn pageNavigate(arena: Allocator, bc: anytype, event: *const Notification.Pa
|
|||||||
false,
|
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
|
// frameNavigated event
|
||||||
try cdp.sendEvent("Page.frameNavigated", .{
|
try cdp.sendEvent("Page.frameNavigated", .{
|
||||||
.type = "Navigation",
|
.type = "Navigation",
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ pub const Notification = struct {
|
|||||||
pub const PageNavigated = struct {
|
pub const PageNavigated = struct {
|
||||||
timestamp: u32,
|
timestamp: u32,
|
||||||
url: []const u8,
|
url: []const u8,
|
||||||
|
opts: page.NavigatedOpts,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const PageNetworkIdle = struct {
|
pub const PageNetworkIdle = struct {
|
||||||
@@ -326,7 +327,7 @@ test "Notification" {
|
|||||||
.url = undefined,
|
.url = undefined,
|
||||||
.opts = .{},
|
.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(14, tc.page_navigate);
|
||||||
try testing.expectEqual(6, tc.page_navigated);
|
try testing.expectEqual(6, tc.page_navigated);
|
||||||
|
|
||||||
@@ -336,7 +337,7 @@ test "Notification" {
|
|||||||
.url = undefined,
|
.url = undefined,
|
||||||
.opts = .{},
|
.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(14, tc.page_navigate);
|
||||||
try testing.expectEqual(6, tc.page_navigated);
|
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_navigate, &tc, TestClient.pageNavigate);
|
||||||
try notifier.register(.page_navigated, &tc, TestClient.pageNavigated);
|
try notifier.register(.page_navigated, &tc, TestClient.pageNavigated);
|
||||||
notifier.dispatch(.page_navigate, &.{ .timestamp = 100, .url = undefined, .opts = .{} });
|
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(114, tc.page_navigate);
|
||||||
try testing.expectEqual(1006, tc.page_navigated);
|
try testing.expectEqual(1006, tc.page_navigated);
|
||||||
|
|
||||||
notifier.unregister(.page_navigate, &tc);
|
notifier.unregister(.page_navigate, &tc);
|
||||||
notifier.dispatch(.page_navigate, &.{ .timestamp = 100, .url = undefined, .opts = .{} });
|
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(114, tc.page_navigate);
|
||||||
try testing.expectEqual(2006, tc.page_navigated);
|
try testing.expectEqual(2006, tc.page_navigated);
|
||||||
|
|
||||||
notifier.unregister(.page_navigated, &tc);
|
notifier.unregister(.page_navigated, &tc);
|
||||||
notifier.dispatch(.page_navigate, &.{ .timestamp = 100, .url = undefined, .opts = .{} });
|
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(114, tc.page_navigate);
|
||||||
try testing.expectEqual(2006, tc.page_navigated);
|
try testing.expectEqual(2006, tc.page_navigated);
|
||||||
|
|
||||||
// already unregistered, try anyways
|
// already unregistered, try anyways
|
||||||
notifier.unregister(.page_navigated, &tc);
|
notifier.unregister(.page_navigated, &tc);
|
||||||
notifier.dispatch(.page_navigate, &.{ .timestamp = 100, .url = undefined, .opts = .{} });
|
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(114, tc.page_navigate);
|
||||||
try testing.expectEqual(2006, tc.page_navigated);
|
try testing.expectEqual(2006, tc.page_navigated);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user