diff --git a/src/cdp/CDP.zig b/src/cdp/CDP.zig index 2ed72c51b..7c197eb16 100644 --- a/src/cdp/CDP.zig +++ b/src/cdp/CDP.zig @@ -714,6 +714,18 @@ pub const BrowserContext = struct { } pub fn createIsolatedWorld(self: *BrowserContext, world_name: []const u8, grant_universal_access: bool) !*IsolatedWorld { + // The name is the world's identity (matching Chrome). Clients re-issue + // this call after every navigation; appending a duplicate each time + // would grow the per-page context count without bound. + for (self.isolated_worlds.items) |world| { + if (std.mem.eql(u8, world.name, world_name)) { + if (world.grant_universal_access != grant_universal_access) { + log.warn(.cdp, "isolated world mismatch", .{ .name = world_name, .gua = grant_universal_access }); + } + return world; + } + } + const browser = &self.cdp.browser; const arena = try browser.arena_pool.acquire(.small, "IsolatedWorld"); errdefer arena.release(); diff --git a/src/cdp/domains/page.zig b/src/cdp/domains/page.zig index 8215990ee..9b334c43f 100644 --- a/src/cdp/domains/page.zig +++ b/src/cdp/domains/page.zig @@ -244,6 +244,17 @@ fn createIsolatedWorld(cmd: *CDP.Command) !void { const bc = cmd.browser_context orelse return error.BrowserContextNotLoaded; const world = try bc.createIsolatedWorld(params.worldName, params.grantUniveralAccess); + + // An existing world already has a live, inspector-registered context for + // the current document: return its id without re-registering. + if (world.context) |js_context| { + var ls: js.Local.Scope = undefined; + js_context.localScope(&ls); + defer ls.deinit(); + const context_id = bc.inspector_session.inspector.getContextId(&ls.local); + return cmd.sendResult(.{ .executionContextId = context_id }, .{}); + } + const frame = bc.mainFrame() orelse return error.FrameNotLoaded; const js_context = try world.createContext(frame); @@ -1127,6 +1138,36 @@ test "cdp.frame: getFrameTree" { } } +test "cdp.frame: createIsolatedWorld is idempotent per name" { + var ctx = try testing.context(); + defer ctx.deinit(); + + const bc = try ctx.loadBrowserContext(.{ .id = "BID-9", .url = "hi.html", .target_id = "FID-000000000X".* }); + + try ctx.processMessage(.{ .id = 20, .method = "Page.createIsolatedWorld", .params = .{ + .frameId = "FID-000000000X", + .worldName = "utility", + .grantUniveralAccess = true, + } }); + try testing.expectEqual(1, bc.isolated_worlds.items.len); + const world_context = bc.isolated_worlds.items[0].context.?; + + try ctx.processMessage(.{ .id = 21, .method = "Page.createIsolatedWorld", .params = .{ + .frameId = "FID-000000000X", + .worldName = "utility", + .grantUniveralAccess = true, + } }); + try testing.expectEqual(1, bc.isolated_worlds.items.len); + try testing.expectEqual(world_context, bc.isolated_worlds.items[0].context.?); + + try ctx.processMessage(.{ .id = 22, .method = "Page.createIsolatedWorld", .params = .{ + .frameId = "FID-000000000X", + .worldName = "other", + .grantUniveralAccess = true, + } }); + try testing.expectEqual(2, bc.isolated_worlds.items.len); +} + test "cdp.frame: child frame metadata" { var ctx = try testing.context(); defer ctx.deinit();