Handle URL.resolve with path traversal as part of the filename

This commit is contained in:
Karl Seguin
2026-01-27 21:45:16 +08:00
parent 451dd0fd64
commit fd21d952ac

View File

@@ -87,13 +87,14 @@ pub fn resolve(allocator: Allocator, base: [:0]const u8, path: anytype, comptime
// an allocator, which is ok, because we expect allocator to be an arena. // an allocator, which is ok, because we expect allocator to be an arena.
var in_i: usize = 0; var in_i: usize = 0;
var out_i: usize = 0; var out_i: usize = 0;
var separator = false;
while (in_i < end) { while (in_i < end) {
if (std.mem.startsWith(u8, out[in_i..], "./")) { if (separator and std.mem.startsWith(u8, out[in_i..], "./")) {
in_i += 2; in_i += 2;
continue; continue;
} }
if (std.mem.startsWith(u8, out[in_i..], "../")) { if (separator and std.mem.startsWith(u8, out[in_i..], "../")) {
lp.assert(out[out_i - 1] == '/', "URL.resolve", .{ .out = out }); lp.assert(out[out_i - 1] == '/', "URL.resolve", .{ .out = out });
if (out_i > path_marker) { if (out_i > path_marker) {
@@ -114,9 +115,11 @@ pub fn resolve(allocator: Allocator, base: [:0]const u8, path: anytype, comptime
continue; continue;
} }
out[out_i] = out[in_i]; const c = out[in_i];
out[out_i] = c;
in_i += 1; in_i += 1;
out_i += 1; out_i += 1;
separator = c == '/';
} }
// we always have an extra space // we always have an extra space
@@ -542,6 +545,11 @@ test "URL: resolve" {
}; };
const cases = [_]Case{ const cases = [_]Case{
.{
.base = "https://example/dir",
.path = "abc../test",
.expected = "https://example/abc../test",
},
.{ .{
.base = "https://example/xyz/abc/123", .base = "https://example/xyz/abc/123",
.path = "something.js", .path = "something.js",