mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-29 15:13:28 +00:00
isolated world
This commit is contained in:
@@ -309,7 +309,7 @@ pub const Session = struct {
|
||||
|
||||
fn contextCreated(self: *Session, page: *Page) void {
|
||||
log.debug("inspector context created", .{});
|
||||
self.inspector.contextCreated(self.executor, "", (page.origin() catch "://") orelse "://", self.aux_data);
|
||||
self.inspector.contextCreated(self.executor, "", (page.origin() catch "://") orelse "://", aux_data, true);
|
||||
}
|
||||
|
||||
fn notify(self: *const Session, notification: *const Notification) void {
|
||||
|
||||
@@ -306,6 +306,26 @@ pub fn BrowserContext(comptime CDP_T: type) type {
|
||||
node_registry: Node.Registry,
|
||||
node_search_list: Node.Search.List,
|
||||
|
||||
isolated_world: ?IsolatedWorld,
|
||||
|
||||
pub fn createIsolatedWorld(
|
||||
self: *Self,
|
||||
world_name: []const u8,
|
||||
grant_universal_access: bool,
|
||||
) !void {
|
||||
if (self.isolated_world != null) return error.AlreadyExists;
|
||||
|
||||
const executor = try self.cdp.browser.env.startExecutor(@import("../browser/html/window.zig").Window, &self.session.state, self.session);
|
||||
errdefer self.cdp.browser.env.stopExecutor(executor);
|
||||
executor.context.exit();
|
||||
|
||||
self.isolated_world = .{
|
||||
.name = try self.session.arena.allocator().dupe(u8, world_name), // TODO allocator
|
||||
.grant_universal_access = grant_universal_access,
|
||||
.executor = executor,
|
||||
};
|
||||
}
|
||||
|
||||
const Self = @This();
|
||||
|
||||
fn init(self: *Self, id: []const u8, cdp: *CDP_T) !void {
|
||||
@@ -326,6 +346,7 @@ pub fn BrowserContext(comptime CDP_T: type) type {
|
||||
.page_life_cycle_events = false, // TODO; Target based value
|
||||
.node_registry = registry,
|
||||
.node_search_list = undefined,
|
||||
.isolated_world = null,
|
||||
};
|
||||
self.node_search_list = Node.Search.List.init(allocator, &self.node_registry);
|
||||
}
|
||||
@@ -437,6 +458,20 @@ pub fn BrowserContext(comptime CDP_T: type) type {
|
||||
};
|
||||
}
|
||||
|
||||
/// The current understanding. An isolated world lives in the same isolate, but a separated context.
|
||||
/// Clients creates this to be able to create variables and run code without interfering
|
||||
/// with the normal namespace and values of the webpage. Similar to the main context we need to pretend to recreate it after
|
||||
/// a executionContextsCleared event which happens when navigating to a new page. A client can have a command be executed
|
||||
/// in the isolated world by using its Context ID or the worldName.
|
||||
/// grantUniveralAccess Indecated whether the isolated world has access to objects like the DOM or other JS Objects.
|
||||
/// Generally the client needs to resolve a node into the isolated world to be able to work with it.
|
||||
/// An object id is unique across all contexts, different object ids can refer to the same Node in different contexts.
|
||||
pub const IsolatedWorld = struct {
|
||||
name: []const u8,
|
||||
grant_universal_access: bool,
|
||||
executor: *@import("../browser/env.zig").Env.Executor,
|
||||
};
|
||||
|
||||
// This is a generic because when we send a result we have two different
|
||||
// behaviors. Normally, we're sending the result to the client. But in some cases
|
||||
// we want to capture the result. So we want the command.sendResult to be
|
||||
|
||||
@@ -127,12 +127,18 @@ fn resolveNode(cmd: anytype) !void {
|
||||
objectGroup: ?[]const u8 = null,
|
||||
executionContextId: ?u32 = null,
|
||||
})) orelse return error.InvalidParams;
|
||||
if (params.nodeId == null or params.backendNodeId != null or params.executionContextId != null) {
|
||||
return error.NotYetImplementedParams;
|
||||
}
|
||||
|
||||
const bc = cmd.browser_context orelse return error.BrowserContextNotLoaded;
|
||||
const node = bc.node_registry.lookup_by_id.get(params.nodeId.?) orelse return error.UnknownNode;
|
||||
|
||||
var executor = bc.session.executor;
|
||||
if (params.executionContextId) |context_id| {
|
||||
if (executor.context.debugContextId() != context_id) {
|
||||
const isolated_world = bc.isolated_world orelse return error.ContextNotFound;
|
||||
executor = isolated_world.executor;
|
||||
if (executor.context.debugContextId() != context_id) return error.ContextNotFound;
|
||||
}
|
||||
}
|
||||
const input_node_id = if (params.nodeId) |node_id| node_id else params.backendNodeId orelse return error.InvalidParams;
|
||||
const node = bc.node_registry.lookup_by_id.get(input_node_id) orelse return error.UnknownNode;
|
||||
|
||||
// node._node is a *parser.Node we need this to be able to find its most derived type e.g. Node -> Element -> HTMLElement
|
||||
// So we use the Node.Union when retrieve the value from the environment
|
||||
|
||||
@@ -97,36 +97,27 @@ fn addScriptToEvaluateOnNewDocument(cmd: anytype) !void {
|
||||
}, .{});
|
||||
}
|
||||
|
||||
// TODO: hard coded method
|
||||
fn createIsolatedWorld(cmd: anytype) !void {
|
||||
_ = cmd.browser_context orelse return error.BrowserContextNotLoaded;
|
||||
|
||||
const session_id = cmd.input.session_id orelse return error.SessionIdRequired;
|
||||
|
||||
const params = (try cmd.params(struct {
|
||||
frameId: []const u8,
|
||||
worldName: []const u8,
|
||||
grantUniveralAccess: bool,
|
||||
})) orelse return error.InvalidParams;
|
||||
if (!params.grantUniveralAccess) {
|
||||
std.debug.print("grantUniveralAccess == false is not yet implemented", .{});
|
||||
// When grantUniveralAccess == false and the client attempts to resolve
|
||||
// or otherwise access a DOM or other JS Object from another context that should fail.
|
||||
}
|
||||
const bc = cmd.browser_context orelse return error.BrowserContextNotLoaded;
|
||||
|
||||
// noop executionContextCreated event
|
||||
try cmd.sendEvent("Runtime.executionContextCreated", .{
|
||||
.context = runtime.ExecutionContextCreated{
|
||||
.id = 0,
|
||||
.origin = "",
|
||||
.name = params.worldName,
|
||||
// TODO: hard coded ID
|
||||
.uniqueId = "7102379147004877974.3265385113993241162",
|
||||
.auxData = .{
|
||||
.isDefault = false,
|
||||
.type = "isolated",
|
||||
.frameId = params.frameId,
|
||||
},
|
||||
},
|
||||
}, .{ .session_id = session_id });
|
||||
try bc.createIsolatedWorld(params.worldName, params.grantUniveralAccess); // orelse return error.IsolatedWorldAlreadyExists;
|
||||
|
||||
// Create the auxdata json from
|
||||
const aux_json = try std.fmt.allocPrint(cmd.arena, "{{\"isDefault\":false,\"type\":\"isolated\",\"frameId\":\"{s}\"}}", .{params.frameId});
|
||||
bc.session.inspector.contextCreated(bc.isolated_world.?.executor, bc.isolated_world.?.name, "", aux_json, false);
|
||||
|
||||
return cmd.sendResult(.{
|
||||
.executionContextId = 0,
|
||||
.executionContextId = bc.isolated_world.?.executor.context.debugContextId(),
|
||||
}, .{});
|
||||
}
|
||||
|
||||
@@ -222,7 +213,24 @@ pub fn pageNavigate(bc: anytype, event: *const Notification.PageNavigate) !void
|
||||
|
||||
// Send Runtime.executionContextsCleared event
|
||||
// TODO: noop event, we have no env context at this point, is it necesarry?
|
||||
// When we actually recreated the context we should have the inspector send this event, see: resetContextGroup
|
||||
try cdp.sendEvent("Runtime.executionContextsCleared", null, .{ .session_id = session_id });
|
||||
|
||||
if (bc.isolated_world != null) {
|
||||
const aux_json = try std.fmt.allocPrint(
|
||||
bc.session.arena.allocator(), // TODO change this
|
||||
"{{\"isDefault\":false,\"type\":\"isolated\",\"frameId\":\"{s}\"}}",
|
||||
.{bc.target_id.?}, // TODO check this
|
||||
);
|
||||
|
||||
bc.session.inspector.contextCreated(
|
||||
bc.isolated_world.?.executor,
|
||||
bc.isolated_world.?.name,
|
||||
"://",
|
||||
aux_json,
|
||||
false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pageNavigated(bc: anytype, event: *const Notification.PageNavigated) !void {
|
||||
|
||||
@@ -1359,14 +1359,23 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
|
||||
self.session.dispatchProtocolMessage(self.isolate, msg);
|
||||
}
|
||||
|
||||
// From CDP docs
|
||||
// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#type-ExecutionContextDescription
|
||||
// ----
|
||||
// - name: Human readable name describing given context.
|
||||
// - origin: Execution context origin (ie. URL who initialised the request)
|
||||
// - auxData: Embedder-specific auxiliary data likely matching
|
||||
// {isDefault: boolean, type: 'default'|'isolated'|'worker', frameId: string}
|
||||
// - is_default_context: Whether the execution context is default, should match the auxData
|
||||
pub fn contextCreated(
|
||||
self: *const Inspector,
|
||||
executor: *const Executor,
|
||||
name: []const u8,
|
||||
origin: []const u8,
|
||||
aux_data: ?[]const u8,
|
||||
is_default_context: bool,
|
||||
) void {
|
||||
self.inner.contextCreated(executor.context, name, origin, aux_data);
|
||||
self.inner.contextCreated(executor.context, name, origin, aux_data, is_default_context);
|
||||
}
|
||||
|
||||
// Retrieves the RemoteObject for a given value.
|
||||
|
||||
Reference in New Issue
Block a user