| ... | @@ -8,6 +8,7 @@ pub const URL = struct { | ... | @@ -8,6 +8,7 @@ pub const URL = struct { |
| 8 | href: []const u8, | 8 | href: []const u8, |
| 9 | scheme: []const u8 = "", | 9 | scheme: []const u8 = "", |
| 10 | protocol: []const u8, | 10 | protocol: []const u8, |
| | 11 | username: []const u8, |
| 11 | | 12 | |
| 12 | pub const HostKind = enum { | 13 | pub const HostKind = enum { |
| 13 | name, | 14 | name, |
| ... | @@ -327,11 +328,21 @@ pub const URL = struct { | ... | @@ -327,11 +328,21 @@ pub const URL = struct { |
| 327 | // 3. Set atSignSeen to true. | 328 | // 3. Set atSignSeen to true. |
| 328 | atSignSeen = true; | 329 | atSignSeen = true; |
| 329 | // 4. For each codePoint in buffer: | 330 | // 4. For each codePoint in buffer: |
| 330 | { | 331 | var it = std.unicode.Utf8View.initUnchecked(buffer.items).iterator(); |
| | 332 | while (it.nextCodepointSlice()) |sl| { |
| 331 | // 1. If codePoint is U+003A (:) and passwordTokenSeen is false, then set passwordTokenSeen to true and continue. | 333 | // 1. If codePoint is U+003A (:) and passwordTokenSeen is false, then set passwordTokenSeen to true and continue. |
| | 334 | if (sl[0] == ':' and !passwordTokenSeen) { |
| | 335 | passwordTokenSeen = true; |
| | 336 | continue; |
| | 337 | } |
| 332 | // 2. Let encodedCodePoints be the result of running UTF-8 percent-encode codePoint using the userinfo percent-encode set. | 338 | // 2. Let encodedCodePoints be the result of running UTF-8 percent-encode codePoint using the userinfo percent-encode set. |
| 333 | // 3. If passwordTokenSeen is true, then append encodedCodePoints to url’s password. | 339 | // 3. If passwordTokenSeen is true, then append encodedCodePoints to url’s password. |
| 334 | // 4. Otherwise, append encodedCodePoints to url’s username. | 340 | // 4. Otherwise, append encodedCodePoints to url’s username. |
| | 341 | if (passwordTokenSeen) { |
| | 342 | try percentEncodeScalarML(&href, 5, sl, is_userinfo_percent_char); |
| | 343 | } else { |
| | 344 | try percentEncodeScalarML(&href, 3, sl, is_userinfo_percent_char); |
| | 345 | } |
| 335 | } | 346 | } |
| 336 | // 5. Set buffer to the empty string. | 347 | // 5. Set buffer to the empty string. |
| 337 | buffer.clearRetainingCapacity(); | 348 | buffer.clearRetainingCapacity(); |
| ... | @@ -769,6 +780,7 @@ pub const URL = struct { | ... | @@ -769,6 +780,7 @@ pub const URL = struct { |
| 769 | const url: URL = .{ | 780 | const url: URL = .{ |
| 770 | .href = _href, | 781 | .href = _href, |
| 771 | .protocol = _href[0..extras.sum(usize, href.lengths[0..2])], | 782 | .protocol = _href[0..extras.sum(usize, href.lengths[0..2])], |
| | 783 | .username = _href[extras.sum(usize, href.lengths[0..2])..][0..href.lengths[3]], |
| 772 | }; | 784 | }; |
| 773 | return url; | 785 | return url; |
| 774 | } | 786 | } |
| ... | @@ -1323,23 +1335,25 @@ fn is_fragment_percent_char(c: u8) bool { | ... | @@ -1323,23 +1335,25 @@ fn is_fragment_percent_char(c: u8) bool { |
| 1323 | if (c == '`') return true; | 1335 | if (c == '`') return true; |
| 1324 | return is_c0control_percent_char(c); | 1336 | return is_c0control_percent_char(c); |
| 1325 | } | 1337 | } |
| 1326 | | 1338 | /// https://url.spec.whatwg.org/#userinfo-percent-encode-set |
| 1327 | // fn is_userinfo_percent_char(c: u8) bool { | 1339 | fn is_userinfo_percent_char(c: u8) bool { |
| 1328 | // if (c == '/') return true; | 1340 | if (c == '/') return true; |
| 1329 | // if (c == ':') return true; | 1341 | if (c == ':') return true; |
| 1330 | // if (c == ';') return true; | 1342 | if (c == ';') return true; |
| 1331 | // if (c == '=') return true; | 1343 | if (c == '=') return true; |
| 1332 | // if (c == '@') return true; | 1344 | if (c == '@') return true; |
| 1333 | // if (c >= '[' and c <= '^') return true; | 1345 | if (c >= '[' and c <= '^') return true; |
| 1334 | // if (c == '|') return true; | 1346 | if (c == '|') return true; |
| 1335 | // return is_path_percent_char(c); | 1347 | return is_path_percent_char(c); |
| 1336 | // } | 1348 | } |
| | 1349 | // /// https://url.spec.whatwg.org/#component-percent-encode-set |
| 1337 | // fn is_component_percent_char(c: u8) bool { | 1350 | // fn is_component_percent_char(c: u8) bool { |
| 1338 | // if (c >= '$' and c <= '&') return true; | 1351 | // if (c >= '$' and c <= '&') return true; |
| 1339 | // if (c == '+') return true; | 1352 | // if (c == '+') return true; |
| 1340 | // if (c == ',') return true; | 1353 | // if (c == ',') return true; |
| 1341 | // return is_userinfo_percent_char(c); | 1354 | // return is_userinfo_percent_char(c); |
| 1342 | // } | 1355 | // } |
| | 1356 | // /// https://url.spec.whatwg.org/#application-x-www-form-urlencoded-percent-encode-set |
| 1343 | // fn is_formurlencoded_percent_char(c: u8) bool { | 1357 | // fn is_formurlencoded_percent_char(c: u8) bool { |
| 1344 | // if (c == '!') return true; | 1358 | // if (c == '!') return true; |
| 1345 | // if (c >= '\'' and c <= ')') return true; | 1359 | // if (c >= '\'' and c <= ')') return true; |
| ... | @@ -1360,7 +1374,7 @@ fn percentEncodeScalarAL(list: *std.ArrayList(u8), cp: []const u8, comptime set: | ... | @@ -1360,7 +1374,7 @@ fn percentEncodeScalarAL(list: *std.ArrayList(u8), cp: []const u8, comptime set: |
| 1360 | if (set(cp[0])) { | 1374 | if (set(cp[0])) { |
| 1361 | for (cp) |b| { | 1375 | for (cp) |b| { |
| 1362 | try list.append('%'); | 1376 | try list.append('%'); |
| 1363 | try list.writer().print("{d:0<2}", .{b}); | 1377 | try list.writer().print("{X:0<2}", .{b}); |
| 1364 | } | 1378 | } |
| 1365 | } else { | 1379 | } else { |
| 1366 | try list.append(cp[0]); | 1380 | try list.append(cp[0]); |
| ... | @@ -1372,7 +1386,7 @@ fn percentEncodeAL(list: *std.ArrayList(u8), input: []const u8, comptime set: fn | ... | @@ -1372,7 +1386,7 @@ fn percentEncodeAL(list: *std.ArrayList(u8), input: []const u8, comptime set: fn |
| 1372 | if (set(sl[0])) { | 1386 | if (set(sl[0])) { |
| 1373 | for (sl) |b| { | 1387 | for (sl) |b| { |
| 1374 | try list.append('%'); | 1388 | try list.append('%'); |
| 1375 | try list.writer().print("{d:0<2}", .{b}); | 1389 | try list.writer().print("{X:0<2}", .{b}); |
| 1376 | } | 1390 | } |
| 1377 | } else { | 1391 | } else { |
| 1378 | try list.appendSlice(sl); | 1392 | try list.appendSlice(sl); |
| ... | @@ -1383,7 +1397,7 @@ fn percentEncodeScalarML(list: *ManyArrayList(15, u8), n: usize, cp: []const u8, | ... | @@ -1383,7 +1397,7 @@ fn percentEncodeScalarML(list: *ManyArrayList(15, u8), n: usize, cp: []const u8, |
| 1383 | if (set(cp[0])) { | 1397 | if (set(cp[0])) { |
| 1384 | for (cp) |b| { | 1398 | for (cp) |b| { |
| 1385 | try list.appendSlice(n, &.{'%'}); | 1399 | try list.appendSlice(n, &.{'%'}); |
| 1386 | try list.print(n, "{d:0<2}", .{b}); | 1400 | try list.print(n, "{X:0<2}", .{b}); |
| 1387 | } | 1401 | } |
| 1388 | } else { | 1402 | } else { |
| 1389 | try list.appendSlice(n, &.{cp[0]}); | 1403 | try list.appendSlice(n, &.{cp[0]}); |
| ... | @@ -1395,7 +1409,7 @@ fn percentEncodeML(list: *ManyArrayList(15, u8), n: usize, input: []const u8, co | ... | @@ -1395,7 +1409,7 @@ fn percentEncodeML(list: *ManyArrayList(15, u8), n: usize, input: []const u8, co |
| 1395 | if (set(sl[0])) { | 1409 | if (set(sl[0])) { |
| 1396 | for (sl) |b| { | 1410 | for (sl) |b| { |
| 1397 | try list.appendSlice(n, &.{'%'}); | 1411 | try list.appendSlice(n, &.{'%'}); |
| 1398 | try list.print(n, "{d:0<2}", .{b}); | 1412 | try list.print(n, "{X:0<2}", .{b}); |
| 1399 | } | 1413 | } |
| 1400 | } else { | 1414 | } else { |
| 1401 | try list.appendSlice(n, sl); | 1415 | try list.appendSlice(n, sl); |