| ... | @@ -70,7 +70,7 @@ pub const IpAddress = union(enum) { | ... | @@ -70,7 +70,7 @@ pub const IpAddress = union(enum) { |
| 70 | pub fn parseLiteral(text: []const u8) ParseLiteralError!IpAddress { | 70 | pub fn parseLiteral(text: []const u8) ParseLiteralError!IpAddress { |
| 71 | if (text.len == 0) return error.InvalidAddress; | 71 | if (text.len == 0) return error.InvalidAddress; |
| 72 | if (text[0] == '[') { | 72 | if (text[0] == '[') { |
| 73 | const addr_end = std.mem.indexOfScalar(u8, text, ']') orelse | 73 | const addr_end = std.mem.findScalar(u8, text, ']') orelse |
| 74 | return error.InvalidAddress; | 74 | return error.InvalidAddress; |
| 75 | const addr_text = text[1..addr_end]; | 75 | const addr_text = text[1..addr_end]; |
| 76 | const port: u16 = p: { | 76 | const port: u16 = p: { |
| ... | @@ -80,7 +80,7 @@ pub const IpAddress = union(enum) { | ... | @@ -80,7 +80,7 @@ pub const IpAddress = union(enum) { |
| 80 | }; | 80 | }; |
| 81 | return parseIp6(addr_text, port) catch error.InvalidAddress; | 81 | return parseIp6(addr_text, port) catch error.InvalidAddress; |
| 82 | } | 82 | } |
| 83 | if (std.mem.indexOfScalar(u8, text, ':')) |i| { | 83 | if (std.mem.findScalar(u8, text, ':')) |i| { |
| 84 | const addr = Ip4Address.parse(text[0..i], 0) catch return error.InvalidAddress; | 84 | const addr = Ip4Address.parse(text[0..i], 0) catch return error.InvalidAddress; |
| 85 | return .{ .ip4 = .{ | 85 | return .{ .ip4 = .{ |
| 86 | .bytes = addr.bytes, | 86 | .bytes = addr.bytes, |
| ... | @@ -431,17 +431,22 @@ pub const Ip6Address = struct { | ... | @@ -431,17 +431,22 @@ pub const Ip6Address = struct { |
| 431 | pub const Parsed = union(enum) { | 431 | pub const Parsed = union(enum) { |
| 432 | success: Unresolved, | 432 | success: Unresolved, |
| 433 | invalid_byte: usize, | 433 | invalid_byte: usize, |
| 434 | unexpected_end, | 434 | incomplete, |
| 435 | junk_after_end: usize, | 435 | junk_after_end: usize, |
| 436 | interface_name_oversized: usize, | 436 | interface_name_oversized: usize, |
| | 437 | invalid_ip4_mapping: usize, |
| | 438 | overflow: usize, |
| 437 | }; | 439 | }; |
| 438 | | 440 | |
| 439 | pub fn parse(text: []const u8) Parsed { | 441 | pub fn parse(text: []const u8) Parsed { |
| 440 | if (text.len < 2) return .unexpected_end; | 442 | if (text.len < 2) return .incomplete; |
| 441 | if (std.ascii.startsWithIgnoreCase(text, "::ffff:")) ip4_mapped: { | 443 | const ip4_prefix = "::ffff:"; |
| 442 | const a4 = (Ip4Address.parse(text["::ffff:".len..], 0) catch break :ip4_mapped).bytes; | 444 | if (std.ascii.startsWithIgnoreCase(text, ip4_prefix)) { |
| | 445 | const parsed = Ip4Address.parse(text[ip4_prefix.len..], 0) catch |
| | 446 | return .{ .invalid_ip4_mapping = ip4_prefix.len }; |
| | 447 | const b = parsed.bytes; |
| 443 | return .{ .success = .{ | 448 | return .{ .success = .{ |
| 444 | .bytes = .{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, a4[0], a4[1], a4[2], a4[3] }, | 449 | .bytes = .{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, b[0], b[1], b[2], b[3] }, |
| 445 | .interface_name = null, | 450 | .interface_name = null, |
| 446 | } }; | 451 | } }; |
| 447 | } | 452 | } |
| ... | @@ -457,7 +462,9 @@ pub const Ip6Address = struct { | ... | @@ -457,7 +462,9 @@ pub const Ip6Address = struct { |
| 457 | .digit => c: switch (text[text_i]) { | 462 | .digit => c: switch (text[text_i]) { |
| 458 | 'a'...'f' => |c| { | 463 | 'a'...'f' => |c| { |
| 459 | const digit = c - 'a' + 10; | 464 | const digit = c - 'a' + 10; |
| 460 | parts[parts_i] = parts[parts_i] * 16 + digit; | 465 | parts[parts_i] = (std.math.mul(u16, parts[parts_i], 16) catch return .{ |
| | 466 | .overflow = text_i, |
| | 467 | }) + digit; |
| 461 | if (digit_i == 4) return .{ .invalid_byte = text_i }; | 468 | if (digit_i == 4) return .{ .invalid_byte = text_i }; |
| 462 | digit_i += 1; | 469 | digit_i += 1; |
| 463 | text_i += 1; | 470 | text_i += 1; |
| ... | @@ -470,7 +477,9 @@ pub const Ip6Address = struct { | ... | @@ -470,7 +477,9 @@ pub const Ip6Address = struct { |
| 470 | 'A'...'F' => |c| continue :c c - 'A' + 'a', | 477 | 'A'...'F' => |c| continue :c c - 'A' + 'a', |
| 471 | '0'...'9' => |c| { | 478 | '0'...'9' => |c| { |
| 472 | const digit = c - '0'; | 479 | const digit = c - '0'; |
| 473 | parts[parts_i] = parts[parts_i] * 16 + digit; | 480 | parts[parts_i] = (std.math.mul(u16, parts[parts_i], 16) catch return .{ |
| | 481 | .overflow = text_i, |
| | 482 | }) + digit; |
| 474 | if (digit_i == 4) return .{ .invalid_byte = text_i }; | 483 | if (digit_i == 4) return .{ .invalid_byte = text_i }; |
| 475 | digit_i += 1; | 484 | digit_i += 1; |
| 476 | text_i += 1; | 485 | text_i += 1; |
| ... | @@ -497,7 +506,7 @@ pub const Ip6Address = struct { | ... | @@ -497,7 +506,7 @@ pub const Ip6Address = struct { |
| 497 | if (parts.len - parts_i == 0) continue :state .end; | 506 | if (parts.len - parts_i == 0) continue :state .end; |
| 498 | digit_i = 0; | 507 | digit_i = 0; |
| 499 | text_i += 1; | 508 | text_i += 1; |
| 500 | if (text.len - text_i == 0) return .unexpected_end; | 509 | if (text.len - text_i == 0) return .incomplete; |
| 501 | continue :c text[text_i]; | 510 | continue :c text[text_i]; |
| 502 | } | 511 | } |
| 503 | }, | 512 | }, |
| ... | @@ -507,6 +516,7 @@ pub const Ip6Address = struct { | ... | @@ -507,6 +516,7 @@ pub const Ip6Address = struct { |
| 507 | text_i += 1; | 516 | text_i += 1; |
| 508 | const name = text[text_i..]; | 517 | const name = text[text_i..]; |
| 509 | if (name.len > Interface.Name.max_len) return .{ .interface_name_oversized = text_i }; | 518 | if (name.len > Interface.Name.max_len) return .{ .interface_name_oversized = text_i }; |
| | 519 | if (name.len == 0) return .incomplete; |
| 510 | interface_name_text = name; | 520 | interface_name_text = name; |
| 511 | text_i = @intCast(text.len); | 521 | text_i = @intCast(text.len); |
| 512 | continue :state .end; | 522 | continue :state .end; |
| ... | @@ -521,7 +531,7 @@ pub const Ip6Address = struct { | ... | @@ -521,7 +531,7 @@ pub const Ip6Address = struct { |
| 521 | @memmove(parts[parts.len - src.len ..], src); | 531 | @memmove(parts[parts.len - src.len ..], src); |
| 522 | @memset(parts[s..][0..remaining], 0); | 532 | @memset(parts[s..][0..remaining], 0); |
| 523 | } else { | 533 | } else { |
| 524 | if (remaining != 0) return .unexpected_end; | 534 | if (remaining != 0) return .incomplete; |
| 525 | } | 535 | } |
| 526 | | 536 | |
| 527 | // Workaround that can be removed when this proposal is | 537 | // Workaround that can be removed when this proposal is |