Skip to content

Commit 59f4e45

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

File tree

15 files changed

+1550
-2143
lines changed

15 files changed

+1550
-2143
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

LICENSING.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ The default license for this project is [AGPL-3.0-only](LICENSE).
1010
The following files are licensed under MIT:
1111

1212
```
13-
src/http/Client.zig
1413
src/polyfill/fetch.js
1514
```
1615

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 & 54 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

@@ -43,10 +42,8 @@ const Location = @import("../html/location.zig").Location;
4342

4443
const storage = @import("../storage/storage.zig");
4544

46-
const FetchResult = @import("../http/Client.zig").Client.FetchResult;
47-
45+
const http = @import("../http/client.zig");
4846
const UserContext = @import("../user_context.zig").UserContext;
49-
const HttpClient = @import("asyncio").Client;
5047

5148
const polyfill = @import("../polyfill/polyfill.zig");
5249

@@ -117,9 +114,6 @@ pub const Session = struct {
117114

118115
uri: []const u8,
119116

120-
// TODO handle proxy
121-
loader: Loader,
122-
123117
env: Env,
124118
loop: *Loop,
125119
inspector: jsruntime.Inspector,
@@ -129,7 +123,7 @@ pub const Session = struct {
129123
// TODO move the shed to the browser?
130124
storageShed: storage.Shed,
131125
page: ?Page = null,
132-
httpClient: HttpClient,
126+
http_client: http.Client,
133127

134128
jstypes: [Types.len]usize = undefined,
135129

@@ -139,8 +133,7 @@ pub const Session = struct {
139133
.env = undefined,
140134
.inspector = undefined,
141135
.allocator = allocator,
142-
.loader = Loader.init(allocator),
143-
.httpClient = .{ .allocator = allocator },
136+
.http_client = try http.Client.init(allocator, 5),
144137
.storageShed = storage.Shed.init(allocator),
145138
.arena = std.heap.ArenaAllocator.init(allocator),
146139
.window = Window.create(null, .{ .agent = user_agent }),
@@ -179,8 +172,7 @@ pub const Session = struct {
179172

180173
self.env.deinit();
181174
self.arena.deinit();
182-
self.httpClient.deinit();
183-
self.loader.deinit();
175+
self.http_client.deinit();
184176
self.storageShed.deinit();
185177
}
186178

@@ -367,50 +359,34 @@ pub const Page = struct {
367359
// TODO handle fragment in url.
368360

369361
// load the data
370-
var resp = try self.session.loader.get(alloc, self.uri);
371-
defer resp.deinit();
372-
373-
const req = resp.req;
374-
375-
log.info("GET {any} {d}", .{ self.uri, @intFromEnum(req.response.status) });
362+
var request = try self.session.http_client.request(.GET, self.uri);
363+
defer request.deinit();
364+
var response = try request.sendSync(.{});
376365

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-
});
366+
const header = response.header;
367+
log.info("GET {any} {d}", .{ self.uri, header.status });
384368

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) {
369+
const ct = response.header.get("content-type") orelse {
396370
// no content type in HTTP headers.
397371
// TODO try to sniff mime type from the body.
398372
log.info("no content-type HTTP header", .{});
399373
return;
400-
}
401-
defer alloc.free(ct.?);
374+
};
402375

403-
log.debug("header content-type: {s}", .{ct.?});
404-
var mime = try Mime.parse(alloc, ct.?);
376+
log.debug("header content-type: {s}", .{ct});
377+
var mime = try Mime.parse(alloc, ct);
405378
defer mime.deinit();
406379

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

@@ -453,7 +429,7 @@ pub const Page = struct {
453429
// replace the user context document with the new one.
454430
try self.session.env.setUserContext(.{
455431
.document = html_doc,
456-
.httpClient = &self.session.httpClient,
432+
.http_client = @ptrCast(&self.session.http_client),
457433
});
458434

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

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

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

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

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

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

629610
// check no body
630-
if (body.len == 0) return FetchError.NoBody;
611+
if (arr.items.len == 0) {
612+
return FetchError.NoBody;
613+
}
631614

632-
return body;
615+
return arr.items;
633616
}
634617

635618
// fetchScript senf a GET request to the src and execute the script
@@ -638,7 +621,6 @@ pub const Page = struct {
638621
const alloc = self.arena.allocator();
639622
const body = try self.fetchData(alloc, s.src);
640623
defer alloc.free(body);
641-
642624
try s.eval(alloc, self.session.env, body);
643625
}
644626

src/browser/loader.zig

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

0 commit comments

Comments
 (0)