Skip to content

Commit daa51eb

Browse files
committed
Support base64 encoded scripts
Related to #412
1 parent 76783d9 commit daa51eb

File tree

2 files changed

+88
-0
lines changed

2 files changed

+88
-0
lines changed

src/browser/browser.zig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ const ArenaAllocator = std.heap.ArenaAllocator;
2424

2525
const Dump = @import("dump.zig");
2626
const Mime = @import("mime.zig").Mime;
27+
const DataURI = @import("datauri.zig").DataURI;
2728
const parser = @import("netsurf.zig");
2829

2930
const Window = @import("html/window.zig").Window;
@@ -581,10 +582,18 @@ pub const Page = struct {
581582
// It resolves src using the page's uri.
582583
// If a base path is given, src is resolved according to the base first.
583584
// the caller owns the returned string
585+
// TODO: We are leaking the memory associated with the response.
584586
fn fetchData(self: *const Page, src: []const u8, base: ?[]const u8) ![]const u8 {
585587
log.debug("starting fetch {s}", .{src});
586588

587589
const arena = self.arena;
590+
591+
// Handle data URIs.
592+
const data_uri: ?DataURI = DataURI.parse(arena, src) catch null;
593+
if (data_uri) |v| {
594+
return v.data;
595+
}
596+
588597
var res_src = src;
589598

590599
// if a base path is given, we resolve src using base.

src/browser/datauri.zig

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
const std = @import("std");
2+
const Allocator = std.mem.Allocator;
3+
4+
// Represents https://developer.mozilla.org/en-US/docs/Web/URI/Reference/Schemes/data
5+
pub const DataURI = struct {
6+
was_base64_encoded: bool,
7+
// The contents in the uri. It will be base64 decoded but not prepared in
8+
// any way for mime.charset.
9+
data: []const u8,
10+
11+
// Parses data:[<media-type>][;base64],<data>
12+
pub fn parse(allocator: Allocator, src: []const u8) !DataURI {
13+
if (!std.mem.startsWith(u8, src, "data:")) {
14+
return error.Invalid;
15+
}
16+
17+
const uri = src[5..];
18+
const data_starts = std.mem.indexOf(u8, uri, ",") orelse return error.Invalid;
19+
20+
// Extract the encoding.
21+
var metadata = uri[0..data_starts];
22+
var base64_encoded = false;
23+
if (std.mem.endsWith(u8, metadata, ";base64")) {
24+
base64_encoded = true;
25+
metadata = metadata[0 .. metadata.len - 7];
26+
}
27+
28+
// TODO: Extract mime type. This not trivial because Mime.parse requires
29+
// a []u8 and might mutate the src. And, the DataURI.parse references atm
30+
// do not have deinit calls.
31+
32+
// Prepare the data.
33+
var data = uri[data_starts + 1 ..];
34+
if (base64_encoded) {
35+
const decoder = std.base64.standard.Decoder;
36+
const decoded_size = try decoder.calcSizeForSlice(data);
37+
38+
const buffer = try allocator.alloc(u8, decoded_size);
39+
errdefer allocator.free(buffer);
40+
41+
try decoder.decode(buffer, data);
42+
data = buffer;
43+
}
44+
45+
return .{
46+
.was_base64_encoded = base64_encoded,
47+
.data = data,
48+
};
49+
}
50+
51+
pub fn deinit(self: *const DataURI, allocator: Allocator) void {
52+
if (self.was_base64_encoded) {
53+
allocator.free(self.data);
54+
}
55+
}
56+
};
57+
58+
const testing = std.testing;
59+
test "DataURI: parse valid" {
60+
try test_valid("data:text/javascript; charset=utf-8;base64,Zm9v", "foo");
61+
try test_valid("data:text/javascript; charset=utf-8;,foo", "foo");
62+
try test_valid("data:,foo", "foo");
63+
}
64+
65+
test "DataURI: parse invalid" {
66+
try test_invalid("atad:,foo", error.Invalid);
67+
try test_invalid("data:foo", error.Invalid);
68+
try test_invalid("data:", error.Invalid);
69+
}
70+
71+
fn test_valid(uri: []const u8, expected: []const u8) !void {
72+
const data_uri = try DataURI.parse(std.testing.allocator, uri);
73+
defer data_uri.deinit(testing.allocator);
74+
try testing.expectEqualStrings(expected, data_uri.data);
75+
}
76+
77+
fn test_invalid(uri: []const u8, err: anyerror) !void {
78+
try testing.expectError(err, DataURI.parse(std.testing.allocator, uri));
79+
}

0 commit comments

Comments
 (0)