re-enable minimum viable CDP server

This commit is contained in:
Karl Seguin
2025-10-28 18:56:03 +08:00
parent cdd31353c5
commit d3973172e8
25 changed files with 1512 additions and 1399 deletions

View File

@@ -122,6 +122,135 @@ pub fn isCompleteHTTPUrl(url: []const u8) bool {
std.ascii.startsWithIgnoreCase(url, "ftp://");
}
pub fn getUsername(raw: [:0]const u8) []const u8 {
const user_info = getUserInfo(raw) orelse return "";
const pos = std.mem.indexOfScalarPos(u8, user_info, 0, ':') orelse return user_info;
return user_info[0..pos];
}
pub fn getPassword(raw: [:0]const u8) []const u8 {
const user_info = getUserInfo(raw) orelse return "";
const pos = std.mem.indexOfScalarPos(u8, user_info, 0, ':') orelse return "";
return user_info[pos + 1 ..];
}
pub fn getPathname(raw: [:0]const u8) []const u8 {
const protocol_end = std.mem.indexOf(u8, raw, "://") orelse 0;
const path_start = std.mem.indexOfScalarPos(u8, raw, if (protocol_end > 0) protocol_end + 3 else 0, '/') orelse raw.len;
const query_or_hash_start = std.mem.indexOfAnyPos(u8, raw, path_start, "?#") orelse raw.len;
if (path_start >= query_or_hash_start) {
if (std.mem.indexOf(u8, raw, "://") != null) return "/";
return "";
}
return raw[path_start..query_or_hash_start];
}
pub fn getProtocol(raw: [:0]const u8) []const u8 {
const pos = std.mem.indexOfScalarPos(u8, raw, 0, ':') orelse return "";
return raw[0 .. pos + 1];
}
pub fn getHostname(raw: [:0]const u8) []const u8 {
const host = getHost(raw);
const pos = std.mem.lastIndexOfScalar(u8, host, ':') orelse return host;
return host[0..pos];
}
pub fn getPort(raw: [:0]const u8) []const u8 {
const host = getHost(raw);
const pos = std.mem.lastIndexOfScalar(u8, host, ':') orelse return "";
if (pos + 1 >= host.len) {
return "";
}
for (host[pos + 1 ..]) |c| {
if (c < '0' or c > '9') {
return "";
}
}
return host[pos + 1 ..];
}
pub fn getSearch(raw: [:0]const u8) []const u8 {
const pos = std.mem.indexOfScalarPos(u8, raw, 0, '?') orelse return "";
const query_part = raw[pos..];
if (std.mem.indexOfScalarPos(u8, query_part, 0, '#')) |fragment_start| {
return query_part[0..fragment_start];
}
return query_part;
}
pub fn getHash(raw: [:0]const u8) []const u8 {
const start = std.mem.indexOfScalarPos(u8, raw, 0, '#') orelse return "";
return raw[start..];
}
pub fn getOrigin(allocator: Allocator, raw: [:0]const u8) !?[]const u8 {
const port = getPort(raw);
const protocol = getProtocol(raw);
const hostname = getHostname(raw);
const p = std.meta.stringToEnum(KnownProtocol, getProtocol(raw)) orelse return null;
const include_port = blk: {
if (port.len == 0) {
break :blk false;
}
if (p == .@"https:" and std.mem.eql(u8, port, "443")) {
break :blk false;
}
if (p == .@"http:" and std.mem.eql(u8, port, "80")) {
break :blk false;
}
break :blk true;
};
if (include_port) {
return try std.fmt.allocPrint(allocator, "{s}//{s}:{s}", .{ protocol, hostname, port });
}
return try std.fmt.allocPrint(allocator, "{s}//{s}", .{ protocol, hostname });
}
fn getUserInfo(raw: [:0]const u8) ?[]const u8 {
const scheme_end = std.mem.indexOf(u8, raw, "://") orelse return null;
const authority_start = scheme_end + 3;
const pos = std.mem.indexOfScalar(u8, raw[authority_start..], '@') orelse return null;
const path_start = std.mem.indexOfScalarPos(u8, raw, authority_start, '/') orelse raw.len;
const full_pos = authority_start + pos;
if (full_pos < path_start) {
return raw[authority_start..full_pos];
}
return null;
}
fn getHost(raw: [:0]const u8) []const u8 {
const scheme_end = std.mem.indexOf(u8, raw, "://") orelse return "";
var authority_start = scheme_end + 3;
if (std.mem.indexOf(u8, raw[authority_start..], "@")) |pos| {
authority_start += pos + 1;
}
const authority = raw[authority_start..];
const path_start = std.mem.indexOfAny(u8, authority, "/?#") orelse return authority;
return authority[0..path_start];
}
const KnownProtocol = enum {
@"http:",
@"https:",
};
const testing = @import("../testing.zig");
test "URL: isCompleteHTTPUrl" {
try testing.expectEqual(true, isCompleteHTTPUrl("http://example.com/about"));

View File

@@ -467,4 +467,5 @@ pub const JsApis = flattenTypes(&.{
@import("../webapi/storage/storage.zig"),
@import("../webapi/URL.zig"),
@import("../webapi/Window.zig"),
@import("../webapi/MutationObserver.zig"),
});

View File

@@ -141,7 +141,7 @@ pub fn wait(self: *Session, wait_ms: u32) WaitResult {
return .done;
};
if (self.page) |*page| {
if (self.page) |page| {
return page.wait(wait_ms);
}
return .no_page;

View File

@@ -0,0 +1,23 @@
const js = @import("../js/js.zig");
// @ZIGDOM (haha, bet you wish you hadn't opened this file)
// puppeteer's startup script creates a MutationObserver, even if it doesn't use
// it in simple scripts. This not-even-a-skeleton is required for puppeteer/cdp.js
// to run
const MutationObserver = @This();
pub fn init() MutationObserver {
return .{};
}
pub const JsApi = struct {
pub const bridge = js.Bridge(MutationObserver);
pub const Meta = struct {
pub const name = "MutationObserver";
pub const prototype_chain = bridge.prototypeChain();
pub var class_index: u16 = 0;
};
pub const constructor = bridge.constructor(MutationObserver.init, .{});
};

View File

@@ -340,6 +340,9 @@ pub fn setNodeValue(self: *const Node, value: ?[]const u8, page: *Page) !void {
}
pub fn format(self: *Node, writer: *std.Io.Writer) !void {
// // If you need extra debugging:
// return @import("../dump.zig").deep(self, .{}, writer);
return switch (self._type) {
.cdata => |cd| cd.format(writer),
.element => |el| writer.print("{f}", .{el}),

View File

@@ -39,14 +39,22 @@ pub fn TreeWalker(comptime mode: Mode) type {
self._next = children.first();
} else if (node._child_link.next) |n| {
self._next = Node.linkToNode(n);
} else if (node._parent) |n| {
if (n == self._root) {
self._next = null;
} else {
self._next = Node.linkToNodeOrNull(n._child_link.next);
}
} else {
self._next = null;
// No children, no next sibling - walk up until we find a next sibling or hit root
var current = node._parent;
while (current) |parent| {
if (parent == self._root) {
self._next = null;
break;
}
if (parent._child_link.next) |next_sibling| {
self._next = Node.linkToNode(next_sibling);
break;
}
current = parent._parent;
} else {
self._next = null;
}
}
return node;
}

View File

@@ -1,6 +1,7 @@
const std = @import("std");
const js = @import("../js/js.zig");
const U = @import("../URL.zig");
const Page = @import("../Page.zig");
const URLSearchParams = @import("net/URLSearchParams.zig");
@@ -42,106 +43,42 @@ pub fn init(url: [:0]const u8, base_: ?[:0]const u8, page: *Page) !*URL {
}
pub fn getUsername(self: *const URL) []const u8 {
const user_info = self.getUserInfo() orelse return "";
const pos = std.mem.indexOfScalarPos(u8, user_info, 0, ':') orelse return user_info;
return user_info[0..pos];
return U.getUsername(self._raw);
}
pub fn getPassword(self: *const URL) []const u8 {
const user_info = self.getUserInfo() orelse return "";
const pos = std.mem.indexOfScalarPos(u8, user_info, 0, ':') orelse return "";
return user_info[pos + 1 ..];
return U.getPassword(self._raw);
}
pub fn getPathname(self: *const URL) []const u8 {
const raw = self._raw;
const protocol_end = std.mem.indexOf(u8, raw, "://") orelse 0;
const path_start = std.mem.indexOfScalarPos(u8, raw, if (protocol_end > 0) protocol_end + 3 else 0, '/') orelse raw.len;
const query_or_hash_start = std.mem.indexOfAnyPos(u8, raw, path_start, "?#") orelse raw.len;
if (path_start >= query_or_hash_start) {
if (std.mem.indexOf(u8, raw, "://") != null) return "/";
return "";
}
return raw[path_start..query_or_hash_start];
return U.getPathname(self._raw);
}
pub fn getProtocol(self: *const URL) []const u8 {
const raw = self._raw;
const pos = std.mem.indexOfScalarPos(u8, raw, 0, ':') orelse return "";
return raw[0 .. pos + 1];
return U.getProtocol(self._raw);
}
pub fn getHostname(self: *const URL) []const u8 {
const host = self.getHost();
const pos = std.mem.lastIndexOfScalar(u8, host, ':') orelse return host;
return host[0..pos];
return U.getHostname(self._raw);
}
pub fn getPort(self: *const URL) []const u8 {
const host = self.getHost();
const pos = std.mem.lastIndexOfScalar(u8, host, ':') orelse return "";
if (pos + 1 >= host.len) {
return "";
}
for (host[pos + 1 ..]) |c| {
if (c < '0' or c > '9') {
return "";
}
}
return host[pos + 1 ..];
return U.getPort(self._raw);
}
pub fn getOrigin(self: *const URL, page: *const Page) ![]const u8 {
const port = self.getPort();
const protocol = self.getProtocol();
const hostname = self.getHostname();
const p = std.meta.stringToEnum(KnownProtocol, self.getProtocol()) orelse {
return (try U.getOrigin(page.call_arena, self._raw)) orelse {
// yes, a null string, that's what the spec wants
return "null";
};
const include_port = blk: {
if (port.len == 0) {
break :blk false;
}
if (p == .@"https:" and std.mem.eql(u8, port, "443")) {
break :blk false;
}
if (p == .@"http:" and std.mem.eql(u8, port, "80")) {
break :blk false;
}
break :blk true;
};
if (include_port) {
return std.fmt.allocPrint(page.call_arena, "{s}//{s}:{s}", .{ protocol, hostname, port });
}
return std.fmt.allocPrint(page.call_arena, "{s}//{s}", .{ protocol, hostname });
}
pub fn getSearch(self: *const URL) []const u8 {
const raw = self._raw;
const pos = std.mem.indexOfScalarPos(u8, raw, 0, '?') orelse return "";
const query_part = raw[pos..];
if (std.mem.indexOfScalarPos(u8, query_part, 0, '#')) |fragment_start| {
return query_part[0..fragment_start];
}
return query_part;
return U.getSearch(self._raw);
}
pub fn getHash(self: *const URL) []const u8 {
const raw = self._raw;
const start = std.mem.indexOfScalarPos(u8, raw, 0, '#') orelse return "";
return raw[start..];
return U.getHash(self._raw);
}
pub fn getSearchParams(self: *URL, page: *Page) !*URLSearchParams {

View File

@@ -9,6 +9,7 @@ pub fn registerTypes() []const type {
}
pub const Jar = @import("cookie.zig").Jar;
pub const Cookie =@import("cookie.zig").Cookie;
pub const Shed = struct {
_origins: std.StringHashMapUnmanaged(*Bucket) = .empty,

File diff suppressed because it is too large Load Diff

View File

@@ -24,12 +24,12 @@ const log = @import("../log.zig");
const js = @import("../browser/js/js.zig");
const polyfill = @import("../browser/polyfill/polyfill.zig");
const App = @import("../app.zig").App;
const Browser = @import("../browser/browser.zig").Browser;
const Session = @import("../browser/session.zig").Session;
const Page = @import("../browser/page.zig").Page;
const App = @import("../App.zig");
const Browser = @import("../browser/Browser.zig");
const Session = @import("../browser/Session.zig");
const Page = @import("../browser/Page.zig");
const Incrementing = @import("../id.zig").Incrementing;
const Notification = @import("../notification.zig").Notification;
const Notification = @import("../Notification.zig");
const LogInterceptor = @import("domains/log.zig").LogInterceptor;
const InterceptState = @import("domains/fetch.zig").InterceptState;
@@ -37,7 +37,7 @@ pub const URL_BASE = "chrome://newtab/";
pub const LOADER_ID = "LOADERID24DD2FD56CF1EF33C965C79C";
pub const CDP = CDPT(struct {
const Client = *@import("../server.zig").Client;
const Client = *@import("../Server.zig").Client;
});
const SessionIdGen = Incrementing(u32, "SID");
@@ -117,7 +117,7 @@ pub fn CDPT(comptime TypeProvider: type) type {
// timeouts (or http events) which are ready to be processed.
pub fn hasPage() bool {}
pub fn pageWait(self: *Self, ms: i32) Session.WaitResult {
pub fn pageWait(self: *Self, ms: u32) Session.WaitResult {
const session = &(self.browser.session orelse return .no_page);
return session.wait(ms);
}
@@ -203,7 +203,8 @@ pub fn CDPT(comptime TypeProvider: type) type {
},
5 => switch (@as(u40, @bitCast(domain[0..5].*))) {
asUint(u40, "Fetch") => return @import("domains/fetch.zig").processMessage(command),
asUint(u40, "Input") => return @import("domains/input.zig").processMessage(command),
// @ZIGDOM
// asUint(u40, "Input") => return @import("domains/input.zig").processMessage(command),
else => {},
},
6 => switch (@as(u48, @bitCast(domain[0..6].*))) {
@@ -286,7 +287,8 @@ pub fn CDPT(comptime TypeProvider: type) type {
}
pub fn BrowserContext(comptime CDP_T: type) type {
const Node = @import("Node.zig");
// @ZIGMOD
// const Node = @import("Node.zig");
return struct {
id: []const u8,
@@ -326,8 +328,9 @@ pub fn BrowserContext(comptime CDP_T: type) type {
security_origin: []const u8,
page_life_cycle_events: bool,
secure_context_type: []const u8,
node_registry: Node.Registry,
node_search_list: Node.Search.List,
// @ZIGDOM
// node_registry: Node.Registry,
// node_search_list: Node.Search.List,
inspector: js.Inspector,
isolated_worlds: std.ArrayListUnmanaged(IsolatedWorld),
@@ -360,8 +363,9 @@ pub fn BrowserContext(comptime CDP_T: type) type {
const inspector = try cdp.browser.env.newInspector(arena, self);
var registry = Node.Registry.init(allocator);
errdefer registry.deinit();
// @ZIGDOM
// var registry = Node.Registry.init(allocator);
// errdefer registry.deinit();
self.* = .{
.id = id,
@@ -374,8 +378,9 @@ pub fn BrowserContext(comptime CDP_T: type) type {
.secure_context_type = "Secure", // TODO = enum
.loader_id = LOADER_ID,
.page_life_cycle_events = false, // TODO; Target based value
.node_registry = registry,
.node_search_list = undefined,
// @ZIGDOM
// .node_registry = registry,
// .node_search_list = undefined,
.isolated_worlds = .empty,
.inspector = inspector,
.notification_arena = cdp.notification_arena.allocator(),
@@ -383,7 +388,8 @@ pub fn BrowserContext(comptime CDP_T: type) type {
.captured_responses = .empty,
.log_interceptor = LogInterceptor(Self).init(allocator, self),
};
self.node_search_list = Node.Search.List.init(allocator, &self.node_registry);
// ZIGDOM
// self.node_search_list = Node.Search.List.init(allocator, &self.node_registry);
errdefer self.deinit();
try cdp.browser.notification.register(.page_remove, self, onPageRemove);
@@ -418,8 +424,9 @@ pub fn BrowserContext(comptime CDP_T: type) type {
world.deinit();
}
self.isolated_worlds.clearRetainingCapacity();
self.node_registry.deinit();
self.node_search_list.deinit();
// @ZIGDOM
// self.node_registry.deinit();
// self.node_search_list.deinit();
self.cdp.browser.notification.unregisterAll(self);
if (self.http_proxy_changed) {
@@ -433,8 +440,10 @@ pub fn BrowserContext(comptime CDP_T: type) type {
}
pub fn reset(self: *Self) void {
self.node_registry.reset();
self.node_search_list.reset();
// @ZIGDOM
_ = self;
// self.node_registry.reset();
// self.node_search_list.reset();
}
pub fn createIsolatedWorld(self: *Self, world_name: []const u8, grant_universal_access: bool) !*IsolatedWorld {
@@ -453,19 +462,20 @@ pub fn BrowserContext(comptime CDP_T: type) type {
return world;
}
pub fn nodeWriter(self: *Self, root: *const Node, opts: Node.Writer.Opts) Node.Writer {
return .{
.root = root,
.depth = opts.depth,
.exclude_root = opts.exclude_root,
.registry = &self.node_registry,
};
}
// @ZIGDOM
// pub fn nodeWriter(self: *Self, root: *const Node, opts: Node.Writer.Opts) Node.Writer {
// return .{
// .root = root,
// .depth = opts.depth,
// .exclude_root = opts.exclude_root,
// .registry = &self.node_registry,
// };
// }
pub fn getURL(self: *const Self) ?[]const u8 {
pub fn getURL(self: *const Self) ?[:0]const u8 {
const page = self.session.currentPage() orelse return null;
const raw_url = page.url.raw;
return if (raw_url.len == 0) null else raw_url;
const url = page.url;
return if (url.len == 0) null else url;
}
pub fn networkEnable(self: *Self) !void {

File diff suppressed because it is too large Load Diff

View File

@@ -23,7 +23,7 @@ const log = @import("../../log.zig");
const network = @import("network.zig");
const Http = @import("../../http/Http.zig");
const Notification = @import("../../notification.zig").Notification;
const Notification = @import("../../Notification.zig");
pub fn processMessage(cmd: anytype) !void {
const action = std.meta.stringToEnum(enum {

View File

@@ -17,7 +17,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
const std = @import("std");
const Page = @import("../../browser/page.zig").Page;
const Page = @import("../../browser/Page.zig");
pub fn processMessage(cmd: anytype) !void {
const action = std.meta.stringToEnum(enum {

View File

@@ -101,7 +101,7 @@ pub fn LogInterceptor(comptime BC: type) type {
.fatal => "error",
},
.text = self.allocating.written(),
.timestamp = @import("../../datetime.zig").milliTimestamp(),
.timestamp = @import("../../datetime.zig").milliTimestamp(.monotonic),
},
}, .{
.session_id = self.bc.session_id,

View File

@@ -21,7 +21,7 @@ const Allocator = std.mem.Allocator;
const CdpStorage = @import("storage.zig");
const Transfer = @import("../../http/Client.zig").Transfer;
const Notification = @import("../../notification.zig").Notification;
const Notification = @import("../../Notification.zig");
pub fn processMessage(cmd: anytype) !void {
const action = std.meta.stringToEnum(enum {
@@ -87,7 +87,7 @@ fn setExtraHTTPHeaders(cmd: anytype) !void {
return cmd.sendResult(null, .{});
}
const Cookie = @import("../../browser/storage/storage.zig").Cookie;
const Cookie = @import("../../browser/webapi/storage/storage.zig").Cookie;
// Only matches the cookie on provided parameters
fn cookieMatches(cookie: *const Cookie, name: []const u8, domain: ?[]const u8, path: ?[]const u8) bool {
@@ -173,7 +173,7 @@ fn getCookies(cmd: anytype) !void {
const params = (try cmd.params(GetCookiesParam)) orelse GetCookiesParam{};
// If not specified, use the URLs of the page and all of its subframes. TODO subframes
const page_url = if (bc.session.page) |*page| page.url.raw else null; // @speed: avoid repasing the URL
const page_url = if (bc.session.page) |page| page.url else null;
const param_urls = params.urls orelse &[_][]const u8{page_url orelse return error.InvalidParams};
var urls = try std.ArrayListUnmanaged(CdpStorage.PreparedUri).initCapacity(cmd.arena, param_urls.len);
@@ -247,7 +247,7 @@ pub fn httpRequestStart(arena: Allocator, bc: anytype, msg: *const Notification.
.requestId = try std.fmt.allocPrint(arena, "REQ-{d}", .{transfer.id}),
.frameId = target_id,
.loaderId = bc.loader_id,
.documentUrl = DocumentUrlWriter.init(&page.url.uri),
.documentUrl = page.url,
.request = TransferAsRequestWriter.init(transfer),
.initiator = .{ .type = "other" },
}, .{ .session_id = session_id });
@@ -416,34 +416,35 @@ const TransferAsResponseWriter = struct {
}
};
const DocumentUrlWriter = struct {
uri: *std.Uri,
// @ZIGDOM - do we still need this? just send the full URL?
// const DocumentUrlWriter = struct {
// uri: *std.Uri,
fn init(uri: *std.Uri) DocumentUrlWriter {
return .{
.uri = uri,
};
}
// fn init(uri: *std.Uri) DocumentUrlWriter {
// return .{
// .uri = uri,
// };
// }
pub fn jsonStringify(self: *const DocumentUrlWriter, jws: anytype) !void {
self._jsonStringify(jws) catch return error.WriteFailed;
}
fn _jsonStringify(self: *const DocumentUrlWriter, jws: anytype) !void {
const writer = jws.writer;
// pub fn jsonStringify(self: *const DocumentUrlWriter, jws: anytype) !void {
// self._jsonStringify(jws) catch return error.WriteFailed;
// }
// fn _jsonStringify(self: *const DocumentUrlWriter, jws: anytype) !void {
// const writer = jws.writer;
try jws.beginWriteRaw();
try writer.writeByte('\"');
try self.uri.writeToStream(writer, .{
.scheme = true,
.authentication = true,
.authority = true,
.path = true,
.query = true,
});
try writer.writeByte('\"');
jws.endWriteRaw();
}
};
// try jws.beginWriteRaw();
// try writer.writeByte('\"');
// try self.uri.writeToStream(writer, .{
// .scheme = true,
// .authentication = true,
// .authority = true,
// .path = true,
// .query = true,
// });
// try writer.writeByte('\"');
// jws.endWriteRaw();
// }
// };
fn idFromRequestId(request_id: []const u8) !u64 {
if (!std.mem.startsWith(u8, request_id, "REQ-")) {

View File

@@ -17,8 +17,8 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
const std = @import("std");
const Page = @import("../../browser/page.zig").Page;
const Notification = @import("../../notification.zig").Notification;
const Page = @import("../../browser/Page.zig");
const Notification = @import("../../Notification.zig");
const Allocator = std.mem.Allocator;
@@ -134,7 +134,7 @@ fn createIsolatedWorld(cmd: anytype) !void {
fn navigate(cmd: anytype) !void {
const params = (try cmd.params(struct {
url: []const u8,
url: [:0]const u8,
// referrer: ?[]const u8 = null,
// transitionType: ?[]const u8 = null, // TODO: enum
// frameId: ?[]const u8 = null,
@@ -253,7 +253,8 @@ pub fn pageNavigate(arena: Allocator, bc: anytype, event: *const Notification.Pa
bc.inspector.contextCreated(
page.js,
"",
try page.origin(arena),
"", // @ZIGDOM
// try page.origin(arena),
aux_data,
true,
);
@@ -360,7 +361,7 @@ pub fn pageNetworkAlmostIdle(bc: anytype, event: *const Notification.PageNetwork
return sendPageLifecycle(bc, "networkAlmostIdle", event.timestamp);
}
fn sendPageLifecycle(bc: anytype, name: []const u8, timestamp: u32) !void {
fn sendPageLifecycle(bc: anytype, name: []const u8, timestamp: u64) !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;
@@ -379,7 +380,7 @@ const LifecycleEvent = struct {
frameId: []const u8,
loaderId: ?[]const u8,
name: []const u8,
timestamp: u32,
timestamp: u64,
};
const testing = @import("../testing.zig");

View File

@@ -19,9 +19,9 @@
const std = @import("std");
const log = @import("../../log.zig");
const Cookie = @import("../../browser/storage/storage.zig").Cookie;
const CookieJar = @import("../../browser/storage/storage.zig").CookieJar;
pub const PreparedUri = @import("../../browser/storage/cookie.zig").PreparedUri;
const Cookie = @import("../../browser/webapi/storage/storage.zig").Cookie;
const CookieJar = @import("../../browser/webapi/storage/storage.zig").Jar;
pub const PreparedUri = @import("../../browser/webapi/storage/cookie.zig").PreparedUri;
pub fn processMessage(cmd: anytype) !void {
const action = std.meta.stringToEnum(enum {

View File

@@ -143,13 +143,14 @@ fn createTarget(cmd: anytype) !void {
bc.target_id = target_id;
var page = try bc.session.createPage();
const page = try bc.session.createPage();
{
const aux_data = try std.fmt.allocPrint(cmd.arena, "{{\"isDefault\":true,\"type\":\"default\",\"frameId\":\"{s}\"}}", .{target_id});
bc.inspector.contextCreated(
page.js,
"",
try page.origin(cmd.arena),
"", // @ZIGDOM
// try page.origin(arena),
aux_data,
true,
);

View File

@@ -24,7 +24,6 @@ const ArenaAllocator = std.heap.ArenaAllocator;
const Testing = @This();
const main = @import("cdp.zig");
const parser = @import("../browser/netsurf.zig");
const base = @import("../testing.zig");
pub const allocator = base.allocator;

View File

@@ -176,7 +176,7 @@ pub fn abort(self: *Client) void {
}
}
pub fn tick(self: *Client, timeout_ms: i32) !PerformStatus {
pub fn tick(self: *Client, timeout_ms: u32) !PerformStatus {
while (true) {
if (self.handles.hasAvailable() == false) {
break;
@@ -188,7 +188,7 @@ pub fn tick(self: *Client, timeout_ms: i32) !PerformStatus {
const handle = self.handles.getFreeHandle().?;
try self.makeRequest(handle, transfer);
}
return self.perform(timeout_ms);
return self.perform(@intCast(timeout_ms));
}
pub fn request(self: *Client, req: Request) !void {

View File

@@ -83,7 +83,7 @@ pub fn deinit(self: *Http) void {
self.arena.deinit();
}
pub fn poll(self: *Http, timeout_ms: i32) Client.PerformStatus {
pub fn poll(self: *Http, timeout_ms: u32) Client.PerformStatus {
return self.client.tick(timeout_ms) catch |err| {
log.err(.app, "http poll", .{ .err = err });
return .normal;

View File

@@ -1,5 +1,7 @@
const std = @import("std");
pub const App = @import("App.zig");
pub const Server = @import("Server.zig");
pub const log = @import("log.zig");
pub const dump = @import("browser/dump.zig");
pub const build_config = @import("build_config");

View File

@@ -99,27 +99,24 @@ fn run(allocator: Allocator, main_arena: Allocator) !void {
app.telemetry.record(.{ .run = {} });
switch (args.mode) {
.serve => {
return;
// @ZIGDOM-CDP
// .serve => |opts| {
// log.debug(.app, "startup", .{ .mode = "serve" });
// const address = std.net.Address.parseIp4(opts.host, opts.port) catch |err| {
// log.fatal(.app, "invalid server address", .{ .err = err, .host = opts.host, .port = opts.port });
// return args.printUsageAndExit(false);
// };
.serve => |opts| {
log.debug(.app, "startup", .{ .mode = "serve" });
const address = std.net.Address.parseIp4(opts.host, opts.port) catch |err| {
log.fatal(.app, "invalid server address", .{ .err = err, .host = opts.host, .port = opts.port });
return args.printUsageAndExit(false);
};
// // _server is global to handle graceful shutdown.
// _server = try lp.Server.init(app, address);
// const server = &_server.?;
// defer server.deinit();
// _server is global to handle graceful shutdown.
_server = try lp.Server.init(app, address);
const server = &_server.?;
defer server.deinit();
// // max timeout of 1 week.
// const timeout = if (opts.timeout > 604_800) 604_800_000 else @as(i32, opts.timeout) * 1000;
// server.run(address, timeout) catch |err| {
// log.fatal(.app, "server run error", .{ .err = err });
// return err;
// };
// max timeout of 1 week.
const timeout = if (opts.timeout > 604_800) 604_800_000 else @as(u32, opts.timeout) * 1000;
server.run(address, timeout) catch |err| {
log.fatal(.app, "server run error", .{ .err = err });
return err;
};
},
.fetch => |opts| {
const url = opts.url;

View File

@@ -26,7 +26,7 @@ const Allocator = std.mem.Allocator;
const ArenaAllocator = std.heap.ArenaAllocator;
const log = @import("log.zig");
const App = @import("app.zig").App;
const App = @import("App.zig");
const CDP = @import("cdp/cdp.zig").CDP;
const MAX_HTTP_REQUEST_SIZE = 4096;
@@ -69,7 +69,7 @@ pub fn deinit(self: *Server) void {
self.allocator.free(self.json_version_response);
}
pub fn run(self: *Server, address: net.Address, timeout_ms: i32) !void {
pub fn run(self: *Server, address: net.Address, timeout_ms: u32) !void {
const flags = posix.SOCK.STREAM | posix.SOCK.CLOEXEC;
const listener = try posix.socket(address.any.family, flags, posix.IPPROTO.TCP);
self.listener = listener;
@@ -112,7 +112,7 @@ pub fn run(self: *Server, address: net.Address, timeout_ms: i32) !void {
}
}
fn readLoop(self: *Server, socket: posix.socket_t, timeout_ms: i32) !void {
fn readLoop(self: *Server, socket: posix.socket_t, timeout_ms: u32) !void {
// This shouldn't be necessary, but the Client is HUGE (> 512KB) because
// it has a large read buffer. I don't know why, but v8 crashes if this
// is on the stack (and I assume it's related to its size).
@@ -143,7 +143,7 @@ fn readLoop(self: *Server, socket: posix.socket_t, timeout_ms: i32) !void {
}
var cdp = &client.mode.cdp;
var last_message = timestamp();
var last_message = timestamp(.monotonic);
var ms_remaining = timeout_ms;
while (true) {
switch (cdp.pageWait(ms_remaining)) {
@@ -151,7 +151,7 @@ fn readLoop(self: *Server, socket: posix.socket_t, timeout_ms: i32) !void {
if (try client.readSocket() == false) {
return;
}
last_message = timestamp();
last_message = timestamp(.monotonic);
ms_remaining = timeout_ms;
},
.no_page => {
@@ -162,16 +162,16 @@ fn readLoop(self: *Server, socket: posix.socket_t, timeout_ms: i32) !void {
if (try client.readSocket() == false) {
return;
}
last_message = timestamp();
last_message = timestamp(.monotonic);
ms_remaining = timeout_ms;
},
.done => {
const elapsed = timestamp() - last_message;
const elapsed = timestamp(.monotonic) - last_message;
if (elapsed > ms_remaining) {
log.info(.app, "CDP timeout", .{});
return;
}
ms_remaining -= @as(i32, @intCast(elapsed));
ms_remaining -= @intCast(elapsed);
},
}
}
@@ -928,9 +928,7 @@ fn buildJSONVersionResponse(
return try std.fmt.allocPrint(allocator, response_format, .{ body_len, address });
}
fn timestamp() u32 {
return @import("datetime.zig").timestamp();
}
pub const timestamp = @import("datetime.zig").timestamp;
// In-place string lowercase
fn toLower(str: []u8) []u8 {

View File

@@ -6,7 +6,7 @@ const Thread = std.Thread;
const Allocator = std.mem.Allocator;
const log = @import("../log.zig");
const App = @import("../app.zig").App;
const App = @import("../App.zig");
const Http = @import("../http/Http.zig");
const telemetry = @import("telemetry.zig");