authorgravatar for hahv@msn.comHuang Zhichao <hahv@msn.com> 2026-05-25 12:57:12+08:00
committergravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2026-08-27 23:11:38+02:00
loge2c60cf76778cc049d41a9149df8a5fbb172d3c1
tree1c7989c88d1e011732b3387d292e19727b12a6b9
parente11cd2316bf752d42ab03807f40112e85cd46ab0

std.Io.net.HostName: correct `max_len`

`max_len` should be 254 since `HostName` stores the text representation of the domain. www .example .com www .example .com . // with the trailing dot (max 254) \x03www\x07example\x03com\x00 // in the dns packet (max 255)

1 files changed, 19 insertions(+), 8 deletions(-)

lib/std/Io/net/HostName.zig+19-8
...@@ -17,7 +17,17 @@ const Stream = Io.net.Stream;...@@ -17,7 +17,17 @@ const Stream = Io.net.Stream;
17/// Externally managed memory. Already checked to be valid.17/// Externally managed memory. Already checked to be valid.
18bytes: []const u8,18bytes: []const u8,
1919
20pub const max_len = 255;20/// The maximum number of bytes needed to store the text representation of
21/// a max length host name, where labels are separated by dots, including
22/// the trailing dot and the zero-length root label.
23///
24/// The max length of a host name is determined by its packet representation,
25/// where each label has a length prefix of 1 octet, the root label has a
26/// length of 0, and the maximum total number of octets is 255.
27///
28/// See [RFC 1035, Section 3.1](https://datatracker.ietf.org/doc/html/rfc1035#section-3.1)
29pub const max_len = 254;
30const max_len_without_root = max_len - 1;
2131
22pub const FromUriError = error{UriMissingHost} || ValidateError;32pub const FromUriError = error{UriMissingHost} || ValidateError;
2333
...@@ -40,12 +50,12 @@ pub const ValidateError = error{...@@ -40,12 +50,12 @@ pub const ValidateError = error{
40pub fn validate(bytes: []const u8) ValidateError!void {50pub fn validate(bytes: []const u8) ValidateError!void {
41 if (bytes.len == 0) return error.InvalidHostName;51 if (bytes.len == 0) return error.InvalidHostName;
4252
43 // The accepted maximum length of a hostname, including labels and dots.
44 if (bytes.len > max_len) return error.NameTooLong;
45
46 // Ignore trailing dot (FQDN).53 // Ignore trailing dot (FQDN).
47 const end = if (bytes[bytes.len - 1] == '.') bytes.len - 1 else bytes.len;54 const end = if (bytes[bytes.len - 1] == '.') bytes.len - 1 else bytes.len;
4855
56 // The accepted maximum length of a hostname, including labels and dots.
57 if (end > max_len_without_root) return error.NameTooLong;
58
49 // Hostnames are divided into dot-separated "labels", which:59 // Hostnames are divided into dot-separated "labels", which:
50 //60 //
51 // - Start with a letter or digit61 // - Start with a letter or digit
...@@ -92,9 +102,10 @@ test validate {...@@ -92,9 +102,10 @@ test validate {
92 const many_a: [63]u8 = @splat('a');102 const many_a: [63]u8 = @splat('a');
93 try validate(&many_a ++ ".com"); // Label exactly 63 chars (valid)103 try validate(&many_a ++ ".com"); // Label exactly 63 chars (valid)
94104
95 const many_a_dot_buf: [127][2]u8 = @splat(.{ 'a', '.' });105 const many_a_dot_buf: [126][2]u8 = @splat(.{ 'a', '.' });
96 const many_a_dot: []const u8 = @ptrCast(&many_a_dot_buf);106 const many_a_dot: []const u8 = @ptrCast(&many_a_dot_buf);
97 try validate(many_a_dot ++ "a"); // Total length 255 (valid)107 try validate(many_a_dot ++ "a"); // Total length 253 (without the trailing dot)
108 try validate(many_a_dot ++ "a."); // Total length 254 (with the trailing dot)
98109
99 // Invalid hostnames110 // Invalid hostnames
100 try std.testing.expectError(error.InvalidHostName, validate(""));111 try std.testing.expectError(error.InvalidHostName, validate(""));
...@@ -109,8 +120,8 @@ test validate {...@@ -109,8 +120,8 @@ test validate {
109 try std.testing.expectError(error.InvalidHostName, validate("."));120 try std.testing.expectError(error.InvalidHostName, validate("."));
110 try std.testing.expectError(error.InvalidHostName, validate(".."));121 try std.testing.expectError(error.InvalidHostName, validate(".."));
111 try std.testing.expectError(error.InvalidHostName, validate(&many_a ++ "a.com")); // Label length 64 (too long)122 try std.testing.expectError(error.InvalidHostName, validate(&many_a ++ "a.com")); // Label length 64 (too long)
112 try std.testing.expectError(error.NameTooLong, validate(many_a_dot ++ "a.")); // Total length 255 + trailing dot (too long)123 try std.testing.expectError(error.NameTooLong, validate(many_a_dot ++ "ab")); // Total length 254 (without the trailing dot)
113 try std.testing.expectError(error.NameTooLong, validate(many_a_dot ++ "ab")); // Total length 256 (too long)124 try std.testing.expectError(error.NameTooLong, validate(many_a_dot ++ "ab.")); // Total length 255 (with the trailing dot)
114}125}
115126
116pub fn init(bytes: []const u8) ValidateError!HostName {127pub fn init(bytes: []const u8) ValidateError!HostName {