authorgravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2026-01-24 14:01:09 -08:00
committergravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2026-01-24 14:01:09 -08:00
loge2aee9791d52d234b4b4196057508c8734038a7f
tree07bb8cbffb26eb463855fe6bc4179585e38baad4
parent20a830b847b756cea94e66812a39bfaf497cd2fc

populate href field


3 files changed, 31 insertions(+), 6 deletions(-)

generate.ts+1-1
...@@ -57,7 +57,7 @@ pub fn parsePass(input: []const u8, base: ?[]const u8, href: []const u8, origin:...@@ -57,7 +57,7 @@ pub fn parsePass(input: []const u8, base: ?[]const u8, href: []const u8, origin:
57 try expect(u.pathname).toEqualString(pathname);57 try expect(u.pathname).toEqualString(pathname);
58 try expect(u.search).toEqualString(search);58 try expect(u.search).toEqualString(search);
59 try expect(u.hash).toEqualString(hash);59 try expect(u.hash).toEqualString(hash);
60 _ = href;60 try expect(u.href).toEqualString(href);
61}61}
6262
63pub fn parseIDNAFail(comptime input: []const u8) !void {63pub fn parseIDNAFail(comptime input: []const u8) !void {
url.zig+29-4
...@@ -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,
2020
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 };
2627
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 {
8789
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 // scheme94 // 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 }
816821
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();
818842
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}
1467fn setHost(href: *ManyArrayList(15, u8), h: URL.Host) !void {1491fn 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 },
zig-out/test.zig+1-1
...@@ -27,7 +27,7 @@ pub fn parsePass(input: []const u8, base: ?[]const u8, href: []const u8, origin:...@@ -27,7 +27,7 @@ pub fn parsePass(input: []const u8, base: ?[]const u8, href: []const u8, origin:
27 try expect(u.pathname).toEqualString(pathname);27 try expect(u.pathname).toEqualString(pathname);
28 try expect(u.search).toEqualString(search);28 try expect(u.search).toEqualString(search);
29 try expect(u.hash).toEqualString(hash);29 try expect(u.hash).toEqualString(hash);
30 _ = href;30 try expect(u.href).toEqualString(href);
31}31}
3232
33pub fn parseIDNAFail(comptime input: []const u8) !void {33pub fn parseIDNAFail(comptime input: []const u8) !void {