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{...@@ -27,13 +27,9 @@ pub const ValidateError = error{
27/// Validates a hostname according to [RFC 1123](https://www.rfc-editor.org/rfc/rfc1123)27/// Validates a hostname according to [RFC 1123](https://www.rfc-editor.org/rfc/rfc1123)
28pub fn validate(bytes: []const u8) ValidateError!void {28pub fn validate(bytes: []const u8) ValidateError!void {
29 if (bytes.len == 0) return error.InvalidHostName;29 if (bytes.len == 0) return error.InvalidHostName;
30 if (bytes[0] == '.') return error.InvalidHostName;
3130
32 // Ignore trailing dot (FQDN). It doesn't count toward our length.31 // Ignore trailing dot (FQDN). It doesn't count toward our length.
33 const end = if (bytes[bytes.len - 1] == '.') end: {32 const end = if (bytes[bytes.len - 1] == '.') bytes.len - 1 else bytes.len;
34 if (bytes.len == 1) return error.InvalidHostName;
35 break :end bytes.len - 1;
36 } else bytes.len;
3733
38 // The accepted maximum length of a hostname, including labels and dots.34 // The accepted maximum length of a hostname, including labels and dots.
39 if (end > max_len) return error.NameTooLong;35 if (end > max_len) return error.NameTooLong;
...@@ -44,19 +40,16 @@ pub fn validate(bytes: []const u8) ValidateError!void {...@@ -44,19 +40,16 @@ pub fn validate(bytes: []const u8) ValidateError!void {
44 // - Can contain letters, digits, or hyphens40 // - Can contain letters, digits, or hyphens
45 // - Must end with a letter or digit41 // - Must end with a letter or digit
46 // - Have a minimum of 1 character and a maximum of 6342 // - Have a minimum of 1 character and a maximum of 63
47 var label_start: usize = 0;
48 var label_len: usize = 0;43 var label_len: usize = 0;
49 for (bytes[0..end], 0..) |c, i| {44 for (bytes[0..end], 0..) |c, i| {
50 switch (c) {45 switch (c) {
51 '.' => {46 '.' => {
52 if (label_len == 0 or label_len > 63) return error.InvalidHostName;47 if (label_len == 0 or label_len > 63) return error.InvalidHostName;
53 if (!std.ascii.isAlphanumeric(bytes[label_start])) return error.InvalidHostName;
54 if (!std.ascii.isAlphanumeric(bytes[i - 1])) return error.InvalidHostName;48 if (!std.ascii.isAlphanumeric(bytes[i - 1])) return error.InvalidHostName;
55
56 label_start = i + 1;
57 label_len = 0;49 label_len = 0;
58 },50 },
59 '-' => {51 '-' => {
52 if (label_len == 0) return error.InvalidHostName;
60 label_len += 1;53 label_len += 1;
61 },54 },
62 else => {55 else => {
...@@ -68,7 +61,6 @@ pub fn validate(bytes: []const u8) ValidateError!void {...@@ -68,7 +61,6 @@ pub fn validate(bytes: []const u8) ValidateError!void {
6861
69 // Validate the final label62 // Validate the final label
70 if (label_len == 0 or label_len > 63) return error.InvalidHostName;63 if (label_len == 0 or label_len > 63) return error.InvalidHostName;
71 if (!std.ascii.isAlphanumeric(bytes[label_start])) return error.InvalidHostName;
72 if (!std.ascii.isAlphanumeric(bytes[end - 1])) return error.InvalidHostName;64 if (!std.ascii.isAlphanumeric(bytes[end - 1])) return error.InvalidHostName;
73}65}
7466
...@@ -86,6 +78,7 @@ test validate {...@@ -86,6 +78,7 @@ test validate {
86 try validate("127.0.0.1"); // Also a valid hostname78 try validate("127.0.0.1"); // Also a valid hostname
87 try validate("a" ** 63 ++ ".com"); // Label exactly 63 chars (valid)79 try validate("a" ** 63 ++ ".com"); // Label exactly 63 chars (valid)
88 try validate("a." ** 127 ++ "a"); // Total length 255 (valid)80 try validate("a." ** 127 ++ "a"); // Total length 255 (valid)
81 try validate("a." ** 127 ++ "a."); // Total length 255 + trailing dot (valid)
8982
90 // Invalid hostnames83 // Invalid hostnames
91 try std.testing.expectError(error.InvalidHostName, validate(""));84 try std.testing.expectError(error.InvalidHostName, validate(""));
...@@ -94,12 +87,14 @@ test validate {...@@ -94,12 +87,14 @@ test validate {
94 try std.testing.expectError(error.InvalidHostName, validate("host..domain"));87 try std.testing.expectError(error.InvalidHostName, validate("host..domain"));
95 try std.testing.expectError(error.InvalidHostName, validate("-hostname"));88 try std.testing.expectError(error.InvalidHostName, validate("-hostname"));
96 try std.testing.expectError(error.InvalidHostName, validate("hostname-"));89 try std.testing.expectError(error.InvalidHostName, validate("hostname-"));
90 try std.testing.expectError(error.InvalidHostName, validate("hostname-.com"));
97 try std.testing.expectError(error.InvalidHostName, validate("a.-.b"));91 try std.testing.expectError(error.InvalidHostName, validate("a.-.b"));
98 try std.testing.expectError(error.InvalidHostName, validate("host_name.com"));92 try std.testing.expectError(error.InvalidHostName, validate("host_name.com"));
99 try std.testing.expectError(error.InvalidHostName, validate("."));93 try std.testing.expectError(error.InvalidHostName, validate("."));
100 try std.testing.expectError(error.InvalidHostName, validate(".."));94 try std.testing.expectError(error.InvalidHostName, validate(".."));
101 try std.testing.expectError(error.InvalidHostName, validate("a" ** 64 ++ ".com")); // Label length 64 (too long)95 try std.testing.expectError(error.InvalidHostName, validate("a" ** 64 ++ ".com")); // Label length 64 (too long)
102 try std.testing.expectError(error.NameTooLong, validate("a." ** 127 ++ "ab")); // Total length 256 (too long)96 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)
103}98}
10499
105pub fn init(bytes: []const u8) ValidateError!HostName {100pub fn init(bytes: []const u8) ValidateError!HostName {