From 5679a7ed1b1fdf886885c4547af03a70c0bbea4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristo=CC=81fer=20R?= Date: Mon, 7 Apr 2025 23:43:11 -0400 Subject: [PATCH] pwd: fix hostname resolution on macos When macOS's "Private WiFi address" feature is enabled it'll change the hostname to a mac address. Mac addresses look like URIs with a hostname and port component, e.g. 12:34:56:78:90:12 where `:12` looks like port 12. However, mac addresses can also contain letters a through f, so a valid mac address like ab:cd:ef:ab:cd:ef is valid, but will not be parsed as a URI, because `:ef` is not a valid port. This commit attempts to fix that by checking if the hostname is a valid mac address when `std.Uri.parse()` fails and constructing a new std.Uri struct using that information. It's not perfect, but is equally compliant with the URI spec as std.Uri currently is. --- src/termio/stream_handler.zig | 66 +++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 3 deletions(-) diff --git a/src/termio/stream_handler.zig b/src/termio/stream_handler.zig index 43d2888d23..6da66c8d54 100644 --- a/src/termio/stream_handler.zig +++ b/src/termio/stream_handler.zig @@ -1057,6 +1057,13 @@ pub const StreamHandler = struct { self.terminal.markSemanticPrompt(.command); } + fn isUriPathSeparator(c: u8) bool { + return switch (c) { + '?', '#' => true, + else => false, + }; + } + pub fn reportPwd(self: *StreamHandler, url: []const u8) !void { // Special handling for the empty URL. We treat the empty URL // as resetting the pwd as if we never saw a pwd. I can't find any @@ -1085,9 +1092,62 @@ pub const StreamHandler = struct { return; } - const uri = std.Uri.parse(url) catch |e| { - log.warn("invalid url in OSC 7: {}", .{e}); - return; + const uri: std.Uri = uri: { + const uri = std.Uri.parse(url) catch |e| { + // It's possible this is a mac address on macOS where the last 2 characters in the + // address are non-digits, e.g. 'ff', and thus an invalid port. + // + // Example: file://12:34:56:78:90:12/path/to/file + + // Insufficient length to have a mac address in the hostname. + if (url.len < 24) { + log.warn("invalid url in OSC 7: {}", .{e}); + return; + } + + // The first '/' after the scheme marks the end of the hostname. If the hostname is + // not 17 characters, it's not a mac address. + if (std.mem.indexOfScalarPos(u8, url, 7, '/') != 24) { + log.warn("invalid url in OSC 7: {}", .{e}); + return; + } + + // At this point we have a potential mac address as the hostname. + const mac_address = url[7..24]; + + for (0..mac_address.len) |i| { + const c = mac_address[i]; + + if (i + 1 % 3 == 0) { + if (c != ':') { + log.warn("invalid url in OSC 7: {}", .{e}); + return; + } + } else { + if (!std.mem.containsAtLeastScalar(u8, "0123456789abcdef", 1, mac_address[i])) { + log.warn("invalid url in OSC 7: {}", .{e}); + return; + } + } + } + + // At this point we have what looks like a valid mac address. + + var uri_path_end_idx: usize = 24; + while (uri_path_end_idx < url.len and !isUriPathSeparator(url[uri_path_end_idx])) { + uri_path_end_idx += 1; + } + + // Same compliance factor as std.Uri.parse(), i.e. not at all compliant with the URI + // spec. + break :uri .{ + .scheme = "file://", + .host = .{ .percent_encoded = mac_address }, + .path = .{ .percent_encoded = url[24..uri_path_end_idx] }, + }; + }; + + break :uri uri; }; if (!std.mem.eql(u8, "file", uri.scheme) and