Add --advertise_host option to serve command

Allows overwriting the --host for the json/version payload. When --host is set
to 0.0.0.0, we want to provide a mechanism to specify the specific address to
connect to in /json/version (or anywhere else that we "advertise" the address).

Inspired by https://github.com/lightpanda-io/browser/pull/1923 but rather than
defaulting to 127.0.0.1 (which seems just as unsafe), adds the explicit config
option.
This commit is contained in:
Karl Seguin
2026-03-22 12:40:17 +08:00
parent c1fc2b1301
commit 4e2e895cd9
2 changed files with 41 additions and 6 deletions

View File

@@ -163,6 +163,20 @@ pub fn cdpTimeout(self: *const Config) usize {
};
}
pub fn port(self: *const Config) u16 {
return switch (self.mode) {
.serve => |opts| opts.port,
else => unreachable,
};
}
pub fn advertiseHost(self: *const Config) []const u8 {
return switch (self.mode) {
.serve => |opts| opts.advertise_host orelse opts.host,
else => unreachable,
};
}
pub fn webBotAuth(self: *const Config) ?WebBotAuthConfig {
return switch (self.mode) {
inline .serve, .fetch, .mcp => |opts| WebBotAuthConfig{
@@ -199,6 +213,7 @@ pub const Mode = union(RunMode) {
pub const Serve = struct {
host: []const u8 = "127.0.0.1",
port: u16 = 9222,
advertise_host: ?[]const u8 = null,
timeout: u31 = 10,
cdp_max_connections: u16 = 16,
cdp_max_pending_connections: u16 = 128,
@@ -416,6 +431,11 @@ pub fn printUsageAndExit(self: *const Config, success: bool) void {
\\--port Port of the CDP server
\\ Defaults to 9222
\\
\\--advertise_host
\\ The host to advertise, e.g. in the /json/version response.
\\ Useful, for example, when --host is 0.0.0.0.
\\ Defaults to --host value
\\
\\--timeout Inactivity timeout in seconds before disconnecting clients
\\ Defaults to 10 (seconds). Limited to 604800 (1 week).
\\
@@ -557,6 +577,15 @@ fn parseServeArgs(
continue;
}
if (std.mem.eql(u8, "--advertise_host", opt)) {
const str = args.next() orelse {
log.fatal(.app, "missing argument value", .{ .arg = "--advertise_host" });
return error.InvalidArgument;
};
serve.advertise_host = try allocator.dupe(u8, str);
continue;
}
if (std.mem.eql(u8, "--timeout", opt)) {
const str = args.next() orelse {
log.fatal(.app, "missing argument value", .{ .arg = "--timeout" });

View File

@@ -45,7 +45,7 @@ clients_pool: std.heap.MemoryPool(Client),
pub fn init(app: *App, address: net.Address) !*Server {
const allocator = app.allocator;
const json_version_response = try buildJSONVersionResponse(allocator, address);
const json_version_response = try buildJSONVersionResponse(app);
errdefer allocator.free(json_version_response);
const self = try allocator.create(Server);
@@ -484,11 +484,17 @@ pub const Client = struct {
// --------
fn buildJSONVersionResponse(
allocator: Allocator,
address: net.Address,
app: *const App,
) ![]const u8 {
const body_format = "{{\"webSocketDebuggerUrl\": \"ws://{f}/\"}}";
const body_len = std.fmt.count(body_format, .{address});
const port = app.config.port();
const host = app.config.advertiseHost();
if (std.mem.eql(u8, host, "0.0.0.0")) {
log.info(.cdp, "unreachable advertised host", .{
.message = "when --host is set to 0.0.0.0 consider setting --advertise_host to a reachable address",
});
}
const body_format = "{{\"webSocketDebuggerUrl\": \"ws://{s}:{d}/\"}}";
const body_len = std.fmt.count(body_format, .{host, port});
// We send a Connection: Close (and actually close the connection)
// because chromedp (Go driver) sends a request to /json/version and then
@@ -502,7 +508,7 @@ fn buildJSONVersionResponse(
"Connection: Close\r\n" ++
"Content-Type: application/json; charset=UTF-8\r\n\r\n" ++
body_format;
return try std.fmt.allocPrint(allocator, response_format, .{ body_len, address });
return try std.fmt.allocPrint(app.allocator, response_format, .{ body_len, host, port });
}
pub const timestamp = @import("datetime.zig").timestamp;