mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-09-14 23:15:14 -04:00
1. Abstract "Driver". Non-CDP things that referenced *CDP now reference a Driver 2. Move the NodeRegistry out of CDP. This created an artificial link between agent / mcp and CDP 3. Add BiDi driver with enough to navigate to a page
181 lines
6.4 KiB
Zig
181 lines
6.4 KiB
Zig
// Copyright (C) 2023-2026 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 lp = @import("lightpanda");
|
|
const builtin = @import("builtin");
|
|
|
|
const abort = std.process.abort;
|
|
|
|
// tracks how deep within a panic we're panicling
|
|
var panic_level: usize = 0;
|
|
|
|
// Locked to avoid interleaving panic messages from multiple threads.
|
|
var panic_mutex: std.Io.Mutex = .init;
|
|
|
|
// overwrite's Zig default panic handler
|
|
pub fn panic(msg: []const u8, _: ?*std.builtin.StackTrace, begin_addr: ?usize) noreturn {
|
|
@branchHint(.cold);
|
|
crash(msg, .{ .source = "global" }, begin_addr orelse @returnAddress());
|
|
}
|
|
|
|
pub noinline fn crash(
|
|
reason: []const u8,
|
|
args: anytype,
|
|
begin_addr: usize,
|
|
) noreturn {
|
|
@branchHint(.cold);
|
|
|
|
nosuspend switch (panic_level) {
|
|
0 => {
|
|
panic_level = panic_level + 1;
|
|
|
|
{
|
|
panic_mutex.lockUncancelable(lp.io);
|
|
defer panic_mutex.unlock(lp.io);
|
|
|
|
var writer_w = std.Io.File.stderr().writerStreaming(lp.io, &.{});
|
|
const writer = &writer_w.interface;
|
|
|
|
writer.writeAll(
|
|
\\
|
|
\\Lightpanda has crashed. Please report the issue:
|
|
\\https://github.com/lightpanda-io/browser/issues
|
|
\\or let us know on discord: https://discord.gg/g24PtgD6
|
|
\\
|
|
) catch abort();
|
|
|
|
writer.print("\nreason: {s}\n", .{reason}) catch abort();
|
|
writer.print("OS: {s}\n", .{@tagName(builtin.os.tag)}) catch abort();
|
|
writer.print("mode: {s}\n", .{@tagName(builtin.mode)}) catch abort();
|
|
writer.print("version: {s}\n", .{lp.build_config.version}) catch abort();
|
|
inline for (@typeInfo(@TypeOf(args)).@"struct".fields) |f| {
|
|
writer.writeAll(f.name ++ ": ") catch break;
|
|
lp.log.writeValue(.pretty, @field(args, f.name), writer) catch abort();
|
|
writer.writeByte('\n') catch abort();
|
|
}
|
|
|
|
std.debug.writeCurrentStackTrace(.{ .first_address = begin_addr }, .{ .writer = writer, .mode = .no_color }) catch abort();
|
|
}
|
|
|
|
report(reason, begin_addr, args) catch {};
|
|
},
|
|
1 => {
|
|
panic_level = 2;
|
|
var stderr_w = std.Io.File.stderr().writerStreaming(lp.io, &.{});
|
|
const stderr = &stderr_w.interface;
|
|
stderr.writeAll("panicked during a panic. Aborting.\n") catch abort();
|
|
},
|
|
else => {},
|
|
};
|
|
|
|
abort();
|
|
}
|
|
|
|
fn report(reason: []const u8, begin_addr: usize, args: anytype) !void {
|
|
if (comptime lp.IS_DEBUG) {
|
|
return;
|
|
}
|
|
|
|
if (@import("telemetry/telemetry.zig").isDisabled()) {
|
|
return;
|
|
}
|
|
|
|
var curl_path: [2048]u8 = undefined;
|
|
const curl_path_len = curlPath(&curl_path) orelse return;
|
|
|
|
var url_buffer: [4096]u8 = undefined;
|
|
const url = blk: {
|
|
var writer: std.Io.Writer = .fixed(&url_buffer);
|
|
try writer.print("https://crash.lightpanda.io/c?v={s}&r=", .{lp.build_config.version_encoded});
|
|
for (reason) |b| {
|
|
switch (b) {
|
|
'A'...'Z', 'a'...'z', '0'...'9', '-', '.', '_' => try writer.writeByte(b),
|
|
' ' => try writer.writeByte('+'),
|
|
else => try writer.writeByte('!'), // some weird character, that we shouldn't have, but that'll we'll replace with a weird (bur url-safe) character
|
|
}
|
|
}
|
|
|
|
try writer.writeByte(0);
|
|
break :blk writer.buffered();
|
|
};
|
|
|
|
var body_buffer: [8192]u8 = undefined;
|
|
const body = blk: {
|
|
var writer: std.Io.Writer = .fixed(body_buffer[0..8191]); // reserve 1 space
|
|
inline for (@typeInfo(@TypeOf(args)).@"struct".fields) |f| {
|
|
// remove url value from the crash report.
|
|
if (comptime std.mem.eql(u8, f.name, "url")) {
|
|
writer.writeAll("url: REDACTED\n") catch break;
|
|
continue;
|
|
}
|
|
writer.writeAll(f.name ++ ": ") catch break;
|
|
lp.log.writeValue(.pretty, @field(args, f.name), &writer) catch {};
|
|
writer.writeByte('\n') catch {};
|
|
}
|
|
|
|
std.debug.writeCurrentStackTrace(.{ .first_address = begin_addr }, .{ .writer = &writer, .mode = .no_color }) catch {};
|
|
const written = writer.buffered();
|
|
if (written.len == 0) {
|
|
break :blk "???";
|
|
}
|
|
// Overwrite the last character with our null terminator
|
|
// body_buffer always has to be > written
|
|
body_buffer[written.len] = 0;
|
|
break :blk body_buffer[0 .. written.len + 1];
|
|
};
|
|
|
|
var argv = [_:null]?[*:0]const u8{
|
|
curl_path[0..curl_path_len :0],
|
|
"-fsSL",
|
|
"-H",
|
|
"Content-Type: application/octet-stream",
|
|
"--data-binary",
|
|
body[0 .. body.len - 1 :0],
|
|
url[0 .. url.len - 1 :0],
|
|
};
|
|
|
|
const result = std.c.fork();
|
|
switch (result) {
|
|
0 => {
|
|
_ = std.c.close(0);
|
|
_ = std.c.close(1);
|
|
_ = std.c.close(2);
|
|
_ = std.c.execve(argv[0].?, &argv, std.c.environ);
|
|
std.c.exit(0);
|
|
},
|
|
else => return,
|
|
}
|
|
}
|
|
|
|
fn curlPath(buf: []u8) ?usize {
|
|
const path_z = std.c.getenv("PATH") orelse return null;
|
|
var it = std.mem.tokenizeScalar(u8, std.mem.span(path_z), std.fs.path.delimiter);
|
|
|
|
var fba = std.heap.FixedBufferAllocator.init(buf);
|
|
const allocator = fba.allocator();
|
|
|
|
const cwd = std.Io.Dir.cwd();
|
|
while (it.next()) |p| {
|
|
defer fba.reset();
|
|
const full_path = std.fs.path.joinZ(allocator, &.{ p, "curl" }) catch continue;
|
|
cwd.access(lp.io, full_path, .{}) catch continue;
|
|
return full_path.len;
|
|
}
|
|
return null;
|
|
}
|