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(
1348113481 if (is_windows) {
1348213482 if (options.family == null) {
1348313483 if (IpAddress.parseIp4(name, options.port)) |addr| {
13484 try resolved.putAll(t_io, &.{
13485 .{ .address = addr },
13486 .{ .canonical_name = copyCanon(options.canonical_name_buffer, name) },
13487 });
13484 if (copyCanon(options.canonical_name_buffer, name)) |canon| {
13485 try resolved.putAll(t_io, &.{
13486 .{ .address = addr },
13487 .{ .canonical_name = canon },
13488 });
13489 } else {
13490 try resolved.putOne(t_io, .{ .address = addr });
13491 }
1348813492 return;
1348913493 } else |_| {}
1349013494 }
......@@ -13608,20 +13612,28 @@ fn netLookupFallible(
1360813612 if (native_os == .linux) {
1360913613 if (options.family != .ip4) {
1361013614 if (IpAddress.parseIp6(name, options.port)) |addr| {
13611 try resolved.putAll(t_io, &.{
13612 .{ .address = addr },
13613 .{ .canonical_name = copyCanon(options.canonical_name_buffer, name) },
13614 });
13615 if (copyCanon(options.canonical_name_buffer, name)) |canon| {
13616 try resolved.putAll(t_io, &.{
13617 .{ .address = addr },
13618 .{ .canonical_name = canon },
13619 });
13620 } else {
13621 try resolved.putOne(t_io, .{ .address = addr });
13622 }
1361513623 return;
1361613624 } else |_| {}
1361713625 }
1361813626
1361913627 if (options.family != .ip6) {
1362013628 if (IpAddress.parseIp4(name, options.port)) |addr| {
13621 try resolved.putAll(t_io, &.{
13622 .{ .address = addr },
13623 .{ .canonical_name = copyCanon(options.canonical_name_buffer, name) },
13624 });
13629 if (copyCanon(options.canonical_name_buffer, name)) |canon| {
13630 try resolved.putAll(t_io, &.{
13631 .{ .address = addr },
13632 .{ .canonical_name = canon },
13633 });
13634 } else {
13635 try resolved.putOne(t_io, .{ .address = addr });
13636 }
1362513637 return;
1362613638 } else |_| {}
1362713639 }
......@@ -13652,11 +13664,13 @@ fn netLookupFallible(
1365213664 results_buffer[results_index] = .{ .address = .{ .ip4 = .loopback(options.port) } };
1365313665 results_index += 1;
1365413666 }
13655 const canon_name = "localhost";
13656 const canon_name_dest = options.canonical_name_buffer[0..canon_name.len];
13657 canon_name_dest.* = canon_name.*;
13658 results_buffer[results_index] = .{ .canonical_name = .{ .bytes = canon_name_dest } };
13659 results_index += 1;
13667 if (options.canonical_name_buffer) |buf| {
13668 const canon_name = "localhost";
13669 const canon_name_dest = buf[0..canon_name.len];
13670 canon_name_dest.* = canon_name.*;
13671 results_buffer[results_index] = .{ .canonical_name = .{ .bytes = canon_name_dest } };
13672 results_index += 1;
13673 }
1366013674 try resolved.putAll(t_io, results_buffer[0..results_index]);
1366113675 return;
1366213676 }
......@@ -13688,7 +13702,7 @@ fn netLookupFallible(
1368813702 const port_c = std.fmt.bufPrintZ(&port_buffer, "{d}", .{options.port}) catch unreachable;
1368913703
1369013704 const hints: posix.addrinfo = .{
13691 .flags = .{ .CANONNAME = options.request_canonical_name, .NUMERICSERV = true },
13705 .flags = .{ .CANONNAME = options.canonical_name_buffer != null, .NUMERICSERV = true },
1369213706 .family = posix.AF.UNSPEC,
1369313707 .socktype = posix.SOCK.STREAM,
1369413708 .protocol = posix.IPPROTO.TCP,
......@@ -13745,9 +13759,9 @@ fn netLookupFallible(
1374513759 }
1374613760 }
1374713761 if (canon_name) |n| {
13748 try resolved.putOne(t_io, .{
13749 .canonical_name = copyCanon(options.canonical_name_buffer, std.mem.sliceTo(n, 0)),
13750 });
13762 if (copyCanon(options.canonical_name_buffer, std.mem.sliceTo(n, 0))) |canon| {
13763 try resolved.putOne(t_io, .{ .canonical_name = canon });
13764 }
1375113765 }
1375213766 return;
1375313767 }
......@@ -14268,12 +14282,14 @@ fn lookupDnsSearch(
1426814282 // both provides the desired default canonical name (if the requested
1426914283 // name is not a CNAME record) and serves as a buffer for passing the
1427014284 // full requested name to `lookupDns`.
14271 @memcpy(options.canonical_name_buffer[0..canon_name.len], canon_name);
14272 options.canonical_name_buffer[canon_name.len] = '.';
14285 var local_buf: [HostName.max_len]u8 = undefined;
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] = '.';
1427314289 var it = std.mem.tokenizeAny(u8, search, " \t");
1427414290 while (it.next()) |token| {
14275 @memcpy(options.canonical_name_buffer[canon_name.len + 1 ..][0..token.len], token);
14276 const lookup_canon_name = options.canonical_name_buffer[0 .. canon_name.len + 1 + token.len];
14291 @memcpy(canon_buf[canon_name.len + 1 ..][0..token.len], token);
14292 const lookup_canon_name = canon_buf[0 .. canon_name.len + 1 + token.len];
1427714293 if (t.lookupDns(lookup_canon_name, &rc, resolved, options)) |result| {
1427814294 return result;
1427914295 } else |err| switch (err) {
......@@ -14282,7 +14298,7 @@ fn lookupDnsSearch(
1428214298 }
1428314299 }
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];
1428614302 return t.lookupDns(lookup_canon_name, &rc, resolved, options);
1428714303}
1428814304
......@@ -14464,14 +14480,23 @@ fn lookupDns(
1446414480 addresses_len += 1;
1446514481 },
1446614482 .CNAME => {
14467 _, canonical_name = HostName.expand(record.packet, record.data_off, options.canonical_name_buffer) catch
14468 return error.InvalidDnsCnameRecord;
14483 if (options.canonical_name_buffer) |buf| {
14484 _, canonical_name = HostName.expand(
14485 record.packet,
14486 record.data_off,
14487 buf,
14488 ) catch return error.InvalidDnsCnameRecord;
14489 }
1446914490 },
1447014491 _ => continue,
1447114492 };
1447214493 }
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 }
1447514500 if (addresses_len == 0) return error.NoAddressReturned;
1447614501}
1447714502
......@@ -14552,13 +14577,15 @@ fn lookupHostsReader(
1455214577 } else continue;
1455314578
1455414579 if (canonical_name == null) {
14555 if (HostName.init(first_name_text.?)) |name_text| {
14556 if (name_text.bytes.len <= options.canonical_name_buffer.len) {
14557 const canonical_name_dest = options.canonical_name_buffer[0..name_text.bytes.len];
14558 @memcpy(canonical_name_dest, name_text.bytes);
14559 canonical_name = .{ .bytes = canonical_name_dest };
14560 }
14561 } else |_| {}
14580 if (options.canonical_name_buffer) |buf| {
14581 if (HostName.init(first_name_text.?)) |name_text| {
14582 if (name_text.bytes.len <= buf.len) {
14583 const canonical_name_dest = buf[0..name_text.bytes.len];
14584 @memcpy(canonical_name_dest, name_text.bytes);
14585 canonical_name = .{ .bytes = canonical_name_dest };
14586 }
14587 } else |_| {}
14588 }
1456214589 }
1456314590
1456414591 if (options.family != .ip6) {
......@@ -14652,17 +14679,23 @@ const LookupDnsWindows = struct {
1465214679 });
1465314680 },
1465414681 };
14655 if (lookup_dns.results.pQueryRecords) |record| try lookup_dns.resolved.putOne(t_io, .{
14656 .canonical_name = .{ .bytes = lookup_dns.options.canonical_name_buffer[0..std.unicode.wtf16LeToWtf8(
14657 lookup_dns.options.canonical_name_buffer,
14658 std.mem.span(@as([*:0]const windows.WCHAR, @ptrCast(@alignCast(record.pName)))),
14659 )] },
14660 });
14682 if (lookup_dns.results.pQueryRecords) |record| {
14683 if (lookup_dns.options.canonical_name_buffer) |buf| {
14684 const name_wtf16 = std.mem.span(
14685 @as([*:0]const windows.WCHAR, @ptrCast(@alignCast(record.pName))),
14686 );
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 }
1466114693 }
1466214694};
1466314695
14664fn copyCanon(canonical_name_buffer: *[HostName.max_len]u8, name: []const u8) HostName {
14665 const dest = canonical_name_buffer[0..name.len];
14696fn copyCanon(canonical_name_buffer: ?*[HostName.max_len]u8, name: []const u8) ?HostName {
14697 const buf = canonical_name_buffer orelse return null;
14698 const dest = buf[0..name.len];
1466614699 @memcpy(dest, name);
1466714700 return .{ .bytes = dest };
1466814701}
lib/std/Io/net/HostName.zig+1-2
......@@ -125,9 +125,8 @@ pub fn eql(a: HostName, b: HostName) bool {
125125
126126pub const LookupOptions = struct {
127127 port: u16,
128 request_canonical_name: bool = false,
129 canonical_name_buffer: *[max_len]u8,
130128 /// `null` means either.
129 canonical_name_buffer: ?*[max_len]u8 = null,
131130 family: ?IpAddress.Family = null,
132131};
133132
lib/std/Io/net/test.zig-1
......@@ -129,7 +129,6 @@ test "resolve DNS" {
129129
130130 net.HostName.lookup(try .init("localhost"), io, &results, .{
131131 .port = 80,
132 .request_canonical_name = true,
133132 .canonical_name_buffer = &canonical_name_buffer,
134133 }) catch |err| switch (err) {
135134 error.NetworkDown => return error.SkipZigTest,