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