| ... | ... | @@ -11,7 +11,7 @@ pub const URL = struct { |
| 11 | 11 | username: []const u8, |
| 12 | 12 | password: []const u8, |
| 13 | 13 | hostname: []const u8, |
| 14 | | hostname_kind: HostKind = .name, |
| 14 | hostname_kind: HostKind, |
| 15 | 15 | port: []const u8, |
| 16 | 16 | host: []const u8, |
| 17 | 17 | pathname: []const u8, |
| ... | ... | @@ -19,12 +19,14 @@ pub const URL = struct { |
| 19 | 19 | hash: []const u8, |
| 20 | 20 | |
| 21 | 21 | pub const HostKind = enum { |
| 22 | unset, |
| 22 | 23 | name, |
| 23 | 24 | ipv4, |
| 24 | 25 | ipv6, |
| 25 | 26 | }; |
| 26 | 27 | |
| 27 | 28 | const Host = union(HostKind) { |
| 29 | unset: void, |
| 28 | 30 | name: []const u8, |
| 29 | 31 | ipv4: u32, |
| 30 | 32 | ipv6: u128, |
| ... | ... | @@ -87,7 +89,8 @@ pub const URL = struct { |
| 87 | 89 | |
| 88 | 90 | var href = ManyArrayList(8 + 7, u8).init(alloc); |
| 89 | 91 | defer href.deinit(); |
| 90 | | var hostname_kind: HostKind = .name; |
| 92 | var hostname_kind: HostKind = .unset; |
| 93 | var has_opaque_path = false; |
| 91 | 94 | // scheme |
| 92 | 95 | // : |
| 93 | 96 | // // |
| ... | ... | @@ -178,6 +181,7 @@ pub const URL = struct { |
| 178 | 181 | else { |
| 179 | 182 | href.clear(10); |
| 180 | 183 | state = .opaque_path; |
| 184 | has_opaque_path = true; |
| 181 | 185 | } |
| 182 | 186 | } |
| 183 | 187 | // 3. Otherwise, if state override is not given, set buffer to the empty string, state to no scheme state, and start over (from the first code point in input). |
| ... | ... | @@ -402,7 +406,6 @@ pub const URL = struct { |
| 402 | 406 | hostname_kind = h; |
| 403 | 407 | buffer.clearRetainingCapacity(); |
| 404 | 408 | state = .port; |
| 405 | | try href.set(8, ":"); |
| 406 | 409 | } |
| 407 | 410 | // 3. Otherwise, if one of the following is true: |
| 408 | 411 | // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#) |
| ... | ... | @@ -479,6 +482,7 @@ pub const URL = struct { |
| 479 | 482 | try href.set(0, "file"); |
| 480 | 483 | // 2. Set url’s host to the empty string. |
| 481 | 484 | href.clear(7); |
| 485 | hostname_kind = .name; |
| 482 | 486 | // 3. If c is U+002F (/) or U+005C (\), then: |
| 483 | 487 | if (c == '/' or c == '\\') { |
| 484 | 488 | // 1. If c is U+005C (\), invalid-reverse-solidus validation error. |
| ... | ... | @@ -574,6 +578,7 @@ pub const URL = struct { |
| 574 | 578 | else if (buffer.items.len == 0) { |
| 575 | 579 | // 1. Set url’s host to the empty string. |
| 576 | 580 | href.clear(7); |
| 581 | hostname_kind = .name; |
| 577 | 582 | // 2. If state override is given, then return. |
| 578 | 583 | if (state_override != null) break; |
| 579 | 584 | // 3. Set state to path start state. |
| ... | ... | @@ -814,6 +819,25 @@ pub const URL = struct { |
| 814 | 819 | } |
| 815 | 820 | } |
| 816 | 821 | |
| 822 | if (hostname_kind != .unset) { |
| 823 | try href.appendSlice(2, "//"); |
| 824 | } |
| 825 | if (href.lengths[5] > 0) { |
| 826 | try href.set(4, ":"); |
| 827 | } |
| 828 | if (href.lengths[3] > 0 or href.lengths[5] > 0) { |
| 829 | try href.set(6, "@"); |
| 830 | } |
| 831 | if (href.lengths[9] > 0) { |
| 832 | try href.set(8, ":"); |
| 833 | } |
| 834 | |
| 835 | var path_offset: usize = 0; |
| 836 | if (hostname_kind == .unset and !has_opaque_path and std.mem.startsWith(u8, href.items(10), "//")) { |
| 837 | try href.replace(10, 0, 0, "/."); |
| 838 | path_offset += 2; |
| 839 | } |
| 840 | |
| 817 | 841 | const _href = try href.list.toOwnedSlice(); |
| 818 | 842 | |
| 819 | 843 | const url: URL = .{ |
| ... | ... | @@ -825,7 +849,7 @@ pub const URL = struct { |
| 825 | 849 | .hostname_kind = hostname_kind, |
| 826 | 850 | .port = _href[extras.sum(usize, href.lengths[0..9])..][0..href.lengths[9]], |
| 827 | 851 | .host = _href[extras.sum(usize, href.lengths[0..7])..][0..extras.sum(usize, href.lengths[7..][0..if (href.lengths[9] == 0) 1 else 3])], |
| 828 | | .pathname = _href[extras.sum(usize, href.lengths[0..10])..][0..href.lengths[10]], |
| 852 | .pathname = _href[extras.sum(usize, href.lengths[0..10])..][0..href.lengths[10]][path_offset..], |
| 829 | 853 | .search = if (href.lengths[12] == 0) "" else _href[extras.sum(usize, href.lengths[0..11])..][0..extras.sum(usize, href.lengths[11..][0..2])], |
| 830 | 854 | .hash = if (href.lengths[14] == 0) "" else _href[extras.sum(usize, href.lengths[0..13])..][0..extras.sum(usize, href.lengths[13..][0..2])], |
| 831 | 855 | }; |
| ... | ... | @@ -1466,6 +1490,7 @@ fn percentEncodeML(list: *ManyArrayList(15, u8), n: usize, input: []const u8, co |
| 1466 | 1490 | } |
| 1467 | 1491 | fn setHost(href: *ManyArrayList(15, u8), h: URL.Host) !void { |
| 1468 | 1492 | switch (h) { |
| 1493 | .unset => unreachable, |
| 1469 | 1494 | .name => { |
| 1470 | 1495 | try href.set(7, h.name); |
| 1471 | 1496 | }, |