commit 065c6e7946e712dc8563c975a4ca951927145da7 (tree)
parent aaba36ff763a7f016bba1afc4eff758302538362
Author: Guillaume <guillaume.alabre@gmail.com>
Date: Sun, 15 Mar 2026 09:11:11 +0100
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>
Diffstat:
1 file changed, 5 insertions(+), 10 deletions(-)
diff --git a/lib/std/Io/net/HostName.zig b/lib/std/Io/net/HostName.zig
@@ -27,13 +27,9 @@ pub const ValidateError = error{
/// Validates a hostname according to [RFC 1123](https://www.rfc-editor.org/rfc/rfc1123)
pub fn validate(bytes: []const u8) ValidateError!void {
if (bytes.len == 0) return error.InvalidHostName;
- if (bytes[0] == '.') return error.InvalidHostName;
// Ignore trailing dot (FQDN). It doesn't count toward our length.
- const end = if (bytes[bytes.len - 1] == '.') end: {
- if (bytes.len == 1) return error.InvalidHostName;
- break :end bytes.len - 1;
- } else bytes.len;
+ const end = if (bytes[bytes.len - 1] == '.') bytes.len - 1 else bytes.len;
// The accepted maximum length of a hostname, including labels and dots.
if (end > max_len) return error.NameTooLong;
@@ -44,19 +40,16 @@ pub fn validate(bytes: []const u8) ValidateError!void {
// - Can contain letters, digits, or hyphens
// - Must end with a letter or digit
// - Have a minimum of 1 character and a maximum of 63
- var label_start: usize = 0;
var label_len: usize = 0;
for (bytes[0..end], 0..) |c, i| {
switch (c) {
'.' => {
if (label_len == 0 or label_len > 63) return error.InvalidHostName;
- if (!std.ascii.isAlphanumeric(bytes[label_start])) return error.InvalidHostName;
if (!std.ascii.isAlphanumeric(bytes[i - 1])) return error.InvalidHostName;
-
- label_start = i + 1;
label_len = 0;
},
'-' => {
+ if (label_len == 0) return error.InvalidHostName;
label_len += 1;
},
else => {
@@ -68,7 +61,6 @@ pub fn validate(bytes: []const u8) ValidateError!void {
// Validate the final label
if (label_len == 0 or label_len > 63) return error.InvalidHostName;
- if (!std.ascii.isAlphanumeric(bytes[label_start])) return error.InvalidHostName;
if (!std.ascii.isAlphanumeric(bytes[end - 1])) return error.InvalidHostName;
}
@@ -86,6 +78,7 @@ test validate {
try validate("127.0.0.1"); // Also a valid hostname
try validate("a" ** 63 ++ ".com"); // Label exactly 63 chars (valid)
try validate("a." ** 127 ++ "a"); // Total length 255 (valid)
+ try validate("a." ** 127 ++ "a."); // Total length 255 + trailing dot (valid)
// Invalid hostnames
try std.testing.expectError(error.InvalidHostName, validate(""));
@@ -94,12 +87,14 @@ test validate {
try std.testing.expectError(error.InvalidHostName, validate("host..domain"));
try std.testing.expectError(error.InvalidHostName, validate("-hostname"));
try std.testing.expectError(error.InvalidHostName, validate("hostname-"));
+ try std.testing.expectError(error.InvalidHostName, validate("hostname-.com"));
try std.testing.expectError(error.InvalidHostName, validate("a.-.b"));
try std.testing.expectError(error.InvalidHostName, validate("host_name.com"));
try std.testing.expectError(error.InvalidHostName, validate("."));
try std.testing.expectError(error.InvalidHostName, validate(".."));
try std.testing.expectError(error.InvalidHostName, validate("a" ** 64 ++ ".com")); // Label length 64 (too long)
try std.testing.expectError(error.NameTooLong, validate("a." ** 127 ++ "ab")); // Total length 256 (too long)
+ try std.testing.expectError(error.NameTooLong, validate("a." ** 127 ++ "ab.")); // Total length 256 + trailing dot (too long)
}
pub fn init(bytes: []const u8) ValidateError!HostName {