Skip to content

Commit d2515df

Browse files
committed
replace zig-async-io and std.http.Client with a custom HTTP client
1 parent c418198 commit d2515df

File tree

13 files changed

+1291
-1881
lines changed

13 files changed

+1291
-1881
lines changed

.gitmodules

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,3 @@
2323
[submodule "vendor/mimalloc"]
2424
path = vendor/mimalloc
2525
url = https://github.com/microsoft/mimalloc.git/
26-
[submodule "vendor/tls.zig"]
27-
path = vendor/tls.zig
28-
url = https://github.com/ianic/tls.zig.git/
29-
[submodule "vendor/zig-async-io"]
30-
path = vendor/zig-async-io
31-
url = https://github.com/lightpanda-io/zig-async-io.git/
32-
branch = zig-0.14

build.zig

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,9 @@ fn common(
177177
options: jsruntime.Options,
178178
) !void {
179179
const target = step.root_module.resolved_target.?;
180+
const optimize = step.root_module.optimize.?;
181+
const dep_opts = .{ .target = target, .optimize = optimize };
182+
180183
const jsruntimemod = try jsruntime_pkgs.module(
181184
b,
182185
options,
@@ -189,15 +192,7 @@ fn common(
189192
netsurf.addImport("jsruntime", jsruntimemod);
190193
step.root_module.addImport("netsurf", netsurf);
191194

192-
const asyncio = b.addModule("asyncio", .{
193-
.root_source_file = b.path("vendor/zig-async-io/src/lib.zig"),
194-
});
195-
step.root_module.addImport("asyncio", asyncio);
196-
197-
const tlsmod = b.addModule("tls", .{
198-
.root_source_file = b.path("vendor/tls.zig/src/root.zig"),
199-
});
200-
step.root_module.addImport("tls", tlsmod);
195+
step.root_module.addImport("tls", b.dependency("tls", dep_opts).module("tls"));
201196
}
202197

203198
fn moduleNetSurf(b: *std.Build, target: std.Build.ResolvedTarget) !*std.Build.Module {

build.zig.zon

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
.{
2+
.name = .browser,
3+
.paths = .{""},
4+
.version = "0.0.0",
5+
.fingerprint = 0xda130f3af836cea0,
6+
.dependencies = .{
7+
.tls = .{
8+
.url = "https://github.com/karlseguin/tls.zig/archive/e39d40150f10464992da11352fb3955b3345272f.tar.gz",
9+
.hash = "122039cd3abe387b69d23930bf12154c2c84fc894874e10129a1fc5e8ac75ca0ddc0"
10+
},
11+
},
12+
}

src/browser/browser.zig

Lines changed: 36 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ const Allocator = std.mem.Allocator;
2424
const Types = @import("root").Types;
2525

2626
const parser = @import("netsurf");
27-
const Loader = @import("loader.zig").Loader;
2827
const Dump = @import("dump.zig");
2928
const Mime = @import("mime.zig").Mime;
3029

@@ -45,8 +44,8 @@ const storage = @import("../storage/storage.zig");
4544

4645
const FetchResult = @import("../http/Client.zig").Client.FetchResult;
4746

47+
const http = @import("../http/client.zig");
4848
const UserContext = @import("../user_context.zig").UserContext;
49-
const HttpClient = @import("asyncio").Client;
5049

5150
const polyfill = @import("../polyfill/polyfill.zig");
5251

@@ -117,9 +116,6 @@ pub const Session = struct {
117116

118117
uri: []const u8,
119118

120-
// TODO handle proxy
121-
loader: Loader,
122-
123119
env: Env,
124120
loop: *Loop,
125121
inspector: jsruntime.Inspector,
@@ -129,7 +125,7 @@ pub const Session = struct {
129125
// TODO move the shed to the browser?
130126
storageShed: storage.Shed,
131127
page: ?Page = null,
132-
httpClient: HttpClient,
128+
http_client: http.Client,
133129

134130
jstypes: [Types.len]usize = undefined,
135131

@@ -139,8 +135,7 @@ pub const Session = struct {
139135
.env = undefined,
140136
.inspector = undefined,
141137
.allocator = allocator,
142-
.loader = Loader.init(allocator),
143-
.httpClient = .{ .allocator = allocator },
138+
.http_client = try http.Client.init(allocator, 5),
144139
.storageShed = storage.Shed.init(allocator),
145140
.arena = std.heap.ArenaAllocator.init(allocator),
146141
.window = Window.create(null, .{ .agent = user_agent }),
@@ -179,8 +174,7 @@ pub const Session = struct {
179174

180175
self.env.deinit();
181176
self.arena.deinit();
182-
self.httpClient.deinit();
183-
self.loader.deinit();
177+
self.http_client.deinit();
184178
self.storageShed.deinit();
185179
}
186180

@@ -367,50 +361,34 @@ pub const Page = struct {
367361
// TODO handle fragment in url.
368362

369363
// load the data
370-
var resp = try self.session.loader.get(alloc, self.uri);
371-
defer resp.deinit();
372-
373-
const req = resp.req;
364+
var request = try self.session.http_client.request(.GET, self.uri);
365+
defer request.deinit();
366+
var response = try request.sendSync(.{});
374367

375-
log.info("GET {any} {d}", .{ self.uri, @intFromEnum(req.response.status) });
376-
377-
// TODO handle redirection
378-
log.debug("{?} {d} {s}", .{
379-
req.response.version,
380-
@intFromEnum(req.response.status),
381-
req.response.reason,
382-
// TODO log headers
383-
});
368+
const header = response.header;
369+
log.info("GET {any} {d}", .{ self.uri, header.status });
384370

385-
// TODO handle charset
386-
// https://html.spec.whatwg.org/#content-type
387-
var it = req.response.iterateHeaders();
388-
var ct: ?[]const u8 = null;
389-
while (true) {
390-
const h = it.next() orelse break;
391-
if (std.ascii.eqlIgnoreCase(h.name, "Content-Type")) {
392-
ct = try alloc.dupe(u8, h.value);
393-
}
394-
}
395-
if (ct == null) {
371+
const ct = response.header.get("content-type") orelse {
396372
// no content type in HTTP headers.
397373
// TODO try to sniff mime type from the body.
398374
log.info("no content-type HTTP header", .{});
399375
return;
400-
}
401-
defer alloc.free(ct.?);
376+
};
402377

403-
log.debug("header content-type: {s}", .{ct.?});
404-
var mime = try Mime.parse(alloc, ct.?);
378+
log.debug("header content-type: {s}", .{ct});
379+
var mime = try Mime.parse(alloc, ct);
405380
defer mime.deinit();
406381

407382
if (mime.isHTML()) {
408-
try self.loadHTMLDoc(req.reader(), mime.charset orelse "utf-8", auxData);
383+
try self.loadHTMLDoc(&response, mime.charset orelse "utf-8", auxData);
409384
} else {
410-
log.info("non-HTML document: {s}", .{ct.?});
411-
385+
log.info("non-HTML document: {s}", .{ct});
386+
var arr: std.ArrayListUnmanaged(u8) = .{};
387+
while (try response.next()) |data| {
388+
try arr.appendSlice(alloc, try alloc.dupe(u8, data));
389+
}
412390
// save the body into the page.
413-
self.raw_data = try req.reader().readAllAlloc(alloc, 16 * 1024 * 1024);
391+
self.raw_data = arr.items;
414392
}
415393
}
416394

@@ -453,7 +431,7 @@ pub const Page = struct {
453431
// replace the user context document with the new one.
454432
try self.session.env.setUserContext(.{
455433
.document = html_doc,
456-
.httpClient = &self.session.httpClient,
434+
.http_client = @ptrCast(&self.session.http_client),
457435
});
458436

459437
// browse the DOM tree to retrieve scripts
@@ -614,22 +592,29 @@ pub const Page = struct {
614592
var b: []u8 = buffer[0..];
615593
const u = try std.Uri.resolve_inplace(self.uri, src, &b);
616594

617-
var fetchres = try self.session.loader.get(alloc, u);
618-
defer fetchres.deinit();
595+
var request = try self.session.http_client.request(.GET, u);
596+
defer request.deinit();
597+
var response = try request.sendSync(.{});
619598

620-
const resp = fetchres.req.response;
599+
log.info("fetch {any}: {d}", .{ u, response.header.status });
621600

622-
log.info("fetch {any}: {d}", .{ u, resp.status });
601+
if (response.header.status != 200) {
602+
return FetchError.BadStatusCode;
603+
}
623604

624-
if (resp.status != .ok) return FetchError.BadStatusCode;
605+
var arr: std.ArrayListUnmanaged(u8) = .{};
606+
while (try response.next()) |data| {
607+
try arr.appendSlice(alloc, try alloc.dupe(u8, data));
608+
}
625609

626610
// TODO check content-type
627-
const body = try fetchres.req.reader().readAllAlloc(alloc, 16 * 1024 * 1024);
628611

629612
// check no body
630-
if (body.len == 0) return FetchError.NoBody;
613+
if (arr.items.len == 0) {
614+
return FetchError.NoBody;
615+
}
631616

632-
return body;
617+
return arr.items;
633618
}
634619

635620
// fetchScript senf a GET request to the src and execute the script
@@ -638,7 +623,6 @@ pub const Page = struct {
638623
const alloc = self.arena.allocator();
639624
const body = try self.fetchData(alloc, s.src);
640625
defer alloc.free(body);
641-
642626
try s.eval(alloc, self.session.env, body);
643627
}
644628

src/browser/loader.zig

Lines changed: 0 additions & 97 deletions
This file was deleted.

0 commit comments

Comments
 (0)