Merge pull request #1012 from lightpanda-io/cdp_detached
Some checks failed
e2e-test / zig build release (push) Has been cancelled
e2e-test / demo-scripts (push) Has been cancelled
e2e-test / cdp-and-hyperfine-bench (push) Has been cancelled
e2e-test / perf-fmt (push) Has been cancelled
zig-test / zig build dev (push) Has been cancelled
zig-test / browser fetch (push) Has been cancelled
zig-test / zig test (push) Has been cancelled
zig-test / perf-fmt (push) Has been cancelled

Don't assume that page events means the BrowserContext has a page
This commit is contained in:
Pierre Tachoire
2025-09-05 10:19:18 +02:00
committed by GitHub
3 changed files with 33 additions and 45 deletions

View File

@@ -179,8 +179,10 @@ fn arePatternsSupported(patterns: []RequestPattern) bool {
} }
pub fn requestIntercept(arena: Allocator, bc: anytype, intercept: *const Notification.RequestIntercept) !void { pub fn requestIntercept(arena: Allocator, bc: anytype, intercept: *const Notification.RequestIntercept) !void {
// unreachable because we _have_ to have a page. // detachTarget could be called, in which case, we still have a page doing
const session_id = bc.session_id orelse unreachable; // things, but no session.
const session_id = bc.session_id orelse return;
const target_id = bc.target_id orelse unreachable; const target_id = bc.target_id orelse unreachable;
// We keep it around to wait for modifications to the request. // We keep it around to wait for modifications to the request.
@@ -380,8 +382,10 @@ fn failRequest(cmd: anytype) !void {
} }
pub fn requestAuthRequired(arena: Allocator, bc: anytype, intercept: *const Notification.RequestAuthRequired) !void { pub fn requestAuthRequired(arena: Allocator, bc: anytype, intercept: *const Notification.RequestAuthRequired) !void {
// unreachable because we _have_ to have a page. // detachTarget could be called, in which case, we still have a page doing
const session_id = bc.session_id orelse unreachable; // things, but no session.
const session_id = bc.session_id orelse return;
const target_id = bc.target_id orelse unreachable; const target_id = bc.target_id orelse unreachable;
// We keep it around to wait for modifications to the request. // We keep it around to wait for modifications to the request.

View File

@@ -230,14 +230,10 @@ pub fn httpRequestFail(arena: Allocator, bc: anytype, msg: *const Notification.R
} }
pub fn httpRequestStart(arena: Allocator, bc: anytype, msg: *const Notification.RequestStart) !void { pub fn httpRequestStart(arena: Allocator, bc: anytype, msg: *const Notification.RequestStart) !void {
// Isn't possible to do a network request within a Browser (which our // detachTarget could be called, in which case, we still have a page doing
// notification is tied to), without a page. // things, but no session.
std.debug.assert(bc.session.page != null); const session_id = bc.session_id orelse return;
var cdp = bc.cdp;
// all unreachable because we _have_ to have a page.
const session_id = bc.session_id orelse unreachable;
const target_id = bc.target_id orelse unreachable; const target_id = bc.target_id orelse unreachable;
const page = bc.session.currentPage() orelse unreachable; const page = bc.session.currentPage() orelse unreachable;
@@ -248,22 +244,17 @@ pub fn httpRequestStart(arena: Allocator, bc: anytype, msg: *const Notification.
const transfer = msg.transfer; const transfer = msg.transfer;
// We're missing a bunch of fields, but, for now, this seems like enough // We're missing a bunch of fields, but, for now, this seems like enough
try cdp.sendEvent("Network.requestWillBeSent", .{ .requestId = try std.fmt.allocPrint(arena, "REQ-{d}", .{transfer.id}), .frameId = target_id, .loaderId = bc.loader_id, .documentUrl = DocumentUrlWriter.init(&page.url.uri), .request = TransferAsRequestWriter.init(transfer) }, .{ .session_id = session_id }); try bc.cdp.sendEvent("Network.requestWillBeSent", .{ .requestId = try std.fmt.allocPrint(arena, "REQ-{d}", .{transfer.id}), .frameId = target_id, .loaderId = bc.loader_id, .documentUrl = DocumentUrlWriter.init(&page.url.uri), .request = TransferAsRequestWriter.init(transfer) }, .{ .session_id = session_id });
} }
pub fn httpResponseHeaderDone(arena: Allocator, bc: anytype, msg: *const Notification.ResponseHeaderDone) !void { pub fn httpResponseHeaderDone(arena: Allocator, bc: anytype, msg: *const Notification.ResponseHeaderDone) !void {
// Isn't possible to do a network request within a Browser (which our // detachTarget could be called, in which case, we still have a page doing
// notification is tied to), without a page. // things, but no session.
std.debug.assert(bc.session.page != null); const session_id = bc.session_id orelse return;
var cdp = bc.cdp;
// all unreachable because we _have_ to have a page.
const session_id = bc.session_id orelse unreachable;
const target_id = bc.target_id orelse unreachable; const target_id = bc.target_id orelse unreachable;
// We're missing a bunch of fields, but, for now, this seems like enough // We're missing a bunch of fields, but, for now, this seems like enough
try cdp.sendEvent("Network.responseReceived", .{ try bc.cdp.sendEvent("Network.responseReceived", .{
.requestId = try std.fmt.allocPrint(arena, "REQ-{d}", .{msg.transfer.id}), .requestId = try std.fmt.allocPrint(arena, "REQ-{d}", .{msg.transfer.id}),
.loaderId = bc.loader_id, .loaderId = bc.loader_id,
.frameId = target_id, .frameId = target_id,
@@ -272,16 +263,11 @@ pub fn httpResponseHeaderDone(arena: Allocator, bc: anytype, msg: *const Notific
} }
pub fn httpRequestDone(arena: Allocator, bc: anytype, msg: *const Notification.RequestDone) !void { pub fn httpRequestDone(arena: Allocator, bc: anytype, msg: *const Notification.RequestDone) !void {
// Isn't possible to do a network request within a Browser (which our // detachTarget could be called, in which case, we still have a page doing
// notification is tied to), without a page. // things, but no session.
std.debug.assert(bc.session.page != null); const session_id = bc.session_id orelse return;
var cdp = bc.cdp; try bc.cdp.sendEvent("Network.loadingFinished", .{
// all unreachable because we _have_ to have a page.
const session_id = bc.session_id orelse unreachable;
try cdp.sendEvent("Network.loadingFinished", .{
.requestId = try std.fmt.allocPrint(arena, "REQ-{d}", .{msg.transfer.id}), .requestId = try std.fmt.allocPrint(arena, "REQ-{d}", .{msg.transfer.id}),
.encodedDataLength = msg.transfer.bytes_received, .encodedDataLength = msg.transfer.bytes_received,
}, .{ .session_id = session_id }); }, .{ .session_id = session_id });

View File

@@ -162,19 +162,17 @@ fn navigate(cmd: anytype) !void {
} }
pub fn pageNavigate(arena: Allocator, bc: anytype, event: *const Notification.PageNavigate) !void { pub fn pageNavigate(arena: Allocator, bc: anytype, event: *const Notification.PageNavigate) !void {
// I don't think it's possible that we get these notifications and don't // detachTarget could be called, in which case, we still have a page doing
// have these things setup. // things, but no session.
std.debug.assert(bc.session.page != null); const session_id = bc.session_id orelse return;
var cdp = bc.cdp;
bc.loader_id = bc.cdp.loader_id_gen.next(); bc.loader_id = bc.cdp.loader_id_gen.next();
const loader_id = bc.loader_id; const loader_id = bc.loader_id;
const target_id = bc.target_id orelse unreachable; const target_id = bc.target_id orelse unreachable;
const session_id = bc.session_id orelse unreachable;
bc.reset(); bc.reset();
var cdp = bc.cdp;
const reason_: ?[]const u8 = switch (event.opts.reason) { const reason_: ?[]const u8 = switch (event.opts.reason) {
.anchor => "anchorClick", .anchor => "anchorClick",
.script => "scriptInitiated", .script => "scriptInitiated",
@@ -292,16 +290,14 @@ pub fn pageCreated(bc: anytype, page: *Page) !void {
} }
pub fn pageNavigated(bc: anytype, event: *const Notification.PageNavigated) !void { pub fn pageNavigated(bc: anytype, event: *const Notification.PageNavigated) !void {
// I don't think it's possible that we get these notifications and don't // detachTarget could be called, in which case, we still have a page doing
// have these things setup. // things, but no session.
std.debug.assert(bc.session.page != null); const session_id = bc.session_id orelse return;
var cdp = bc.cdp;
const timestamp = event.timestamp;
const loader_id = bc.loader_id; const loader_id = bc.loader_id;
const target_id = bc.target_id orelse unreachable; const target_id = bc.target_id orelse unreachable;
const session_id = bc.session_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",
@@ -370,10 +366,12 @@ pub fn pageNetworkAlmostIdle(bc: anytype, event: *const Notification.PageNetwork
} }
fn sendPageLifecycle(bc: anytype, name: []const u8, timestamp: u32) !void { fn sendPageLifecycle(bc: anytype, name: []const u8, timestamp: u32) !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 loader_id = bc.loader_id;
const target_id = bc.target_id orelse unreachable; const target_id = bc.target_id orelse unreachable;
const session_id = bc.session_id orelse unreachable;
return bc.cdp.sendEvent("Page.lifecycleEvent", LifecycleEvent{ return bc.cdp.sendEvent("Page.lifecycleEvent", LifecycleEvent{
.name = name, .name = name,
.frameId = target_id, .frameId = target_id,