authorgravatar for evgenii@eorlov.orgEvgenii Orlov <evgenii@eorlov.org> 2026-03-23 11:00:18+01:00
committergravatar for evgenii.orlov@semrush.comEvgenii Orlov <evgenii.orlov@semrush.com> 2026-03-23 11:02:47+01:00
log0ee6a79da5a134a57d178edbe1acdd289470c909
treea0b7293aa8a87573db514608cfd19ef879bd8a79
parentc7d69f01608d2df5a4a65ee885100eae4369ce80

std.Io.net.HostName.netLookup: make `canonical_name_buffer` optional


3 files changed, 78 insertions(+), 47 deletions(-)

lib/std/Io/Threaded.zig+77-44
...@@ -13481,10 +13481,14 @@ fn netLookupFallible(...@@ -13481,10 +13481,14 @@ fn netLookupFallible(
13481 if (is_windows) {13481 if (is_windows) {
13482 if (options.family == null) {13482 if (options.family == null) {
13483 if (IpAddress.parseIp4(name, options.port)) |addr| {13483 if (IpAddress.parseIp4(name, options.port)) |addr| {
13484 try resolved.putAll(t_io, &.{13484 if (copyCanon(options.canonical_name_buffer, name)) |canon| {
13485 .{ .address = addr },13485 try resolved.putAll(t_io, &.{
13486 .{ .canonical_name = copyCanon(options.canonical_name_buffer, name) },13486 .{ .address = addr },
13487 });13487 .{ .canonical_name = canon },
13488 });
13489 } else {
13490 try resolved.putOne(t_io, .{ .address = addr });
13491 }
13488 return;13492 return;
13489 } else |_| {}13493 } else |_| {}
13490 }13494 }
...@@ -13608,20 +13612,28 @@ fn netLookupFallible(...@@ -13608,20 +13612,28 @@ fn netLookupFallible(
13608 if (native_os == .linux) {13612 if (native_os == .linux) {
13609 if (options.family != .ip4) {13613 if (options.family != .ip4) {
13610 if (IpAddress.parseIp6(name, options.port)) |addr| {13614 if (IpAddress.parseIp6(name, options.port)) |addr| {
13611 try resolved.putAll(t_io, &.{13615 if (copyCanon(options.canonical_name_buffer, name)) |canon| {
13612 .{ .address = addr },13616 try resolved.putAll(t_io, &.{
13613 .{ .canonical_name = copyCanon(options.canonical_name_buffer, name) },13617 .{ .address = addr },
13614 });13618 .{ .canonical_name = canon },
13619 });
13620 } else {
13621 try resolved.putOne(t_io, .{ .address = addr });
13622 }
13615 return;13623 return;
13616 } else |_| {}13624 } else |_| {}
13617 }13625 }
1361813626
13619 if (options.family != .ip6) {13627 if (options.family != .ip6) {
13620 if (IpAddress.parseIp4(name, options.port)) |addr| {13628 if (IpAddress.parseIp4(name, options.port)) |addr| {
13621 try resolved.putAll(t_io, &.{13629 if (copyCanon(options.canonical_name_buffer, name)) |canon| {
13622 .{ .address = addr },13630 try resolved.putAll(t_io, &.{
13623 .{ .canonical_name = copyCanon(options.canonical_name_buffer, name) },13631 .{ .address = addr },
13624 });13632 .{ .canonical_name = canon },
13633 });
13634 } else {
13635 try resolved.putOne(t_io, .{ .address = addr });
13636 }
13625 return;13637 return;
13626 } else |_| {}13638 } else |_| {}
13627 }13639 }
...@@ -13652,11 +13664,13 @@ fn netLookupFallible(...@@ -13652,11 +13664,13 @@ fn netLookupFallible(
13652 results_buffer[results_index] = .{ .address = .{ .ip4 = .loopback(options.port) } };13664 results_buffer[results_index] = .{ .address = .{ .ip4 = .loopback(options.port) } };
13653 results_index += 1;13665 results_index += 1;
13654 }13666 }
13655 const canon_name = "localhost";13667 if (options.canonical_name_buffer) |buf| {
13656 const canon_name_dest = options.canonical_name_buffer[0..canon_name.len];13668 const canon_name = "localhost";
13657 canon_name_dest.* = canon_name.*;13669 const canon_name_dest = buf[0..canon_name.len];
13658 results_buffer[results_index] = .{ .canonical_name = .{ .bytes = canon_name_dest } };13670 canon_name_dest.* = canon_name.*;
13659 results_index += 1;13671 results_buffer[results_index] = .{ .canonical_name = .{ .bytes = canon_name_dest } };
13672 results_index += 1;
13673 }
13660 try resolved.putAll(t_io, results_buffer[0..results_index]);13674 try resolved.putAll(t_io, results_buffer[0..results_index]);
13661 return;13675 return;
13662 }13676 }
...@@ -13688,7 +13702,7 @@ fn netLookupFallible(...@@ -13688,7 +13702,7 @@ fn netLookupFallible(
13688 const port_c = std.fmt.bufPrintZ(&port_buffer, "{d}", .{options.port}) catch unreachable;13702 const port_c = std.fmt.bufPrintZ(&port_buffer, "{d}", .{options.port}) catch unreachable;
1368913703
13690 const hints: posix.addrinfo = .{13704 const hints: posix.addrinfo = .{
13691 .flags = .{ .CANONNAME = options.request_canonical_name, .NUMERICSERV = true },13705 .flags = .{ .CANONNAME = options.canonical_name_buffer != null, .NUMERICSERV = true },
13692 .family = posix.AF.UNSPEC,13706 .family = posix.AF.UNSPEC,
13693 .socktype = posix.SOCK.STREAM,13707 .socktype = posix.SOCK.STREAM,
13694 .protocol = posix.IPPROTO.TCP,13708 .protocol = posix.IPPROTO.TCP,
...@@ -13745,9 +13759,9 @@ fn netLookupFallible(...@@ -13745,9 +13759,9 @@ fn netLookupFallible(
13745 }13759 }
13746 }13760 }
13747 if (canon_name) |n| {13761 if (canon_name) |n| {
13748 try resolved.putOne(t_io, .{13762 if (copyCanon(options.canonical_name_buffer, std.mem.sliceTo(n, 0))) |canon| {
13749 .canonical_name = copyCanon(options.canonical_name_buffer, std.mem.sliceTo(n, 0)),13763 try resolved.putOne(t_io, .{ .canonical_name = canon });
13750 });13764 }
13751 }13765 }
13752 return;13766 return;
13753 }13767 }
...@@ -14268,12 +14282,14 @@ fn lookupDnsSearch(...@@ -14268,12 +14282,14 @@ fn lookupDnsSearch(
14268 // both provides the desired default canonical name (if the requested14282 // both provides the desired default canonical name (if the requested
14269 // name is not a CNAME record) and serves as a buffer for passing the14283 // name is not a CNAME record) and serves as a buffer for passing the
14270 // full requested name to `lookupDns`.14284 // full requested name to `lookupDns`.
14271 @memcpy(options.canonical_name_buffer[0..canon_name.len], canon_name);14285 var local_buf: [HostName.max_len]u8 = undefined;
14272 options.canonical_name_buffer[canon_name.len] = '.';14286 const canon_buf = options.canonical_name_buffer orelse &local_buf;
14287 @memcpy(canon_buf[0..canon_name.len], canon_name);
14288 canon_buf[canon_name.len] = '.';
14273 var it = std.mem.tokenizeAny(u8, search, " \t");14289 var it = std.mem.tokenizeAny(u8, search, " \t");
14274 while (it.next()) |token| {14290 while (it.next()) |token| {
14275 @memcpy(options.canonical_name_buffer[canon_name.len + 1 ..][0..token.len], token);14291 @memcpy(canon_buf[canon_name.len + 1 ..][0..token.len], token);
14276 const lookup_canon_name = options.canonical_name_buffer[0 .. canon_name.len + 1 + token.len];14292 const lookup_canon_name = canon_buf[0 .. canon_name.len + 1 + token.len];
14277 if (t.lookupDns(lookup_canon_name, &rc, resolved, options)) |result| {14293 if (t.lookupDns(lookup_canon_name, &rc, resolved, options)) |result| {
14278 return result;14294 return result;
14279 } else |err| switch (err) {14295 } else |err| switch (err) {
...@@ -14282,7 +14298,7 @@ fn lookupDnsSearch(...@@ -14282,7 +14298,7 @@ fn lookupDnsSearch(
14282 }14298 }
14283 }14299 }
1428414300
14285 const lookup_canon_name = options.canonical_name_buffer[0..canon_name.len];14301 const lookup_canon_name = canon_buf[0..canon_name.len];
14286 return t.lookupDns(lookup_canon_name, &rc, resolved, options);14302 return t.lookupDns(lookup_canon_name, &rc, resolved, options);
14287}14303}
1428814304
...@@ -14464,14 +14480,23 @@ fn lookupDns(...@@ -14464,14 +14480,23 @@ fn lookupDns(
14464 addresses_len += 1;14480 addresses_len += 1;
14465 },14481 },
14466 .CNAME => {14482 .CNAME => {
14467 _, canonical_name = HostName.expand(record.packet, record.data_off, options.canonical_name_buffer) catch14483 if (options.canonical_name_buffer) |buf| {
14468 return error.InvalidDnsCnameRecord;14484 _, canonical_name = HostName.expand(
14485 record.packet,
14486 record.data_off,
14487 buf,
14488 ) catch return error.InvalidDnsCnameRecord;
14489 }
14469 },14490 },
14470 _ => continue,14491 _ => continue,
14471 };14492 };
14472 }14493 }
1447314494
14474 try resolved.putOne(t_io, .{ .canonical_name = canonical_name orelse .{ .bytes = lookup_canon_name } });14495 if (options.canonical_name_buffer != null) {
14496 try resolved.putOne(t_io, .{
14497 .canonical_name = canonical_name orelse .{ .bytes = lookup_canon_name },
14498 });
14499 }
14475 if (addresses_len == 0) return error.NoAddressReturned;14500 if (addresses_len == 0) return error.NoAddressReturned;
14476}14501}
1447714502
...@@ -14552,13 +14577,15 @@ fn lookupHostsReader(...@@ -14552,13 +14577,15 @@ fn lookupHostsReader(
14552 } else continue;14577 } else continue;
1455314578
14554 if (canonical_name == null) {14579 if (canonical_name == null) {
14555 if (HostName.init(first_name_text.?)) |name_text| {14580 if (options.canonical_name_buffer) |buf| {
14556 if (name_text.bytes.len <= options.canonical_name_buffer.len) {14581 if (HostName.init(first_name_text.?)) |name_text| {
14557 const canonical_name_dest = options.canonical_name_buffer[0..name_text.bytes.len];14582 if (name_text.bytes.len <= buf.len) {
14558 @memcpy(canonical_name_dest, name_text.bytes);14583 const canonical_name_dest = buf[0..name_text.bytes.len];
14559 canonical_name = .{ .bytes = canonical_name_dest };14584 @memcpy(canonical_name_dest, name_text.bytes);
14560 }14585 canonical_name = .{ .bytes = canonical_name_dest };
14561 } else |_| {}14586 }
14587 } else |_| {}
14588 }
14562 }14589 }
1456314590
14564 if (options.family != .ip6) {14591 if (options.family != .ip6) {
...@@ -14652,17 +14679,23 @@ const LookupDnsWindows = struct {...@@ -14652,17 +14679,23 @@ const LookupDnsWindows = struct {
14652 });14679 });
14653 },14680 },
14654 };14681 };
14655 if (lookup_dns.results.pQueryRecords) |record| try lookup_dns.resolved.putOne(t_io, .{14682 if (lookup_dns.results.pQueryRecords) |record| {
14656 .canonical_name = .{ .bytes = lookup_dns.options.canonical_name_buffer[0..std.unicode.wtf16LeToWtf8(14683 if (lookup_dns.options.canonical_name_buffer) |buf| {
14657 lookup_dns.options.canonical_name_buffer,14684 const name_wtf16 = std.mem.span(
14658 std.mem.span(@as([*:0]const windows.WCHAR, @ptrCast(@alignCast(record.pName)))),14685 @as([*:0]const windows.WCHAR, @ptrCast(@alignCast(record.pName))),
14659 )] },14686 );
14660 });14687 const len = std.unicode.wtf16LeToWtf8(buf, name_wtf16);
14688 try lookup_dns.resolved.putOne(t_io, .{
14689 .canonical_name = .{ .bytes = buf[0..len] },
14690 });
14691 }
14692 }
14661 }14693 }
14662};14694};
1466314695
14664fn copyCanon(canonical_name_buffer: *[HostName.max_len]u8, name: []const u8) HostName {14696fn copyCanon(canonical_name_buffer: ?*[HostName.max_len]u8, name: []const u8) ?HostName {
14665 const dest = canonical_name_buffer[0..name.len];14697 const buf = canonical_name_buffer orelse return null;
14698 const dest = buf[0..name.len];
14666 @memcpy(dest, name);14699 @memcpy(dest, name);
14667 return .{ .bytes = dest };14700 return .{ .bytes = dest };
14668}14701}
lib/std/Io/net/HostName.zig+1-2
...@@ -125,9 +125,8 @@ pub fn eql(a: HostName, b: HostName) bool {...@@ -125,9 +125,8 @@ pub fn eql(a: HostName, b: HostName) bool {
125125
126pub const LookupOptions = struct {126pub const LookupOptions = struct {
127 port: u16,127 port: u16,
128 request_canonical_name: bool = false,
129 canonical_name_buffer: *[max_len]u8,
130 /// `null` means either.128 /// `null` means either.
129 canonical_name_buffer: ?*[max_len]u8 = null,
131 family: ?IpAddress.Family = null,130 family: ?IpAddress.Family = null,
132};131};
133132
lib/std/Io/net/test.zig-1
...@@ -129,7 +129,6 @@ test "resolve DNS" {...@@ -129,7 +129,6 @@ test "resolve DNS" {
129129
130 net.HostName.lookup(try .init("localhost"), io, &results, .{130 net.HostName.lookup(try .init("localhost"), io, &results, .{
131 .port = 80,131 .port = 80,
132 .request_canonical_name = true,
133 .canonical_name_buffer = &canonical_name_buffer,132 .canonical_name_buffer = &canonical_name_buffer,
134 }) catch |err| switch (err) {133 }) catch |err| switch (err) {
135 error.NetworkDown => return error.SkipZigTest,134 error.NetworkDown => return error.SkipZigTest,