| ... | @@ -7,6 +7,7 @@ const unicode_idna = @import("unicode-idna"); | ... | @@ -7,6 +7,7 @@ const unicode_idna = @import("unicode-idna"); |
| 7 | pub const URL = struct { | 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 | | 11 | |
| 11 | pub const HostKind = enum { | 12 | pub const HostKind = enum { |
| 12 | name, | 13 | name, |
| ... | @@ -75,23 +76,27 @@ pub const URL = struct { | ... | @@ -75,23 +76,27 @@ pub const URL = struct { |
| 75 | // inputl[i], must change in tandem with i | 76 | // inputl[i], must change in tandem with i |
| 76 | var c: u8 = if (length > 0) inputl.items[i] else 0; | 77 | var c: u8 = if (length > 0) inputl.items[i] else 0; |
| 77 | | 78 | |
| 78 | var href = std.ArrayList(u8).init(alloc); | 79 | var href = ManyArrayList(8 + 7, u8).init(alloc); |
| 79 | defer href.deinit(); | 80 | defer href.deinit(); |
| 80 | | 81 | // : |
| 81 | var scheme = std.ArrayList(u8).init(alloc); | 82 | // // |
| 82 | defer scheme.deinit(); | | |
| 83 | var username = std.ArrayList(u8).init(alloc); | 83 | var username = std.ArrayList(u8).init(alloc); |
| 84 | defer username.deinit(); | 84 | defer username.deinit(); |
| | 85 | // : |
| 85 | var password = std.ArrayList(u8).init(alloc); | 86 | var password = std.ArrayList(u8).init(alloc); |
| 86 | defer password.deinit(); | 87 | defer password.deinit(); |
| | 88 | // @ |
| 87 | var host: Host = .{ .name = "" }; | 89 | var host: Host = .{ .name = "" }; |
| 88 | defer if (host == .name) alloc.free(host.name); | 90 | defer if (host == .name) alloc.free(host.name); |
| | 91 | // : |
| 89 | var port = std.ArrayList(u8).init(alloc); | 92 | var port = std.ArrayList(u8).init(alloc); |
| 90 | defer port.deinit(); | 93 | defer port.deinit(); |
| 91 | var path = std.ArrayList(u8).init(alloc); | 94 | var path = std.ArrayList(u8).init(alloc); |
| 92 | defer path.deinit(); | 95 | defer path.deinit(); |
| | 96 | // ? |
| 93 | var query = std.ArrayList(u8).init(alloc); | 97 | var query = std.ArrayList(u8).init(alloc); |
| 94 | defer query.deinit(); | 98 | defer query.deinit(); |
| | 99 | // # |
| 95 | var fragment = std.ArrayList(u8).init(alloc); | 100 | var fragment = std.ArrayList(u8).init(alloc); |
| 96 | defer fragment.deinit(); | 101 | defer fragment.deinit(); |
| 97 | | 102 | |
| ... | @@ -122,6 +127,7 @@ pub const URL = struct { | ... | @@ -122,6 +127,7 @@ pub const URL = struct { |
| 122 | } | 127 | } |
| 123 | // 2. Otherwise, if c is U+003A (:), then: | 128 | // 2. Otherwise, if c is U+003A (:), then: |
| 124 | else if (c == ':') { | 129 | else if (c == ':') { |
| | 130 | try href.set(1, ":"); |
| 125 | // 1. If state override is given, then: | 131 | // 1. If state override is given, then: |
| 126 | if (state_override != null) { | 132 | if (state_override != null) { |
| 127 | @panic("TODO"); | 133 | @panic("TODO"); |
| ... | @@ -131,8 +137,7 @@ pub const URL = struct { | ... | @@ -131,8 +137,7 @@ pub const URL = struct { |
| 131 | // 4. If url’s scheme is "file" and its host is an empty host, then return. | 137 | // 4. If url’s scheme is "file" and its host is an empty host, then return. |
| 132 | } | 138 | } |
| 133 | // 2. Set url’s scheme to buffer. | 139 | // 2. Set url’s scheme to buffer. |
| 134 | scheme.clearRetainingCapacity(); | 140 | try href.set(0, buffer.items); |
| 135 | try scheme.appendSlice(buffer.items); | | |
| 136 | // 3. If state override is given, then: | 141 | // 3. If state override is given, then: |
| 137 | if (state_override != null) { | 142 | if (state_override != null) { |
| 138 | @panic("TODO"); | 143 | @panic("TODO"); |
| ... | @@ -142,20 +147,20 @@ pub const URL = struct { | ... | @@ -142,20 +147,20 @@ pub const URL = struct { |
| 142 | // 4. Set buffer to the empty string. | 147 | // 4. Set buffer to the empty string. |
| 143 | buffer.clearRetainingCapacity(); | 148 | buffer.clearRetainingCapacity(); |
| 144 | // 5. If url’s scheme is "file", then: | 149 | // 5. If url’s scheme is "file", then: |
| 145 | if (std.mem.eql(u8, scheme.items, "file")) { | 150 | if (std.mem.eql(u8, href.items(0), "file")) { |
| 146 | // 1. If remaining does not start with "//", special-scheme-missing-following-solidus validation error. | 151 | // 1. If remaining does not start with "//", special-scheme-missing-following-solidus validation error. |
| 147 | {} | 152 | {} |
| 148 | // 2. Set state to file state. | 153 | // 2. Set state to file state. |
| 149 | state = .file; | 154 | state = .file; |
| 150 | } | 155 | } |
| 151 | // 6. Otherwise, if url is special, base is non-null, and base’s scheme is url’s scheme: | 156 | // 6. Otherwise, if url is special, base is non-null, and base’s scheme is url’s scheme: |
| 152 | else if (isSchemeSpecial(scheme.items) and base != null and std.mem.eql(u8, base.?.scheme, scheme.items)) { | 157 | else if (isSchemeSpecial(href.items(0)) and base != null and std.mem.eql(u8, base.?.scheme, href.items(0))) { |
| 153 | @panic("TODO"); | 158 | @panic("TODO"); |
| 154 | // 1. Assert: base is special (and therefore does not have an opaque path). | 159 | // 1. Assert: base is special (and therefore does not have an opaque path). |
| 155 | // 2. Set state to special relative or authority state. | 160 | // 2. Set state to special relative or authority state. |
| 156 | } | 161 | } |
| 157 | // 7. Otherwise, if url is special, set state to special authority slashes state. | 162 | // 7. Otherwise, if url is special, set state to special authority slashes state. |
| 158 | else if (isSchemeSpecial(scheme.items)) { | 163 | else if (isSchemeSpecial(href.items(0))) { |
| 159 | state = .special_authority_slashes; | 164 | state = .special_authority_slashes; |
| 160 | } | 165 | } |
| 161 | // 8. Otherwise, if remaining starts with an U+002F (/), set state to path or authority state and increase pointer by 1. | 166 | // 8. Otherwise, if remaining starts with an U+002F (/), set state to path or authority state and increase pointer by 1. |
| ... | @@ -223,13 +228,13 @@ pub const URL = struct { | ... | @@ -223,13 +228,13 @@ pub const URL = struct { |
| 223 | // 1. Assert: base’s scheme is not "file". | 228 | // 1. Assert: base’s scheme is not "file". |
| 224 | std.debug.assert(!std.mem.eql(u8, base.?.scheme, "file")); | 229 | std.debug.assert(!std.mem.eql(u8, base.?.scheme, "file")); |
| 225 | // 2. Set url’s scheme to base’s scheme. | 230 | // 2. Set url’s scheme to base’s scheme. |
| 226 | try scheme.appendSlice(base.?.scheme); | 231 | try href.set(0, base.?.scheme); |
| 227 | // 3. If c is U+002F (/), then set state to relative slash state. | 232 | // 3. If c is U+002F (/), then set state to relative slash state. |
| 228 | if (c == '/') { | 233 | if (c == '/') { |
| 229 | state = .relative_slash; | 234 | state = .relative_slash; |
| 230 | } | 235 | } |
| 231 | // 4. Otherwise, if url is special and c is U+005C (\), invalid-reverse-solidus validation error, set state to relative slash state. | 236 | // 4. Otherwise, if url is special and c is U+005C (\), invalid-reverse-solidus validation error, set state to relative slash state. |
| 232 | else if (isSchemeSpecial(scheme.items) and c == '\\') { | 237 | else if (isSchemeSpecial(href.items(0)) and c == '\\') { |
| 233 | state = .relative_slash; | 238 | state = .relative_slash; |
| 234 | } | 239 | } |
| 235 | // 5. Otherwise: | 240 | // 5. Otherwise: |
| ... | @@ -267,7 +272,7 @@ pub const URL = struct { | ... | @@ -267,7 +272,7 @@ pub const URL = struct { |
| 267 | }, | 272 | }, |
| 268 | .relative_slash => { | 273 | .relative_slash => { |
| 269 | // 1. If url is special and c is U+002F (/) or U+005C (\), then: | 274 | // 1. If url is special and c is U+002F (/) or U+005C (\), then: |
| 270 | if (isSchemeSpecial(scheme.items) and (c == '/' or c == '\\')) { | 275 | if (isSchemeSpecial(href.items(0)) and (c == '/' or c == '\\')) { |
| 271 | // 1. If c is U+005C (\), invalid-reverse-solidus validation error. | 276 | // 1. If c is U+005C (\), invalid-reverse-solidus validation error. |
| 272 | // 2. Set state to special authority ignore slashes state. | 277 | // 2. Set state to special authority ignore slashes state. |
| 273 | state = .special_authority_ignore_slashes; | 278 | state = .special_authority_ignore_slashes; |
| ... | @@ -340,7 +345,7 @@ pub const URL = struct { | ... | @@ -340,7 +345,7 @@ pub const URL = struct { |
| 340 | // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#) | 345 | // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#) |
| 341 | // - url is special and c is U+005C (\) | 346 | // - url is special and c is U+005C (\) |
| 342 | // then: | 347 | // then: |
| 343 | else if ((i == length or c == '/' or c == '?' or c == '#') or (isSchemeSpecial(scheme.items) and c == '\\')) { | 348 | else if ((i == length or c == '/' or c == '?' or c == '#') or (isSchemeSpecial(href.items(0)) and c == '\\')) { |
| 344 | // 1. If atSignSeen is true and buffer is the empty string, host-missing validation error, return failure. | 349 | // 1. If atSignSeen is true and buffer is the empty string, host-missing validation error, return failure. |
| 345 | if (atSignSeen and buffer.items.len == 0) return error.InvalidURL; | 350 | if (atSignSeen and buffer.items.len == 0) return error.InvalidURL; |
| 346 | // 2. Decrease pointer by buffer’s code point length + 1, set buffer to the empty string, and set state to host state. | 351 | // 2. Decrease pointer by buffer’s code point length + 1, set buffer to the empty string, and set state to host state. |
| ... | @@ -359,7 +364,7 @@ pub const URL = struct { | ... | @@ -359,7 +364,7 @@ pub const URL = struct { |
| 359 | }, | 364 | }, |
| 360 | .host, .hostname => { | 365 | .host, .hostname => { |
| 361 | // 1. If state override is given and url’s scheme is "file", then decrease pointer by 1 and set state to file host state. | 366 | // 1. If state override is given and url’s scheme is "file", then decrease pointer by 1 and set state to file host state. |
| 362 | if (state_override != null and std.mem.eql(u8, scheme.items, "file")) { | 367 | if (state_override != null and std.mem.eql(u8, href.items(0), "file")) { |
| 363 | pointer -= 1; | 368 | pointer -= 1; |
| 364 | i = lastcpi(inputl.items[0..i]); | 369 | i = lastcpi(inputl.items[0..i]); |
| 365 | c = inputl.items[i]; | 370 | c = inputl.items[i]; |
| ... | @@ -373,7 +378,7 @@ pub const URL = struct { | ... | @@ -373,7 +378,7 @@ pub const URL = struct { |
| 373 | if (state_override != null and state_override.? == .hostname) return error.InvalidURL; | 378 | if (state_override != null and state_override.? == .hostname) return error.InvalidURL; |
| 374 | // 3. Let host be the result of host parsing buffer with url is not special. | 379 | // 3. Let host be the result of host parsing buffer with url is not special. |
| 375 | // 4. If host is failure, then return failure. | 380 | // 4. If host is failure, then return failure. |
| 376 | const h = try parseHost(alloc, buffer.items, !isSchemeSpecial(scheme.items)); | 381 | const h = try parseHost(alloc, buffer.items, !isSchemeSpecial(href.items(0))); |
| 377 | // 5. Set url’s host to host, buffer to the empty string, and state to port state. | 382 | // 5. Set url’s host to host, buffer to the empty string, and state to port state. |
| 378 | host = h; | 383 | host = h; |
| 379 | buffer.clearRetainingCapacity(); | 384 | buffer.clearRetainingCapacity(); |
| ... | @@ -383,17 +388,17 @@ pub const URL = struct { | ... | @@ -383,17 +388,17 @@ pub const URL = struct { |
| 383 | // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#) | 388 | // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#) |
| 384 | // - url is special and c is U+005C (\) | 389 | // - url is special and c is U+005C (\) |
| 385 | // then decrease pointer by 1, and: | 390 | // then decrease pointer by 1, and: |
| 386 | else if ((i == length or c == '/' or c == '?' or c == '#') or (isSchemeSpecial(scheme.items) and c == '\\')) { | 391 | else if ((i == length or c == '/' or c == '?' or c == '#') or (isSchemeSpecial(href.items(0)) and c == '\\')) { |
| 387 | pointer -= 1; | 392 | pointer -= 1; |
| 388 | i = lastcpi(inputl.items[0..i]); | 393 | i = lastcpi(inputl.items[0..i]); |
| 389 | c = inputl.items[i]; | 394 | c = inputl.items[i]; |
| 390 | // 1. If url is special and buffer is the empty string, host-missing validation error, return failure. | 395 | // 1. If url is special and buffer is the empty string, host-missing validation error, return failure. |
| 391 | if (isSchemeSpecial(scheme.items) and buffer.items.len == 0) return error.InvalidURL | 396 | if (isSchemeSpecial(href.items(0)) and buffer.items.len == 0) return error.InvalidURL |
| 392 | // 2. Otherwise, if state override is given, buffer is the empty string, and either url includes credentials or url’s port is non-null, then return failure. | 397 | // 2. Otherwise, if state override is given, buffer is the empty string, and either url includes credentials or url’s port is non-null, then return failure. |
| 393 | else if (state_override != null and buffer.items.len == 0 and (username.items.len > 0 or password.items.len > 0)) return error.InvalidURL; | 398 | else if (state_override != null and buffer.items.len == 0 and (username.items.len > 0 or password.items.len > 0)) return error.InvalidURL; |
| 394 | // 3. Let host be the result of host parsing buffer with url is not special. | 399 | // 3. Let host be the result of host parsing buffer with url is not special. |
| 395 | // 4. If host is failure, then return failure. | 400 | // 4. If host is failure, then return failure. |
| 396 | const h = try parseHost(alloc, buffer.items, !isSchemeSpecial(scheme.items)); | 401 | const h = try parseHost(alloc, buffer.items, !isSchemeSpecial(href.items(0))); |
| 397 | // 5. Set url’s host to host, buffer to the empty string, and state to path start state. | 402 | // 5. Set url’s host to host, buffer to the empty string, and state to path start state. |
| 398 | host = h; | 403 | host = h; |
| 399 | buffer.clearRetainingCapacity(); | 404 | buffer.clearRetainingCapacity(); |
| ... | @@ -421,14 +426,14 @@ pub const URL = struct { | ... | @@ -421,14 +426,14 @@ pub const URL = struct { |
| 421 | // - url is special and c is U+005C (\); or | 426 | // - url is special and c is U+005C (\); or |
| 422 | // - state override is given, | 427 | // - state override is given, |
| 423 | // then: | 428 | // then: |
| 424 | else if ((i == length or c == '/' or c == '?' or c == '#') or (isSchemeSpecial(scheme.items) and c == '\\') or (state_override != null)) { | 429 | else if ((i == length or c == '/' or c == '?' or c == '#') or (isSchemeSpecial(href.items(0)) and c == '\\') or (state_override != null)) { |
| 425 | // 1. If buffer is not the empty string: | 430 | // 1. If buffer is not the empty string: |
| 426 | if (buffer.items.len > 0) { | 431 | if (buffer.items.len > 0) { |
| 427 | // 1. Let port be the mathematical integer value that is represented by buffer in radix-10 using ASCII digits for digits with values 0 through 9. | 432 | // 1. Let port be the mathematical integer value that is represented by buffer in radix-10 using ASCII digits for digits with values 0 through 9. |
| 428 | // 2. If port is not a 16-bit unsigned integer, port-out-of-range validation error, return failure. | 433 | // 2. If port is not a 16-bit unsigned integer, port-out-of-range validation error, return failure. |
| 429 | const p = std.fmt.parseInt(u16, buffer.items, 10) catch return error.InvalidURL; | 434 | const p = std.fmt.parseInt(u16, buffer.items, 10) catch return error.InvalidURL; |
| 430 | // 3. Set url’s port to null, if port is url’s scheme’s default port; otherwise to port. | 435 | // 3. Set url’s port to null, if port is url’s scheme’s default port; otherwise to port. |
| 431 | if (schemeDefaultPort(scheme.items) != p) try port.writer().print("{d}", .{p}); | 436 | if (schemeDefaultPort(href.items(0)) != p) try port.writer().print("{d}", .{p}); |
| 432 | // 4. Set buffer to the empty string. | 437 | // 4. Set buffer to the empty string. |
| 433 | buffer.clearRetainingCapacity(); | 438 | buffer.clearRetainingCapacity(); |
| 434 | // 5. If state override is given, then return. | 439 | // 5. If state override is given, then return. |
| ... | @@ -449,8 +454,7 @@ pub const URL = struct { | ... | @@ -449,8 +454,7 @@ pub const URL = struct { |
| 449 | }, | 454 | }, |
| 450 | .file => { | 455 | .file => { |
| 451 | // 1. Set url’s scheme to "file". | 456 | // 1. Set url’s scheme to "file". |
| 452 | scheme.clearRetainingCapacity(); | 457 | try href.set(0, "file"); |
| 453 | try scheme.appendSlice("file"); | | |
| 454 | // 2. Set url’s host to the empty string. | 458 | // 2. Set url’s host to the empty string. |
| 455 | host = .{ .name = "" }; | 459 | host = .{ .name = "" }; |
| 456 | // 3. If c is U+002F (/) or U+005C (\), then: | 460 | // 3. If c is U+002F (/) or U+005C (\), then: |
| ... | @@ -552,7 +556,7 @@ pub const URL = struct { | ... | @@ -552,7 +556,7 @@ pub const URL = struct { |
| 552 | else { | 556 | else { |
| 553 | // 1. Let host be the result of host parsing buffer with url is not special. | 557 | // 1. Let host be the result of host parsing buffer with url is not special. |
| 554 | // 2. If host is failure, then return failure. | 558 | // 2. If host is failure, then return failure. |
| 555 | var h = try parseHost(alloc, buffer.items, !isSchemeSpecial(scheme.items)); | 559 | var h = try parseHost(alloc, buffer.items, !isSchemeSpecial(href.items(0))); |
| 556 | // 3. If host is "localhost", then set host to the empty string. | 560 | // 3. If host is "localhost", then set host to the empty string. |
| 557 | if (h == .name and std.mem.eql(u8, h.name, "localhost")) { | 561 | if (h == .name and std.mem.eql(u8, h.name, "localhost")) { |
| 558 | alloc.free(h.name); | 562 | alloc.free(h.name); |
| ... | @@ -572,7 +576,7 @@ pub const URL = struct { | ... | @@ -572,7 +576,7 @@ pub const URL = struct { |
| 572 | }, | 576 | }, |
| 573 | .path_start => { | 577 | .path_start => { |
| 574 | // 1. If url is special, then: | 578 | // 1. If url is special, then: |
| 575 | if (isSchemeSpecial(scheme.items)) { | 579 | if (isSchemeSpecial(href.items(0))) { |
| 576 | // 1. If c is U+005C (\), invalid-reverse-solidus validation error. | 580 | // 1. If c is U+005C (\), invalid-reverse-solidus validation error. |
| 577 | {} | 581 | {} |
| 578 | // 2. Set state to path state. | 582 | // 2. Set state to path state. |
| ... | @@ -616,7 +620,7 @@ pub const URL = struct { | ... | @@ -616,7 +620,7 @@ pub const URL = struct { |
| 616 | // - url is special and c is U+005C (\) | 620 | // - url is special and c is U+005C (\) |
| 617 | // - state override is not given and c is U+003F (?) or U+0023 (#) | 621 | // - state override is not given and c is U+003F (?) or U+0023 (#) |
| 618 | // then: | 622 | // then: |
| 619 | if ((i == length or c == '/') or (isSchemeSpecial(scheme.items) and c == '\\') or (state_override == null and (c == '?' or c == '#'))) { | 623 | if ((i == length or c == '/') or (isSchemeSpecial(href.items(0)) and c == '\\') or (state_override == null and (c == '?' or c == '#'))) { |
| 620 | // 1. If url is special and c is U+005C (\), invalid-reverse-solidus validation error. | 624 | // 1. If url is special and c is U+005C (\), invalid-reverse-solidus validation error. |
| 621 | {} | 625 | {} |
| 622 | // 2. If buffer is a double-dot URL path segment, then: | 626 | // 2. If buffer is a double-dot URL path segment, then: |
| ... | @@ -627,14 +631,14 @@ pub const URL = struct { | ... | @@ -627,14 +631,14 @@ pub const URL = struct { |
| 627 | // > This means that for input /usr/.. the result is / and not a lack of a path. | 631 | // > This means that for input /usr/.. the result is / and not a lack of a path. |
| 628 | } | 632 | } |
| 629 | // 3. Otherwise, if buffer is a single-dot URL path segment and if neither c is U+002F (/), nor url is special and c is U+005C (\), append the empty string to url’s path. | 633 | // 3. Otherwise, if buffer is a single-dot URL path segment and if neither c is U+002F (/), nor url is special and c is U+005C (\), append the empty string to url’s path. |
| 630 | else if (isSingleDotPathSeg(buffer.items) and (c != '/' or !(isSchemeSpecial(scheme.items) and c == '\\'))) { | 634 | else if (isSingleDotPathSeg(buffer.items) and (c != '/' or !(isSchemeSpecial(href.items(0)) and c == '\\'))) { |
| 631 | // @panic("TODO"); | 635 | // @panic("TODO"); |
| 632 | } | 636 | } |
| 633 | // 4. Otherwise, if buffer is not a single-dot URL path segment, then: | 637 | // 4. Otherwise, if buffer is not a single-dot URL path segment, then: |
| 634 | else if (!isSingleDotPathSeg(buffer.items)) { | 638 | else if (!isSingleDotPathSeg(buffer.items)) { |
| 635 | // 1. If url’s scheme is "file", url’s path is empty, and buffer is a Windows drive letter, then replace the second code point in buffer with U+003A (:). | 639 | // 1. If url’s scheme is "file", url’s path is empty, and buffer is a Windows drive letter, then replace the second code point in buffer with U+003A (:). |
| 636 | // > This is a (platform-independent) Windows drive letter quirk. | 640 | // > This is a (platform-independent) Windows drive letter quirk. |
| 637 | if (std.mem.eql(u8, scheme.items, "file") and path.items.len == 0 and isWindowsDriveLetter(buffer.items)) { | 641 | if (std.mem.eql(u8, href.items(0), "file") and path.items.len == 0 and isWindowsDriveLetter(buffer.items)) { |
| 638 | buffer.items[1] = ':'; | 642 | buffer.items[1] = ':'; |
| 639 | } | 643 | } |
| 640 | // 2. Append buffer to url’s path. | 644 | // 2. Append buffer to url’s path. |
| ... | @@ -715,7 +719,7 @@ pub const URL = struct { | ... | @@ -715,7 +719,7 @@ pub const URL = struct { |
| 715 | // 1. Let queryPercentEncodeSet be the special-query percent-encode set if url is special; otherwise the query percent-encode set. | 719 | // 1. Let queryPercentEncodeSet be the special-query percent-encode set if url is special; otherwise the query percent-encode set. |
| 716 | // 2. Percent-encode after encoding, with encoding, buffer, and queryPercentEncodeSet, and append the result to url’s query. | 720 | // 2. Percent-encode after encoding, with encoding, buffer, and queryPercentEncodeSet, and append the result to url’s query. |
| 717 | // > This operation cannot be invoked code-point-for-code-point due to the stateful ISO-2022-JP encoder. | 721 | // > This operation cannot be invoked code-point-for-code-point due to the stateful ISO-2022-JP encoder. |
| 718 | if (isSchemeSpecial(scheme.items)) { | 722 | if (isSchemeSpecial(href.items(0))) { |
| 719 | try percentEncodeAL(&query, buffer.items, is_special_query_percent_char); | 723 | try percentEncodeAL(&query, buffer.items, is_special_query_percent_char); |
| 720 | } else { | 724 | } else { |
| 721 | try percentEncodeAL(&query, buffer.items, is_query_percent_char); | 725 | try percentEncodeAL(&query, buffer.items, is_query_percent_char); |
| ... | @@ -762,10 +766,11 @@ pub const URL = struct { | ... | @@ -762,10 +766,11 @@ pub const URL = struct { |
| 762 | } | 766 | } |
| 763 | } | 767 | } |
| 764 | | 768 | |
| 765 | const _href = try href.toOwnedSlice(); | 769 | const _href = try href.list.toOwnedSlice(); |
| 766 | | 770 | |
| 767 | const url: URL = .{ | 771 | const url: URL = .{ |
| 768 | .href = _href, | 772 | .href = _href, |
| | 773 | .protocol = _href[0..extras.sum(usize, href.lengths[0..2])], |
| 769 | }; | 774 | }; |
| 770 | return url; | 775 | return url; |
| 771 | } | 776 | } |
| ... | @@ -1376,3 +1381,33 @@ fn percentEncodeAL(list: *std.ArrayList(u8), input: []const u8, comptime set: fn | ... | @@ -1376,3 +1381,33 @@ fn percentEncodeAL(list: *std.ArrayList(u8), input: []const u8, comptime set: fn |
| 1376 | } | 1381 | } |
| 1377 | } | 1382 | } |
| 1378 | } | 1383 | } |
| | 1384 | |
| | 1385 | pub fn ManyArrayList(N: usize, T: type) type { |
| | 1386 | return struct { |
| | 1387 | list: std.ArrayList(T), |
| | 1388 | lengths: [N]usize, |
| | 1389 | |
| | 1390 | pub fn init(allocator: std.mem.Allocator) @This() { |
| | 1391 | return .{ |
| | 1392 | .list = .init(allocator), |
| | 1393 | .lengths = @splat(0), |
| | 1394 | }; |
| | 1395 | } |
| | 1396 | |
| | 1397 | pub fn deinit(self: *@This()) void { |
| | 1398 | self.list.deinit(); |
| | 1399 | } |
| | 1400 | |
| | 1401 | pub fn set(self: *@This(), n: usize, slice: []const T) !void { |
| | 1402 | const real_n = extras.sum(usize, self.lengths[0..n]); |
| | 1403 | try self.list.replaceRange(real_n, self.lengths[n], slice); |
| | 1404 | self.lengths[n] = slice.len; |
| | 1405 | } |
| | 1406 | |
| | 1407 | pub fn items(self: *@This(), n: usize) []T { |
| | 1408 | const real_n = extras.sum(usize, self.lengths[0..n]); |
| | 1409 | const len = self.lengths[n]; |
| | 1410 | return self.list.items[real_n..][0..len]; |
| | 1411 | } |
| | 1412 | }; |
| | 1413 | } |