diff --git a/src/browser/browser.zig b/src/browser/browser.zig index 635390c4..c421498c 100644 --- a/src/browser/browser.zig +++ b/src/browser/browser.zig @@ -214,6 +214,31 @@ pub const Page = struct { }; } + // start js env. + // - auxData: extra data forwarded to the Inspector + // see Inspector.contextCreated + pub fn start(self: *Page, auxData: ?[]const u8) !void { + // start JS env + log.debug("start js env", .{}); + try self.session.env.start(); + + // register the module loader + try self.session.env.setModuleLoadFn(self.session, Session.fetchModule); + + // add global objects + log.debug("setup global env", .{}); + try self.session.env.bindGlobal(&self.session.window); + + // load polyfills + try polyfill.load(self.arena.allocator(), self.session.env); + + // inspector + if (self.session.inspector) |inspector| { + log.debug("inspector context created", .{}); + inspector.contextCreated(self.session.env, "", self.origin orelse "://", auxData); + } + } + // reset js env and mem arena. pub fn end(self: *Page) void { self.session.env.stop(); @@ -373,17 +398,6 @@ pub const Page = struct { // https://html.spec.whatwg.org/#read-html - // start JS env - // TODO load the js env concurrently with the HTML parsing. - log.debug("start js env", .{}); - try self.session.env.start(); - - // register the module loader - try self.session.env.setModuleLoadFn(self.session, Session.fetchModule); - - // load polyfills - try polyfill.load(alloc, self.session.env); - // inspector if (self.session.inspector) |inspector| { inspector.contextCreated(self.session.env, "", self.origin.?, auxData); @@ -395,10 +409,6 @@ pub const Page = struct { .httpClient = &self.session.httpClient, }); - // add global objects - log.debug("setup global env", .{}); - try self.session.env.bindGlobal(&self.session.window); - // browse the DOM tree to retrieve scripts // TODO execute the synchronous scripts during the HTL parsing. // TODO fetch the script resources concurrently but execute them in the diff --git a/src/cdp/cdp.zig b/src/cdp/cdp.zig index 95174a2d..5c056763 100644 --- a/src/cdp/cdp.zig +++ b/src/cdp/cdp.zig @@ -121,6 +121,7 @@ pub fn dispatch( pub const State = struct { executionContextId: u32 = 0, contextID: ?[]const u8 = null, + sessionID: ?[]const u8 = null, frameID: []const u8 = FrameID, url: []const u8 = URLBase, securityOrigin: []const u8 = URLBase, @@ -221,11 +222,11 @@ pub fn sendEvent( // ------ // TODO: hard coded IDs -pub const BrowserSessionID = "9559320D92474062597D9875C664CAC0"; -pub const ContextSessionID = "4FDC2CB760A23A220497A05C95417CF4"; +pub const BrowserSessionID = "BROWSERSESSIONID597D9875C664CAC0"; +pub const ContextSessionID = "CONTEXTSESSIONID0497A05C95417CF4"; pub const URLBase = "chrome://newtab/"; -pub const FrameID = "90D14BBD8AED408A0467AC93100BCDBE"; -pub const LoaderID = "CFC8BED824DD2FD56CF1EF33C965C79C"; +pub const LoaderID = "LOADERID24DD2FD56CF1EF33C965C79C"; +pub const FrameID = "FRAMEIDD8AED408A0467AC93100BCDBE"; pub const TimestampEvent = struct { timestamp: f64, diff --git a/src/cdp/page.zig b/src/cdp/page.zig index cf86297f..d453e9d5 100644 --- a/src/cdp/page.zig +++ b/src/cdp/page.zig @@ -331,8 +331,9 @@ fn navigate( // TODO: noop event, we have no env context at this point, is it necesarry? try sendEvent(alloc, ctx, "Runtime.executionContextsCleared", void, {}, input.sessionId); - // Launch navigate - const p = try ctx.browser.session.createPage(); + // Launch navigate, the page must have been created by a + // target.createTarget. + var p = ctx.browser.session.page orelse return error.NoPage; ctx.state.executionContextId += 1; const auxData = try std.fmt.allocPrint( alloc, diff --git a/src/cdp/runtime.zig b/src/cdp/runtime.zig index 3eef3f6c..f0c58b53 100644 --- a/src/cdp/runtime.zig +++ b/src/cdp/runtime.zig @@ -28,6 +28,7 @@ const result = cdp.result; const IncomingMessage = @import("msg.zig").IncomingMessage; const Input = @import("msg.zig").Input; const stringify = cdp.stringify; +const target = @import("target.zig"); const log = std.log.scoped(.cdp); @@ -116,6 +117,8 @@ fn sendInspector( } } + ctx.state.sessionID = msg.sessionId; + // remove awaitPromise true params // TODO: delete when Promise are correctly handled by zig-js-runtime if (method == .callFunctionOn or method == .evaluate) { diff --git a/src/cdp/target.zig b/src/cdp/target.zig index d21b4edd..e3120379 100644 --- a/src/cdp/target.zig +++ b/src/cdp/target.zig @@ -39,6 +39,7 @@ const Methods = enum { createTarget, closeTarget, sendMessageToTarget, + detachFromTarget, }; pub fn target( @@ -60,13 +61,14 @@ pub fn target( .createTarget => createTarget(alloc, msg, ctx), .closeTarget => closeTarget(alloc, msg, ctx), .sendMessageToTarget => sendMessageToTarget(alloc, msg, ctx), + .detachFromTarget => detachFromTarget(alloc, msg, ctx), }; } // TODO: hard coded IDs -const PageTargetID = "CFCD6EC01573CF29BB638E9DC0F52DDC"; -const BrowserTargetID = "2d2bdef9-1c95-416f-8c0e-83f3ab73a30c"; -const BrowserContextID = "65618675CB7D3585A95049E9DFE95EA9"; +pub const PageTargetID = "PAGETARGETIDB638E9DC0F52DDC"; +pub const BrowserTargetID = "browser9-targ-et6f-id0e-83f3ab73a30c"; +pub const BrowserContextID = "BROWSERCONTEXTIDA95049E9DFE95EA9"; // TODO: noop method fn setDiscoverTargets( @@ -138,7 +140,7 @@ fn setAutoAttach( .sessionId = cdp.BrowserSessionID, .targetInfo = .{ .targetId = PageTargetID, - .title = "New Incognito tab", + .title = "about:blank", .url = cdp.URLBase, .browserContextId = BrowserContextID, }, @@ -171,8 +173,8 @@ fn attachToTarget( const attached = AttachToTarget{ .sessionId = cdp.BrowserSessionID, .targetInfo = .{ - .targetId = PageTargetID, - .title = "New Incognito tab", + .targetId = input.params.targetId, + .title = "about:blank", .url = cdp.URLBase, .browserContextId = BrowserContextID, }, @@ -185,7 +187,7 @@ fn attachToTarget( sessionId: []const u8, }; const output = SessionId{ - .sessionId = input.sessionId orelse BrowserContextID, + .sessionId = input.sessionId orelse cdp.BrowserSessionID, }; return result(alloc, input.id, SessionId, output, null); } @@ -252,7 +254,7 @@ fn getBrowserContexts( return result(alloc, input.id, Resp, resp, null); } -const ContextID = "22648B09EDCCDD11109E2D4FEFBE4F89"; +const ContextID = "CONTEXTIDDCCDD11109E2D4FEFBE4F89"; // TODO: noop method fn createBrowserContext( @@ -313,8 +315,8 @@ fn disposeBrowserContext( } // TODO: hard coded IDs -const TargetID = "57356548460A8F29706A2ADF14316298"; -const LoaderID = "DD4A76F842AA389647D702B4D805F49A"; +const TargetID = "TARGETID460A8F29706A2ADF14316298"; +const LoaderID = "LOADERID42AA389647D702B4D805F49A"; fn createTarget( alloc: std.mem.Allocator, @@ -342,6 +344,23 @@ fn createTarget( ctx.state.securityOrigin = "://"; ctx.state.secureContextType = "InsecureScheme"; ctx.state.loaderID = LoaderID; + ctx.state.sessionID = msg.sessionId; + + // TODO stop the previous page instead? + if (ctx.browser.session.page != null) return error.pageAlreadyExists; + + // create the page + const p = try ctx.browser.session.createPage(); + ctx.state.executionContextId += 1; + // start the js env + const auxData = try std.fmt.allocPrint( + alloc, + // NOTE: we assume this is the default web page + "{{\"isDefault\":true,\"type\":\"default\",\"frameId\":\"{s}\"}}", + .{ctx.state.frameID}, + ); + defer alloc.free(auxData); + try p.start(auxData); // send targetCreated event const created = TargetCreated{ @@ -361,9 +380,10 @@ fn createTarget( .sessionId = cdp.ContextSessionID, .targetInfo = .{ .targetId = ctx.state.frameID, - .title = "", + .title = "about:blank", .url = ctx.state.url, .browserContextId = input.params.browserContextId orelse ContextID, + .attached = true, }, .waitingForDebugger = true, }; @@ -438,6 +458,8 @@ fn closeTarget( null, ); + if (ctx.browser.session.page != null) ctx.browser.session.page.?.end(); + return ""; } @@ -484,3 +506,18 @@ fn sendMessageToTarget( return ""; } + +// noop +fn detachFromTarget( + alloc: std.mem.Allocator, + msg: *IncomingMessage, + _: *Ctx, +) ![]const u8 { + // input + const input = try Input(void).get(alloc, msg); + defer input.deinit(); + log.debug("Req > id {d}, method {s}", .{ input.id, "target.detachFromTarget" }); + + // output + return result(alloc, input.id, bool, true, input.sessionId); +} diff --git a/src/main.zig b/src/main.zig index 84e23536..e4da1df2 100644 --- a/src/main.zig +++ b/src/main.zig @@ -326,6 +326,8 @@ pub fn main() !void { // page const page = try browser.session.createPage(); + try page.start(null); + defer page.end(); _ = page.navigate(opts.url, null) catch |err| switch (err) { error.UnsupportedUriScheme, error.UriMissingHost => { diff --git a/src/server.zig b/src/server.zig index 5e83c009..df25f4f6 100644 --- a/src/server.zig +++ b/src/server.zig @@ -175,6 +175,7 @@ pub const Ctx = struct { self.do(parts.msg) catch |err| { if (err != error.Closed) { log.err("do error: {any}", .{err}); + log.debug("last msg: {s}", .{parts.msg}); } }; } @@ -347,7 +348,7 @@ pub const Ctx = struct { const s = try std.fmt.allocPrint( allocator, tpl, - .{ msg_open, cdp.ContextSessionID }, + .{ msg_open, ctx.state.sessionID orelse cdp.ContextSessionID }, ); try ctx.send(s);