mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-29 15:13:28 +00:00
The TL;DR is that this commit enforces the use of correct IDs, introduces a BrowserContext, and adds some CDP tests. These are the ids we need to be aware of when talking about CDP: - id - browserContextId - targetId - sessionId - loaderId - frameId The `id` is the only one that _should_ originate from the driver. It's attached to most messages and it's how we maintain a request -> response flow: when the server responds to a specific message, it echo's back the id from the requested message. (As opposed to out-of-band events sent from the server which won't have an `id`). When I say "id" from this point forward, I mean every id except for this req->res id. Every other id is created by the browser. Prior to this commit, we didn't really check incoming ids from the driver. If the driver said "attachToTarget" and included a targetId, we just assumed that this was the current targetId. This was aided by the fact that we only used hard-coded IDS. If _we_ only "create" a frameId of "FRAME-1", then it's tempting to think the driver will only ever send a frameId of "FRAME-1". The issue with this approach is that _if_ the browser and driver fall out of sync and there's only ever 1 browserContextId, 1 sessionId and 1 frameId, it's not impossible to imagine cases where we behave on the thing. Imagine this flow: - Driver asks for a new BrowserContext - Browser says OK, your browserContextId is 1 - Driver, for whatever reason, says close browserContextId 2 - Browser says, OK, but it doesn't check the id and just closes the only BrowserContext it knows about (which is 1) By both re-using the same hard-coded ids, and not verifying that the ids sent from the client correspond to the correct ids, any issues are going to be hard to debug. Currently LOADER_ID and FRAEM_ID are still hard-coded. Baby steps.
119 lines
3.7 KiB
Zig
119 lines
3.7 KiB
Zig
// Copyright (C) 2023-2024 Lightpanda (Selecy SAS)
|
|
//
|
|
// Francis Bouvier <francis@lightpanda.io>
|
|
// Pierre Tachoire <pierre@lightpanda.io>
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License as
|
|
// published by the Free Software Foundation, either version 3 of the
|
|
// License, or (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
const std = @import("std");
|
|
const cdp = @import("cdp.zig");
|
|
|
|
// TODO: hard coded data
|
|
const PROTOCOL_VERSION = "1.3";
|
|
const PRODUCT = "Chrome/124.0.6367.29";
|
|
const REVISION = "@9e6ded5ac1ff5e38d930ae52bd9aec09bd1a68e4";
|
|
const USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36";
|
|
const JS_VERSION = "12.4.254.8";
|
|
const DEV_TOOLS_WINDOW_ID = 1923710101;
|
|
|
|
pub fn processMessage(cmd: anytype) !void {
|
|
const action = std.meta.stringToEnum(enum {
|
|
getVersion,
|
|
setDownloadBehavior,
|
|
getWindowForTarget,
|
|
setWindowBounds,
|
|
}, cmd.input.action) orelse return error.UnknownMethod;
|
|
|
|
switch (action) {
|
|
.getVersion => return getVersion(cmd),
|
|
.setDownloadBehavior => return setDownloadBehavior(cmd),
|
|
.getWindowForTarget => return getWindowForTarget(cmd),
|
|
.setWindowBounds => return setWindowBounds(cmd),
|
|
}
|
|
}
|
|
|
|
fn getVersion(cmd: anytype) !void {
|
|
// TODO: pre-serialize?
|
|
return cmd.sendResult(.{
|
|
.protocolVersion = PROTOCOL_VERSION,
|
|
.product = PRODUCT,
|
|
.revision = REVISION,
|
|
.userAgent = USER_AGENT,
|
|
.jsVersion = JS_VERSION,
|
|
}, .{ .include_session_id = false });
|
|
}
|
|
|
|
// TODO: noop method
|
|
fn setDownloadBehavior(cmd: anytype) !void {
|
|
// const params = (try cmd.params(struct {
|
|
// behavior: []const u8,
|
|
// browserContextId: ?[]const u8 = null,
|
|
// downloadPath: ?[]const u8 = null,
|
|
// eventsEnabled: ?bool = null,
|
|
// })) orelse return error.InvalidParams;
|
|
|
|
return cmd.sendResult(null, .{ .include_session_id = false });
|
|
}
|
|
|
|
fn getWindowForTarget(cmd: anytype) !void {
|
|
// const params = (try cmd.params(struct {
|
|
// targetId: ?[]const u8 = null,
|
|
// })) orelse return error.InvalidParams;
|
|
|
|
return cmd.sendResult(.{ .windowId = DEV_TOOLS_WINDOW_ID, .bounds = .{
|
|
.windowState = "normal",
|
|
} }, .{});
|
|
}
|
|
|
|
// TODO: noop method
|
|
fn setWindowBounds(cmd: anytype) !void {
|
|
return cmd.sendResult(null, .{});
|
|
}
|
|
|
|
const testing = @import("testing.zig");
|
|
test "cdp.browser: getVersion" {
|
|
var ctx = testing.context();
|
|
defer ctx.deinit();
|
|
|
|
try ctx.processMessage(.{
|
|
.id = 32,
|
|
.method = "Browser.getVersion",
|
|
});
|
|
|
|
try ctx.expectSentCount(1);
|
|
try ctx.expectSentResult(.{
|
|
.protocolVersion = PROTOCOL_VERSION,
|
|
.product = PRODUCT,
|
|
.revision = REVISION,
|
|
.userAgent = USER_AGENT,
|
|
.jsVersion = JS_VERSION,
|
|
}, .{ .id = 32, .index = 0, .session_id = null });
|
|
}
|
|
|
|
test "cdp.browser: getWindowForTarget" {
|
|
var ctx = testing.context();
|
|
defer ctx.deinit();
|
|
|
|
try ctx.processMessage(.{
|
|
.id = 33,
|
|
.method = "Browser.getWindowForTarget",
|
|
});
|
|
|
|
try ctx.expectSentCount(1);
|
|
try ctx.expectSentResult(.{
|
|
.windowId = DEV_TOOLS_WINDOW_ID,
|
|
.bounds = .{ .windowState = "normal" },
|
|
}, .{ .id = 33, .index = 0, .session_id = null });
|
|
}
|