Fix url constructor

url, base were being joined in the wrong order. Switch to using URL.stitch if
a base is given.
This commit is contained in:
Karl Seguin
2025-06-02 15:43:53 +08:00
parent c80deeb5ec
commit ac75f9bf57
3 changed files with 36 additions and 8 deletions

View File

@@ -145,7 +145,7 @@ pub const Page = struct {
const file_src = blk: {
if (base) |_base| {
break :blk try URL.stitch(self.arena, specifier, _base);
break :blk try URL.stitch(self.arena, specifier, _base, .{});
} else break :blk specifier;
};
@@ -451,7 +451,7 @@ pub const Page = struct {
// if a base path is given, we resolve src using base.
if (base) |_base| {
res_src = try URL.stitch(arena, src, _base);
res_src = try URL.stitch(arena, src, _base, .{});
}
var origin_url = &self.url;

View File

@@ -50,7 +50,14 @@ pub const URL = struct {
page: *Page,
) !URL {
const arena = page.arena;
const raw = try std.mem.concat(arena, u8, &[_][]const u8{ url, base orelse "" });
var raw: []const u8 = undefined;
if (base) |b| {
raw = try @import("../../url.zig").URL.stitch(arena, url, b, .{
.alloc = .always,
});
} else {
raw = try arena.dupe(u8, url);
}
const uri = std.Uri.parse(raw) catch return error.TypeError;
return init(arena, uri);
@@ -276,4 +283,9 @@ test "Browser.URL" {
.{ "url.searchParams.delete('a')", "undefined" },
.{ "url.searchParams.get('a')", "" },
}, .{});
try runner.testCases(&.{
.{ "var url = new URL('over?9000', 'https://lightpanda.io')", null },
.{ "url.href", "https://lightpanda.io/over?9000" },
}, .{});
}

View File

@@ -83,12 +83,28 @@ pub const URL = struct {
return WebApiURL.init(allocator, self.uri);
}
const StitchOpts = struct {
alloc: AllocWhen = .if_needed,
const AllocWhen = enum {
always,
if_needed,
};
};
/// Properly stitches two URL fragments together.
///
/// For URLs with a path, it will replace the last entry with the src.
/// For URLs without a path, it will add src as the path.
pub fn stitch(allocator: Allocator, src: []const u8, base: []const u8) ![]const u8 {
pub fn stitch(
allocator: Allocator,
src: []const u8,
base: []const u8,
opts: StitchOpts,
) ![]const u8 {
if (base.len == 0) {
if (opts.alloc == .always) {
return allocator.dupe(u8, src);
}
return src;
}
@@ -161,7 +177,7 @@ test "URL: Stitching Base & Src URLs (Basic)" {
const base = "https://www.google.com/xyz/abc/123";
const src = "something.js";
const result = try URL.stitch(allocator, src, base);
const result = try URL.stitch(allocator, src, base, .{});
defer allocator.free(result);
try testing.expectString("https://www.google.com/xyz/abc/something.js", result);
}
@@ -171,7 +187,7 @@ test "URL: Stitching Base & Src URLs (Just Ending Slash)" {
const base = "https://www.google.com/";
const src = "something.js";
const result = try URL.stitch(allocator, src, base);
const result = try URL.stitch(allocator, src, base, .{});
defer allocator.free(result);
try testing.expectString("https://www.google.com/something.js", result);
}
@@ -181,7 +197,7 @@ test "URL: Stitching Base & Src URLs (No Ending Slash)" {
const base = "https://www.google.com";
const src = "something.js";
const result = try URL.stitch(allocator, src, base);
const result = try URL.stitch(allocator, src, base, .{});
defer allocator.free(result);
try testing.expectString("https://www.google.com/something.js", result);
}
@@ -191,7 +207,7 @@ test "URL: Stiching Base & Src URLs (Both Local)" {
const base = "./abcdef/123.js";
const src = "something.js";
const result = try URL.stitch(allocator, src, base);
const result = try URL.stitch(allocator, src, base, .{});
defer allocator.free(result);
try testing.expectString("./abcdef/something.js", result);
}