diff --git a/generate.ts b/generate.ts index 3b6d3129dbdeacddbed0cdacc815212ccd74eac3..98b1496aa509597ccb5c498a32b886a7b7876cc1 100644 --- a/generate.ts +++ b/generate.ts @@ -50,7 +50,7 @@ pub fn parsePass(input: []const u8, base: ?[]const u8, href: []const u8, origin: _ = href; _ = origin; try expect(u.protocol).toEqualString(protocol); - _ = username; + try expect(u.username).toEqualString(username); _ = password; _ = host; _ = hostname; diff --git a/url.zig b/url.zig index 711e9d29ef09a9e6cb2ee859d24462ec0ed180de..4a41caa4bf9ccf168a52a734bc865d7945918823 100644 --- a/url.zig +++ b/url.zig @@ -8,6 +8,7 @@ pub const URL = struct { href: []const u8, scheme: []const u8 = "", protocol: []const u8, + username: []const u8, pub const HostKind = enum { name, @@ -327,11 +328,21 @@ pub const URL = struct { // 3. Set atSignSeen to true. atSignSeen = true; // 4. For each codePoint in buffer: - { + var it = std.unicode.Utf8View.initUnchecked(buffer.items).iterator(); + while (it.nextCodepointSlice()) |sl| { // 1. If codePoint is U+003A (:) and passwordTokenSeen is false, then set passwordTokenSeen to true and continue. + if (sl[0] == ':' and !passwordTokenSeen) { + passwordTokenSeen = true; + continue; + } // 2. Let encodedCodePoints be the result of running UTF-8 percent-encode codePoint using the userinfo percent-encode set. // 3. If passwordTokenSeen is true, then append encodedCodePoints to url’s password. // 4. Otherwise, append encodedCodePoints to url’s username. + if (passwordTokenSeen) { + try percentEncodeScalarML(&href, 5, sl, is_userinfo_percent_char); + } else { + try percentEncodeScalarML(&href, 3, sl, is_userinfo_percent_char); + } } // 5. Set buffer to the empty string. buffer.clearRetainingCapacity(); @@ -769,6 +780,7 @@ pub const URL = struct { const url: URL = .{ .href = _href, .protocol = _href[0..extras.sum(usize, href.lengths[0..2])], + .username = _href[extras.sum(usize, href.lengths[0..2])..][0..href.lengths[3]], }; return url; } @@ -1323,23 +1335,25 @@ fn is_fragment_percent_char(c: u8) bool { if (c == '`') return true; return is_c0control_percent_char(c); } - -// fn is_userinfo_percent_char(c: u8) bool { -// if (c == '/') return true; -// if (c == ':') return true; -// if (c == ';') return true; -// if (c == '=') return true; -// if (c == '@') return true; -// if (c >= '[' and c <= '^') return true; -// if (c == '|') return true; -// return is_path_percent_char(c); -// } +/// https://url.spec.whatwg.org/#userinfo-percent-encode-set +fn is_userinfo_percent_char(c: u8) bool { + if (c == '/') return true; + if (c == ':') return true; + if (c == ';') return true; + if (c == '=') return true; + if (c == '@') return true; + if (c >= '[' and c <= '^') return true; + if (c == '|') return true; + return is_path_percent_char(c); +} +// /// https://url.spec.whatwg.org/#component-percent-encode-set // fn is_component_percent_char(c: u8) bool { // if (c >= '$' and c <= '&') return true; // if (c == '+') return true; // if (c == ',') return true; // return is_userinfo_percent_char(c); // } +// /// https://url.spec.whatwg.org/#application-x-www-form-urlencoded-percent-encode-set // fn is_formurlencoded_percent_char(c: u8) bool { // if (c == '!') return true; // if (c >= '\'' and c <= ')') return true; @@ -1360,7 +1374,7 @@ fn percentEncodeScalarAL(list: *std.ArrayList(u8), cp: []const u8, comptime set: if (set(cp[0])) { for (cp) |b| { try list.append('%'); - try list.writer().print("{d:0<2}", .{b}); + try list.writer().print("{X:0<2}", .{b}); } } else { try list.append(cp[0]); @@ -1372,7 +1386,7 @@ fn percentEncodeAL(list: *std.ArrayList(u8), input: []const u8, comptime set: fn if (set(sl[0])) { for (sl) |b| { try list.append('%'); - try list.writer().print("{d:0<2}", .{b}); + try list.writer().print("{X:0<2}", .{b}); } } else { try list.appendSlice(sl); @@ -1383,7 +1397,7 @@ fn percentEncodeScalarML(list: *ManyArrayList(15, u8), n: usize, cp: []const u8, if (set(cp[0])) { for (cp) |b| { try list.appendSlice(n, &.{'%'}); - try list.print(n, "{d:0<2}", .{b}); + try list.print(n, "{X:0<2}", .{b}); } } else { try list.appendSlice(n, &.{cp[0]}); @@ -1395,7 +1409,7 @@ fn percentEncodeML(list: *ManyArrayList(15, u8), n: usize, input: []const u8, co if (set(sl[0])) { for (sl) |b| { try list.appendSlice(n, &.{'%'}); - try list.print(n, "{d:0<2}", .{b}); + try list.print(n, "{X:0<2}", .{b}); } } else { try list.appendSlice(n, sl); diff --git a/zig-out/test.zig b/zig-out/test.zig index 61c3dba9d695660ed1a714c2d8370665b3fb8926..b91c16aeb63285e558a0a3d8d06a357c7a0e5b7e 100644 --- a/zig-out/test.zig +++ b/zig-out/test.zig @@ -20,7 +20,7 @@ pub fn parsePass(input: []const u8, base: ?[]const u8, href: []const u8, origin: _ = href; _ = origin; try expect(u.protocol).toEqualString(protocol); - _ = username; + try expect(u.username).toEqualString(username); _ = password; _ = host; _ = hostname;