mirror of
https://github.com/ziglang/zig.git
synced 2026-01-20 22:35:24 +00:00
std.net: Fix IPv6 address format compression for long zero runs (#22441)
This commit is contained in:
parent
220f80e71d
commit
77007445bf
@ -683,17 +683,50 @@ pub const Ip6Address = extern struct {
|
||||
break :blk buf;
|
||||
},
|
||||
};
|
||||
|
||||
// Find the longest zero run
|
||||
var longest_start: usize = 8;
|
||||
var longest_len: usize = 0;
|
||||
var current_start: usize = 0;
|
||||
var current_len: usize = 0;
|
||||
|
||||
for (native_endian_parts, 0..) |part, i| {
|
||||
if (part == 0) {
|
||||
if (current_len == 0) {
|
||||
current_start = i;
|
||||
}
|
||||
current_len += 1;
|
||||
if (current_len > longest_len) {
|
||||
longest_start = current_start;
|
||||
longest_len = current_len;
|
||||
}
|
||||
} else {
|
||||
current_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Only compress if the longest zero run is 2 or more
|
||||
if (longest_len < 2) {
|
||||
longest_start = 8;
|
||||
longest_len = 0;
|
||||
}
|
||||
|
||||
try out_stream.writeAll("[");
|
||||
var i: usize = 0;
|
||||
var abbrv = false;
|
||||
while (i < native_endian_parts.len) : (i += 1) {
|
||||
if (native_endian_parts[i] == 0) {
|
||||
if (i == longest_start) {
|
||||
// Emit "::" for the longest zero run
|
||||
if (!abbrv) {
|
||||
try out_stream.writeAll(if (i == 0) "::" else ":");
|
||||
abbrv = true;
|
||||
}
|
||||
i += longest_len - 1; // Skip the compressed range
|
||||
continue;
|
||||
}
|
||||
if (abbrv) {
|
||||
abbrv = false;
|
||||
}
|
||||
try std.fmt.format(out_stream, "{x}", .{native_endian_parts[i]});
|
||||
if (i != native_endian_parts.len - 1) {
|
||||
try out_stream.writeAll(":");
|
||||
|
||||
@ -26,6 +26,62 @@ test "parse and render IP addresses at comptime" {
|
||||
}
|
||||
}
|
||||
|
||||
test "format IPv6 address with no zero runs" {
|
||||
if (builtin.os.tag == .wasi) return error.SkipZigTest;
|
||||
|
||||
const addr = try std.net.Address.parseIp6("2001:db8:1:2:3:4:5:6", 0);
|
||||
|
||||
var buffer: [50]u8 = undefined;
|
||||
const result = std.fmt.bufPrint(buffer[0..], "{}", .{addr}) catch unreachable;
|
||||
|
||||
try std.testing.expectEqualStrings("[2001:db8:1:2:3:4:5:6]:0", result);
|
||||
}
|
||||
|
||||
test "parse IPv6 addresses and check compressed form" {
|
||||
if (builtin.os.tag == .wasi) return error.SkipZigTest;
|
||||
|
||||
const alloc = testing.allocator;
|
||||
|
||||
// 1) Parse an IPv6 address that should compress to [2001:db8::1:0:0:2]:0
|
||||
const addr1 = try std.net.Address.parseIp6("2001:0db8:0000:0000:0001:0000:0000:0002", 0);
|
||||
|
||||
// 2) Parse an IPv6 address that should compress to [2001:db8::1:2]:0
|
||||
const addr2 = try std.net.Address.parseIp6("2001:0db8:0000:0000:0000:0000:0001:0002", 0);
|
||||
|
||||
// 3) Parse an IPv6 address that should compress to [2001:db8:1:0:1::2]:0
|
||||
const addr3 = try std.net.Address.parseIp6("2001:0db8:0001:0000:0001:0000:0000:0002", 0);
|
||||
|
||||
// Print each address in Zig's default "[ipv6]:port" form.
|
||||
const printed1 = try std.fmt.allocPrint(alloc, "{any}", .{addr1});
|
||||
defer testing.allocator.free(printed1);
|
||||
const printed2 = try std.fmt.allocPrint(alloc, "{any}", .{addr2});
|
||||
defer testing.allocator.free(printed2);
|
||||
const printed3 = try std.fmt.allocPrint(alloc, "{any}", .{addr3});
|
||||
defer testing.allocator.free(printed3);
|
||||
|
||||
// Check the exact compressed forms we expect.
|
||||
try std.testing.expectEqualStrings("[2001:db8::1:0:0:2]:0", printed1);
|
||||
try std.testing.expectEqualStrings("[2001:db8::1:2]:0", printed2);
|
||||
try std.testing.expectEqualStrings("[2001:db8:1:0:1::2]:0", printed3);
|
||||
}
|
||||
|
||||
test "parse IPv6 address, check raw bytes" {
|
||||
if (builtin.os.tag == .wasi) return error.SkipZigTest;
|
||||
|
||||
const expected_raw: [16]u8 = .{
|
||||
0x20, 0x01, 0x0d, 0xb8, // 2001:db8
|
||||
0x00, 0x00, 0x00, 0x00, // :0000:0000
|
||||
0x00, 0x01, 0x00, 0x00, // :0001:0000
|
||||
0x00, 0x00, 0x00, 0x02, // :0000:0002
|
||||
};
|
||||
|
||||
const addr = try std.net.Address.parseIp6("2001:db8:0000:0000:0001:0000:0000:0002", 0);
|
||||
|
||||
const actual_raw = addr.in6.sa.addr[0..];
|
||||
try std.testing.expectEqualSlices(u8, expected_raw[0..], actual_raw);
|
||||
|
||||
}
|
||||
|
||||
test "parse and render IPv6 addresses" {
|
||||
if (builtin.os.tag == .wasi) return error.SkipZigTest;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user