Skip to content

Commit 0b6ebd4

Browse files
committed
add hash support to URL stitch
1 parent 421bc5a commit 0b6ebd4

File tree

4 files changed

+41
-19
lines changed

4 files changed

+41
-19
lines changed

src/browser/html/location.zig

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,17 +44,12 @@ pub const Location = struct {
4444
}
4545

4646
pub fn set_hash(_: *const Location, hash: []const u8, page: *Page) !void {
47-
const current_url = page.url.raw;
48-
49-
const base_without_hash = if (std.mem.indexOfScalar(u8, current_url, '#')) |pos|
50-
current_url[0..pos]
47+
const normalized_hash = if (hash[0] == '#')
48+
hash
5149
else
52-
current_url;
53-
54-
const normalized_hash = std.mem.trimStart(u8, hash, "#");
55-
const new_url = try std.fmt.allocPrint(page.arena, "{s}#{s}", .{ base_without_hash, normalized_hash });
50+
try std.fmt.allocPrint(page.arena, "#{s}", .{hash});
5651

57-
return page.navigateFromWebAPI(new_url, .{ .reason = .script }, .replace);
52+
return page.navigateFromWebAPI(normalized_hash, .{ .reason = .script }, .replace);
5853
}
5954

6055
pub fn get_protocol(self: *Location) []const u8 {

src/browser/navigation/Navigation.zig

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,9 @@ pub fn navigate(
228228
const committed = try page.js.createPromiseResolver(.page);
229229
const finished = try page.js.createPromiseResolver(.page);
230230

231-
const new_url = try URL.parse(url, null);
231+
const new_url_string = try URL.stitch(arena, url, page.url.raw, .{});
232+
const new_url = try URL.parse(new_url_string, null);
233+
232234
const is_same_document = try page.url.eqlDocument(&new_url, arena);
233235

234236
switch (kind) {

src/browser/page.zig

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1084,7 +1084,6 @@ pub const Page = struct {
10841084
if (try self.url.eqlDocument(&new_url, session.transfer_arena)) {
10851085
self.url = new_url;
10861086
try self.window.changeLocation(self.url.raw, self);
1087-
10881087
try session.navigation.updateEntries(stitched_url, kind, self, true);
10891088
return;
10901089
}

src/url.zig

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -81,16 +81,34 @@ pub const URL = struct {
8181
/// For URLs without a path, it will add src as the path.
8282
pub fn stitch(
8383
allocator: Allocator,
84-
path: []const u8,
85-
base: []const u8,
84+
_path: []const u8,
85+
_base: []const u8,
8686
comptime opts: StitchOpts,
8787
) !StitchReturn(opts) {
88-
if (base.len == 0 or isCompleteHTTPUrl(path)) {
89-
return simpleStitch(allocator, path, opts);
88+
if (_base.len == 0 or isCompleteHTTPUrl(_path)) {
89+
return simpleStitch(allocator, _path, opts);
9090
}
9191

92+
if (_path.len == 0) {
93+
return simpleStitch(allocator, _base, opts);
94+
}
95+
96+
// base should get stripped of its hash whenever we are stitching.
97+
const base = if (std.mem.indexOfScalar(u8, _base, '#')) |hash_pos|
98+
_base[0..hash_pos]
99+
else
100+
_base;
101+
102+
const path_hash_start = std.mem.indexOfScalar(u8, _path, '#');
103+
const path = if (path_hash_start) |pos| _path[0..pos] else _path;
104+
const hash = if (path_hash_start) |pos| _path[pos..] else "";
105+
106+
// if path is just hash, we just append it to base.
92107
if (path.len == 0) {
93-
return simpleStitch(allocator, base, opts);
108+
if (comptime opts.null_terminated) {
109+
return std.fmt.allocPrintSentinel(allocator, "{s}{s}", .{ base, hash }, 0);
110+
}
111+
return std.fmt.allocPrint(allocator, "{s}{s}", .{ base, hash });
94112
}
95113

96114
if (std.mem.startsWith(u8, path, "//")) {
@@ -101,9 +119,9 @@ pub const URL = struct {
101119

102120
const protocol = base[0..index];
103121
if (comptime opts.null_terminated) {
104-
return std.fmt.allocPrintSentinel(allocator, "{s}:{s}", .{ protocol, path }, 0);
122+
return std.fmt.allocPrintSentinel(allocator, "{s}:{s}{s}", .{ protocol, path, hash }, 0);
105123
}
106-
return std.fmt.allocPrint(allocator, "{s}:{s}", .{ protocol, path });
124+
return std.fmt.allocPrint(allocator, "{s}:{s}{s}", .{ protocol, path, hash });
107125
}
108126

109127
// Quick hack because domains have to be at least 3 characters.
@@ -133,7 +151,10 @@ pub const URL = struct {
133151

134152
// We preallocate all of the space possibly needed.
135153
// This is the root, old_path, new path, 3 slashes and perhaps a null terminated slot.
136-
var out = try allocator.alloc(u8, root.len + old_path.len + path.len + 3 + if (comptime opts.null_terminated) 1 else 0);
154+
var out = try allocator.alloc(
155+
u8,
156+
root.len + old_path.len + path.len + hash.len + 3 + if (comptime opts.null_terminated) 1 else 0,
157+
);
137158
var end: usize = 0;
138159
@memmove(out[0..root.len], root);
139160
end += root.len;
@@ -180,6 +201,11 @@ pub const URL = struct {
180201
read += 1;
181202
}
182203

204+
if (hash.len > 0) {
205+
@memmove(out[write .. write + hash.len], hash);
206+
write += hash.len;
207+
}
208+
183209
if (comptime opts.null_terminated) {
184210
// we always have an extra space
185211
out[write] = 0;

0 commit comments

Comments
 (0)