Skip to content

Commit b5eea21

Browse files
authored
Merge pull request #612 from lightpanda-io/fix-url-resolving
Fix URL Resolving
2 parents deded47 + 15be423 commit b5eea21

File tree

2 files changed

+73
-4
lines changed

2 files changed

+73
-4
lines changed

src/browser/browser.zig

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -587,11 +587,9 @@ pub const Page = struct {
587587

588588
// if a base path is given, we resolve src using base.
589589
if (base) |_base| {
590-
const dir = std.fs.path.dirname(_base);
591-
if (dir) |_dir| {
592-
res_src = try std.fs.path.resolve(arena, &.{ _dir, src });
593-
}
590+
res_src = try URL.stitch(arena, src, _base);
594591
}
592+
595593
var origin_url = &self.url;
596594
const url = try origin_url.resolve(arena, res_src);
597595

src/url.zig

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,35 @@ pub const URL = struct {
8181
pub fn toWebApi(self: *const URL, allocator: Allocator) !WebApiURL {
8282
return WebApiURL.init(allocator, self.uri);
8383
}
84+
85+
/// Properly stitches two URL fragments together.
86+
///
87+
/// For URLs with a path, it will replace the last entry with the src.
88+
/// For URLs without a path, it will add src as the path.
89+
pub fn stitch(allocator: std.mem.Allocator, src: []const u8, base: []const u8) ![]const u8 {
90+
if (base.len == 0) {
91+
return src;
92+
}
93+
94+
const protocol_end: usize = blk: {
95+
if (std.mem.indexOf(u8, base, "://")) |protocol_index| {
96+
break :blk protocol_index + 3;
97+
} else {
98+
break :blk 0;
99+
}
100+
};
101+
102+
if (std.mem.lastIndexOfScalar(u8, base[protocol_end..], '/')) |index| {
103+
const last_slash_pos = index + protocol_end;
104+
if (last_slash_pos == base.len - 1) {
105+
return std.fmt.allocPrint(allocator, "{s}{s}", .{ base, src });
106+
} else {
107+
return std.fmt.allocPrint(allocator, "{s}/{s}", .{ base[0..last_slash_pos], src });
108+
}
109+
} else {
110+
return std.fmt.allocPrint(allocator, "{s}/{s}", .{ base, src });
111+
}
112+
}
84113
};
85114

86115
test "Url resolve size" {
@@ -98,3 +127,45 @@ test "Url resolve size" {
98127
try std.testing.expectEqual(out_url.raw[25], '/');
99128
try std.testing.expectEqualStrings(out_url.raw[26..], &url_string);
100129
}
130+
131+
const testing = @import("testing.zig");
132+
133+
test "URL: Stitching Base & Src URLs (Basic)" {
134+
const allocator = testing.allocator;
135+
136+
const base = "https://www.google.com/xyz/abc/123";
137+
const src = "something.js";
138+
const result = try URL.stitch(allocator, src, base);
139+
defer allocator.free(result);
140+
try testing.expectString("https://www.google.com/xyz/abc/something.js", result);
141+
}
142+
143+
test "URL: Stitching Base & Src URLs (Just Ending Slash)" {
144+
const allocator = testing.allocator;
145+
146+
const base = "https://www.google.com/";
147+
const src = "something.js";
148+
const result = try URL.stitch(allocator, src, base);
149+
defer allocator.free(result);
150+
try testing.expectString("https://www.google.com/something.js", result);
151+
}
152+
153+
test "URL: Stitching Base & Src URLs (No Ending Slash)" {
154+
const allocator = testing.allocator;
155+
156+
const base = "https://www.google.com";
157+
const src = "something.js";
158+
const result = try URL.stitch(allocator, src, base);
159+
defer allocator.free(result);
160+
try testing.expectString("https://www.google.com/something.js", result);
161+
}
162+
163+
test "URL: Stiching Base & Src URLs (Both Local)" {
164+
const allocator = testing.allocator;
165+
166+
const base = "./abcdef/123.js";
167+
const src = "something.js";
168+
const result = try URL.stitch(allocator, src, base);
169+
defer allocator.free(result);
170+
try testing.expectString("./abcdef/something.js", result);
171+
}

0 commit comments

Comments
 (0)