From 03bb16fcec53ba884c04e725a48fe828b907308d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristo=CC=81fer=20R?= Date: Mon, 4 Nov 2024 16:54:38 -0500 Subject: [PATCH] Move hostname helpers to src/os/hostname.zig --- src/os/hostname.zig | 44 ++++++++++++++++++++++++++++++++ src/termio/stream_handler.zig | 47 +++-------------------------------- 2 files changed, 47 insertions(+), 44 deletions(-) create mode 100644 src/os/hostname.zig diff --git a/src/os/hostname.zig b/src/os/hostname.zig new file mode 100644 index 000000000..0bed2d547 --- /dev/null +++ b/src/os/hostname.zig @@ -0,0 +1,44 @@ +const std = @import("std"); +const posix = std.posix; + +pub fn bufPrintHostnameFromFileUri(buf: []u8, uri: std.Uri) ![]const u8 { + // Get the raw string of the URI. Its unclear to me if the various + // tags of this enum guarantee no percent-encoding so we just + // check all of it. This isn't a performance critical path. + const host_component = uri.host orelse return error.NoHostnameInUri; + const host = switch (host_component) { + .raw => |v| v, + .percent_encoded => |v| v, + }; + + // When the "Private Wi-Fi address" setting is toggled on macOS the hostname + // is set to a string of digits separated by a colon, e.g. '12:34:56:78:90:12'. + // The URI will be parsed as if the last set o digit is a port, so we need to + // make sure that part is included when it's set. + if (uri.port) |port| { + var fbs = std.io.fixedBufferStream(buf); + std.fmt.format(fbs.writer().any(), "{s}:{d}", .{ host, port }) catch |err| switch (err) { + error.NoSpaceLeft => return error.NoSpaceLeft, + else => unreachable, + }; + + return fbs.getWritten(); + } + + return host; +} + +pub fn isLocalHostname(hostname: []const u8) !bool { + // A 'localhost' hostname is always considered local. + if (std.mem.eql(u8, "localhost", hostname)) { + return true; + } + + // If hostname is not "localhost" it must match our hostname. + var buf: [posix.HOST_NAME_MAX]u8 = undefined; + const ourHostname = posix.gethostname(&buf) catch |err| { + return err; + }; + + return std.mem.eql(u8, hostname, ourHostname); +} diff --git a/src/termio/stream_handler.zig b/src/termio/stream_handler.zig index 8db67f66c..c97c533ea 100644 --- a/src/termio/stream_handler.zig +++ b/src/termio/stream_handler.zig @@ -5,6 +5,7 @@ const xev = @import("xev"); const apprt = @import("../apprt.zig"); const build_config = @import("../build_config.zig"); const configpkg = @import("../config.zig"); +const hostname = @import("../os/hostname.zig"); const renderer = @import("../renderer.zig"); const termio = @import("../termio.zig"); const terminal = @import("../terminal/main.zig"); @@ -1030,48 +1031,6 @@ pub const StreamHandler = struct { self.terminal.markSemanticPrompt(.command); } - pub fn bufPrintHostnameFromFileUri(buf: []u8, uri: std.Uri) ![]const u8 { - // Get the raw string of the URI. Its unclear to me if the various - // tags of this enum guarantee no percent-encoding so we just - // check all of it. This isn't a performance critical path. - const host_component = uri.host orelse return error.NoHostnameInUri; - const host = switch (host_component) { - .raw => |v| v, - .percent_encoded => |v| v, - }; - - // When the "Private Wi-Fi address" setting is toggled on macOS the hostname - // is set to a string of digits separated by a colon, e.g. '12:34:56:78:90:12'. - // The URI will be parsed as if the last set o digit is a port, so we need to - // make sure that part is included when it's set. - if (uri.port) |port| { - var fbs = std.io.fixedBufferStream(buf); - std.fmt.format(fbs.writer().any(), "{s}:{d}", .{ host, port }) catch |err| switch (err) { - error.NoSpaceLeft => return error.NoSpaceLeft, - else => unreachable, - }; - - return fbs.getWritten(); - } - - return host; - } - - pub fn isLocalHostname(hostname: []const u8) !bool { - // A 'localhost' hostname is always considered local. - if (std.mem.eql(u8, "localhost", hostname)) { - return true; - } - - // If hostname is not "localhost" it must match our hostname. - var buf: [posix.HOST_NAME_MAX]u8 = undefined; - const ourHostname = posix.gethostname(&buf) catch |err| { - return err; - }; - - return std.mem.eql(u8, hostname, ourHostname); - } - pub fn reportPwd(self: *StreamHandler, url: []const u8) !void { if (builtin.os.tag == .windows) { log.warn("reportPwd unimplemented on windows", .{}); @@ -1097,7 +1056,7 @@ pub const StreamHandler = struct { // Make sure there is space for a max length hostname + the max number of digits. var host_and_port_buf: [posix.HOST_NAME_MAX + PORT_NUMBER_MAX_DIGITS]u8 = undefined; - const hostname = bufPrintHostnameFromFileUri(&host_and_port_buf, uri) catch |err| switch (err) { + const hostname_from_uri = hostname.bufPrintHostnameFromFileUri(&host_and_port_buf, uri) catch |err| switch (err) { error.NoHostnameInUri => { log.warn("OSC 7 uri must contain a hostname: {}", .{err}); return; @@ -1111,7 +1070,7 @@ pub const StreamHandler = struct { // OSC 7 is a little sketchy because anyone can send any value from // any host (such an SSH session). The best practice terminals follow // is to valid the hostname to be local. - const host_valid = isLocalHostname(hostname) catch |err| switch (err) { + const host_valid = hostname.isLocalHostname(hostname_from_uri) catch |err| switch (err) { error.PermissionDenied, error.Unexpected => { log.warn("failed to get hostname for OSC 7 validation: {}", .{err}); return;