authorgravatar for guillaume.alabre@gmail.comGuillaume <guillaume.alabre@gmail.com> 2026-03-15 09:11:11+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-03-15 09:11:11+01:00
log065c6e7946e712dc8563c975a4ca951927145da7
treef6f9713b1f272831339b6585c96be08e909e7704
parentaaba36ff763a7f016bba1afc4eff758302538362

std.Io.net.HostName: simplify validate logic (#30764)

Follow-up of efe649b13e582be855376944bac1346426e238d6 Reviewed-on: https://codeberg.org/ziglang/zig/pulls/30764 Reviewed-by: Andrew Kelley <andrew@ziglang.org> Co-authored-by: Guillaume <guillaume.alabre@gmail.com> Co-committed-by: Guillaume <guillaume.alabre@gmail.com>

1 files changed, 5 insertions(+), 10 deletions(-)

lib/std/Io/net/HostName.zig+5-10
......@@ -27,13 +27,9 @@ pub const ValidateError = error{
2727/// Validates a hostname according to [RFC 1123](https://www.rfc-editor.org/rfc/rfc1123)
2828pub fn validate(bytes: []const u8) ValidateError!void {
2929 if (bytes.len == 0) return error.InvalidHostName;
30 if (bytes[0] == '.') return error.InvalidHostName;
3130
3231 // Ignore trailing dot (FQDN). It doesn't count toward our length.
33 const end = if (bytes[bytes.len - 1] == '.') end: {
34 if (bytes.len == 1) return error.InvalidHostName;
35 break :end bytes.len - 1;
36 } else bytes.len;
32 const end = if (bytes[bytes.len - 1] == '.') bytes.len - 1 else bytes.len;
3733
3834 // The accepted maximum length of a hostname, including labels and dots.
3935 if (end > max_len) return error.NameTooLong;
......@@ -44,19 +40,16 @@ pub fn validate(bytes: []const u8) ValidateError!void {
4440 // - Can contain letters, digits, or hyphens
4541 // - Must end with a letter or digit
4642 // - Have a minimum of 1 character and a maximum of 63
47 var label_start: usize = 0;
4843 var label_len: usize = 0;
4944 for (bytes[0..end], 0..) |c, i| {
5045 switch (c) {
5146 '.' => {
5247 if (label_len == 0 or label_len > 63) return error.InvalidHostName;
53 if (!std.ascii.isAlphanumeric(bytes[label_start])) return error.InvalidHostName;
5448 if (!std.ascii.isAlphanumeric(bytes[i - 1])) return error.InvalidHostName;
55
56 label_start = i + 1;
5749 label_len = 0;
5850 },
5951 '-' => {
52 if (label_len == 0) return error.InvalidHostName;
6053 label_len += 1;
6154 },
6255 else => {
......@@ -68,7 +61,6 @@ pub fn validate(bytes: []const u8) ValidateError!void {
6861
6962 // Validate the final label
7063 if (label_len == 0 or label_len > 63) return error.InvalidHostName;
71 if (!std.ascii.isAlphanumeric(bytes[label_start])) return error.InvalidHostName;
7264 if (!std.ascii.isAlphanumeric(bytes[end - 1])) return error.InvalidHostName;
7365}
7466
......@@ -86,6 +78,7 @@ test validate {
8678 try validate("127.0.0.1"); // Also a valid hostname
8779 try validate("a" ** 63 ++ ".com"); // Label exactly 63 chars (valid)
8880 try validate("a." ** 127 ++ "a"); // Total length 255 (valid)
81 try validate("a." ** 127 ++ "a."); // Total length 255 + trailing dot (valid)
8982
9083 // Invalid hostnames
9184 try std.testing.expectError(error.InvalidHostName, validate(""));
......@@ -94,12 +87,14 @@ test validate {
9487 try std.testing.expectError(error.InvalidHostName, validate("host..domain"));
9588 try std.testing.expectError(error.InvalidHostName, validate("-hostname"));
9689 try std.testing.expectError(error.InvalidHostName, validate("hostname-"));
90 try std.testing.expectError(error.InvalidHostName, validate("hostname-.com"));
9791 try std.testing.expectError(error.InvalidHostName, validate("a.-.b"));
9892 try std.testing.expectError(error.InvalidHostName, validate("host_name.com"));
9993 try std.testing.expectError(error.InvalidHostName, validate("."));
10094 try std.testing.expectError(error.InvalidHostName, validate(".."));
10195 try std.testing.expectError(error.InvalidHostName, validate("a" ** 64 ++ ".com")); // Label length 64 (too long)
10296 try std.testing.expectError(error.NameTooLong, validate("a." ** 127 ++ "ab")); // Total length 256 (too long)
97 try std.testing.expectError(error.NameTooLong, validate("a." ** 127 ++ "ab.")); // Total length 256 + trailing dot (too long)
10398}
10499
105100pub fn init(bytes: []const u8) ValidateError!HostName {