mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-12-15 15:58:57 +00:00
re-enable minimum viable CDP server
This commit is contained in:
@@ -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"));
|
||||
|
||||
@@ -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"),
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
|
||||
23
src/browser/webapi/MutationObserver.zig
Normal file
23
src/browser/webapi/MutationObserver.zig
Normal 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, .{});
|
||||
};
|
||||
@@ -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}),
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
1137
src/cdp/Node.zig
1137
src/cdp/Node.zig
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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-")) {
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
|
||||
35
src/main.zig
35
src/main.zig
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user