mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-03-06 07:37:20 -05:00
Merge pull request #203 from lightpanda-io/upgrade-zig
Upgrade zig 0.12
This commit is contained in:
2
.github/workflows/wpt.yml
vendored
2
.github/workflows/wpt.yml
vendored
@@ -47,7 +47,7 @@ jobs:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ghcr.io/lightpanda-io/zig-browsercore:0.12.0-dev.1773-8a8fd47d2
|
||||
image: ghcr.io/lightpanda-io/zig-browsercore:0.12.1
|
||||
credentials:
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
2
.github/workflows/zig-fmt.yml
vendored
2
.github/workflows/zig-fmt.yml
vendored
@@ -27,7 +27,7 @@ jobs:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ghcr.io/lightpanda-io/zig:0.12.0-dev.1773-8a8fd47d2
|
||||
image: ghcr.io/lightpanda-io/zig:0.12.1
|
||||
credentials:
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
6
.github/workflows/zig-test.yml
vendored
6
.github/workflows/zig-test.yml
vendored
@@ -45,7 +45,7 @@ jobs:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ghcr.io/lightpanda-io/zig-browsercore:0.12.0-dev.1773-8a8fd47d2
|
||||
image: ghcr.io/lightpanda-io/zig-browsercore:0.12.1
|
||||
credentials:
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -71,7 +71,7 @@ jobs:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ghcr.io/lightpanda-io/zig-browsercore:0.12.0-dev.1773-8a8fd47d2
|
||||
image: ghcr.io/lightpanda-io/zig-browsercore:0.12.1
|
||||
credentials:
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -97,7 +97,7 @@ jobs:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ghcr.io/lightpanda-io/zig-browsercore:0.12.0-dev.1773-8a8fd47d2
|
||||
image: ghcr.io/lightpanda-io/zig-browsercore:0.12.1
|
||||
credentials:
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -76,7 +76,7 @@ We do not provide yet binary versions of Lightpanda, you have to compile it from
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Lightpanda is written with [Zig](https://ziglang.org/) `0.12`. You have to
|
||||
Lightpanda is written with [Zig](https://ziglang.org/) `0.12.1`. You have to
|
||||
install it with the right version in order to build the project.
|
||||
|
||||
Lightpanda also depends on
|
||||
|
||||
82
build.zig
82
build.zig
@@ -28,7 +28,7 @@ const jsruntime_pkgs = jsruntime.packages(jsruntime_path);
|
||||
/// which zig version to install.
|
||||
const recommended_zig_version = jsruntime.recommended_zig_version;
|
||||
|
||||
pub fn build(b: *std.build.Builder) !void {
|
||||
pub fn build(b: *std.Build) !void {
|
||||
switch (comptime builtin.zig_version.order(std.SemanticVersion.parse(recommended_zig_version) catch unreachable)) {
|
||||
.eq => {},
|
||||
.lt => {
|
||||
@@ -53,11 +53,11 @@ pub fn build(b: *std.build.Builder) !void {
|
||||
// compile and install
|
||||
const exe = b.addExecutable(.{
|
||||
.name = "browsercore",
|
||||
.root_source_file = .{ .path = "src/main.zig" },
|
||||
.root_source_file = b.path("src/main.zig"),
|
||||
.target = target,
|
||||
.optimize = mode,
|
||||
});
|
||||
try common(exe, options);
|
||||
try common(b, exe, options);
|
||||
b.installArtifact(exe);
|
||||
|
||||
// run
|
||||
@@ -76,11 +76,11 @@ pub fn build(b: *std.build.Builder) !void {
|
||||
// compile and install
|
||||
const shell = b.addExecutable(.{
|
||||
.name = "browsercore-shell",
|
||||
.root_source_file = .{ .path = "src/main_shell.zig" },
|
||||
.root_source_file = b.path("src/main_shell.zig"),
|
||||
.target = target,
|
||||
.optimize = mode,
|
||||
});
|
||||
try common(shell, options);
|
||||
try common(b, shell, options);
|
||||
try jsruntime_pkgs.add_shell(shell);
|
||||
|
||||
// run
|
||||
@@ -98,17 +98,17 @@ pub fn build(b: *std.build.Builder) !void {
|
||||
|
||||
// compile
|
||||
const tests = b.addTest(.{
|
||||
.root_source_file = .{ .path = "src/run_tests.zig" },
|
||||
.test_runner = "src/test_runner.zig",
|
||||
.single_threaded = true,
|
||||
.root_source_file = b.path("src/run_tests.zig"),
|
||||
.test_runner = b.path("src/test_runner.zig"),
|
||||
.target = target,
|
||||
.optimize = mode,
|
||||
});
|
||||
try common(tests, options);
|
||||
try common(b, tests, options);
|
||||
|
||||
// add jsruntime pretty deps
|
||||
const pretty = tests.step.owner.createModule(.{
|
||||
.source_file = .{ .path = "vendor/zig-js-runtime/src/pretty.zig" },
|
||||
tests.root_module.addAnonymousImport("pretty", .{
|
||||
.root_source_file = b.path("vendor/zig-js-runtime/src/pretty.zig"),
|
||||
});
|
||||
tests.addModule("pretty", pretty);
|
||||
|
||||
const run_tests = b.addRunArtifact(tests);
|
||||
if (b.args) |args| {
|
||||
@@ -125,12 +125,11 @@ pub fn build(b: *std.build.Builder) !void {
|
||||
// compile and install
|
||||
const wpt = b.addExecutable(.{
|
||||
.name = "browsercore-wpt",
|
||||
.root_source_file = .{ .path = "src/main_wpt.zig" },
|
||||
.root_source_file = b.path("src/main_wpt.zig"),
|
||||
.target = target,
|
||||
.optimize = mode,
|
||||
});
|
||||
try common(wpt, options);
|
||||
b.installArtifact(wpt);
|
||||
try common(b, wpt, options);
|
||||
|
||||
// run
|
||||
const wpt_cmd = b.addRunArtifact(wpt);
|
||||
@@ -147,11 +146,11 @@ pub fn build(b: *std.build.Builder) !void {
|
||||
// compile and install
|
||||
const get = b.addExecutable(.{
|
||||
.name = "browsercore-get",
|
||||
.root_source_file = .{ .path = "src/main_get.zig" },
|
||||
.root_source_file = b.path("src/main_get.zig"),
|
||||
.target = target,
|
||||
.optimize = mode,
|
||||
});
|
||||
try common(get, options);
|
||||
try common(b, get, options);
|
||||
b.installArtifact(get);
|
||||
|
||||
// run
|
||||
@@ -165,25 +164,38 @@ pub fn build(b: *std.build.Builder) !void {
|
||||
}
|
||||
|
||||
fn common(
|
||||
b: *std.Build,
|
||||
step: *std.Build.Step.Compile,
|
||||
options: jsruntime.Options,
|
||||
) !void {
|
||||
try jsruntime_pkgs.add(step, options);
|
||||
linkNetSurf(step);
|
||||
const jsruntimemod = try jsruntime_pkgs.module(
|
||||
b,
|
||||
options,
|
||||
step.root_module.optimize.?,
|
||||
step.root_module.resolved_target.?,
|
||||
);
|
||||
step.root_module.addImport("jsruntime", jsruntimemod);
|
||||
|
||||
// link mimalloc
|
||||
step.addObjectFile(.{ .path = "vendor/mimalloc/out/libmimalloc.a" });
|
||||
step.addIncludePath(.{ .path = "vendor/mimalloc/out/include" });
|
||||
const netsurf = moduleNetSurf(b);
|
||||
netsurf.addImport("jsruntime", jsruntimemod);
|
||||
step.root_module.addImport("netsurf", netsurf);
|
||||
}
|
||||
|
||||
fn linkNetSurf(step: *std.build.LibExeObjStep) void {
|
||||
|
||||
fn moduleNetSurf(b: *std.Build) *std.Build.Module {
|
||||
const mod = b.addModule("netsurf", .{
|
||||
.root_source_file = b.path("src/netsurf/netsurf.zig"),
|
||||
});
|
||||
// iconv
|
||||
step.addObjectFile(.{ .path = "vendor/libiconv/lib/libiconv.a" });
|
||||
step.addIncludePath(.{ .path = "vendor/libiconv/include" });
|
||||
mod.addObjectFile(b.path("vendor/libiconv/lib/libiconv.a"));
|
||||
mod.addIncludePath(b.path("vendor/libiconv/include"));
|
||||
|
||||
// mimalloc
|
||||
mod.addImport("mimalloc", moduleMimalloc(b));
|
||||
|
||||
// netsurf libs
|
||||
const ns = "vendor/netsurf";
|
||||
mod.addIncludePath(b.path(ns ++ "/include"));
|
||||
|
||||
const libs: [4][]const u8 = .{
|
||||
"libdom",
|
||||
"libhubbub",
|
||||
@@ -191,8 +203,20 @@ fn linkNetSurf(step: *std.build.LibExeObjStep) void {
|
||||
"libwapcaplet",
|
||||
};
|
||||
inline for (libs) |lib| {
|
||||
step.addObjectFile(.{ .path = ns ++ "/lib/" ++ lib ++ ".a" });
|
||||
step.addIncludePath(.{ .path = ns ++ "/" ++ lib ++ "/src" });
|
||||
mod.addObjectFile(b.path(ns ++ "/lib/" ++ lib ++ ".a"));
|
||||
mod.addIncludePath(b.path(ns ++ "/" ++ lib ++ "/src"));
|
||||
}
|
||||
step.addIncludePath(.{ .path = ns ++ "/include" });
|
||||
|
||||
return mod;
|
||||
}
|
||||
|
||||
fn moduleMimalloc(b: *std.Build) *std.Build.Module {
|
||||
const mod = b.addModule("mimalloc", .{
|
||||
.root_source_file = b.path("src/mimalloc/mimalloc.zig"),
|
||||
});
|
||||
|
||||
mod.addObjectFile(b.path("vendor/mimalloc/out/libmimalloc.a"));
|
||||
mod.addIncludePath(b.path("vendor/mimalloc/out/include"));
|
||||
|
||||
return mod;
|
||||
}
|
||||
|
||||
1391
src/async/Client.zig
1391
src/async/Client.zig
File diff suppressed because it is too large
Load Diff
@@ -18,7 +18,7 @@
|
||||
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const os = std.os;
|
||||
const posix = std.posix;
|
||||
const io = std.io;
|
||||
const assert = std.debug.assert;
|
||||
|
||||
@@ -28,15 +28,15 @@ pub const Stream = struct {
|
||||
alloc: std.mem.Allocator,
|
||||
conn: *tcp.Conn,
|
||||
|
||||
handle: std.os.socket_t,
|
||||
handle: posix.socket_t,
|
||||
|
||||
pub fn close(self: Stream) void {
|
||||
os.closeSocket(self.handle);
|
||||
posix.close(self.handle);
|
||||
self.alloc.destroy(self.conn);
|
||||
}
|
||||
|
||||
pub const ReadError = os.ReadError;
|
||||
pub const WriteError = os.WriteError;
|
||||
pub const ReadError = posix.ReadError;
|
||||
pub const WriteError = posix.WriteError;
|
||||
|
||||
pub const Reader = io.Reader(Stream, ReadError, read);
|
||||
pub const Writer = io.Writer(Stream, WriteError, write);
|
||||
@@ -55,8 +55,8 @@ pub const Stream = struct {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn readv(s: Stream, iovecs: []const os.iovec) ReadError!usize {
|
||||
return os.readv(s.handle, iovecs);
|
||||
pub fn readv(s: Stream, iovecs: []const posix.iovec) ReadError!usize {
|
||||
return posix.readv(s.handle, iovecs);
|
||||
}
|
||||
|
||||
/// Returns the number of bytes read. If the number read is smaller than
|
||||
@@ -105,7 +105,7 @@ pub const Stream = struct {
|
||||
|
||||
/// See https://github.com/ziglang/zig/issues/7699
|
||||
/// See equivalent function: `std.fs.File.writev`.
|
||||
pub fn writev(self: Stream, iovecs: []const os.iovec_const) WriteError!usize {
|
||||
pub fn writev(self: Stream, iovecs: []const posix.iovec_const) WriteError!usize {
|
||||
if (iovecs.len == 0) return 0;
|
||||
const first_buffer = iovecs[0].iov_base[0..iovecs[0].iov_len];
|
||||
return try self.write(first_buffer);
|
||||
@@ -115,7 +115,7 @@ pub const Stream = struct {
|
||||
/// order to handle partial writes from the underlying OS layer.
|
||||
/// See https://github.com/ziglang/zig/issues/7699
|
||||
/// See equivalent function: `std.fs.File.writevAll`.
|
||||
pub fn writevAll(self: Stream, iovecs: []os.iovec_const) WriteError!void {
|
||||
pub fn writevAll(self: Stream, iovecs: []posix.iovec_const) WriteError!void {
|
||||
if (iovecs.len == 0) return;
|
||||
|
||||
var i: usize = 0;
|
||||
|
||||
@@ -59,19 +59,19 @@ pub const Conn = struct {
|
||||
|
||||
loop: *Loop,
|
||||
|
||||
pub fn connect(self: *Conn, socket: std.os.socket_t, address: std.net.Address) !void {
|
||||
pub fn connect(self: *Conn, socket: std.posix.socket_t, address: std.net.Address) !void {
|
||||
var cmd = Command{ .impl = NetworkImpl.init(self.loop) };
|
||||
cmd.impl.connect(&cmd, socket, address);
|
||||
_ = try cmd.wait();
|
||||
}
|
||||
|
||||
pub fn send(self: *Conn, socket: std.os.socket_t, buffer: []const u8) !usize {
|
||||
pub fn send(self: *Conn, socket: std.posix.socket_t, buffer: []const u8) !usize {
|
||||
var cmd = Command{ .impl = NetworkImpl.init(self.loop) };
|
||||
cmd.impl.send(&cmd, socket, buffer);
|
||||
return try cmd.wait();
|
||||
}
|
||||
|
||||
pub fn receive(self: *Conn, socket: std.os.socket_t, buffer: []u8) !usize {
|
||||
pub fn receive(self: *Conn, socket: std.posix.socket_t, buffer: []u8) !usize {
|
||||
var cmd = Command{ .impl = NetworkImpl.init(self.loop) };
|
||||
cmd.impl.receive(&cmd, socket, buffer);
|
||||
return try cmd.wait();
|
||||
@@ -93,12 +93,12 @@ pub fn tcpConnectToHost(alloc: std.mem.Allocator, loop: *Loop, name: []const u8,
|
||||
else => return err,
|
||||
};
|
||||
}
|
||||
return std.os.ConnectError.ConnectionRefused;
|
||||
return std.posix.ConnectError.ConnectionRefused;
|
||||
}
|
||||
|
||||
pub fn tcpConnectToAddress(alloc: std.mem.Allocator, loop: *Loop, addr: net.Address) !Stream {
|
||||
const sockfd = try std.os.socket(addr.any.family, std.os.SOCK.STREAM, std.os.IPPROTO.TCP);
|
||||
errdefer std.os.closeSocket(sockfd);
|
||||
const sockfd = try std.posix.socket(addr.any.family, std.posix.SOCK.STREAM, std.posix.IPPROTO.TCP);
|
||||
errdefer std.posix.close(sockfd);
|
||||
|
||||
var conn = try alloc.create(Conn);
|
||||
conn.* = Conn{ .loop = loop };
|
||||
|
||||
@@ -40,11 +40,9 @@ test "blocking mode fetch API" {
|
||||
// force client's CA cert scan from system.
|
||||
try client.ca_bundle.rescan(client.allocator);
|
||||
|
||||
var res = try client.fetch(alloc, .{
|
||||
const res = try client.fetch(.{
|
||||
.location = .{ .uri = try std.Uri.parse(url) },
|
||||
.payload = .none,
|
||||
});
|
||||
defer res.deinit();
|
||||
|
||||
try std.testing.expect(res.status == .ok);
|
||||
}
|
||||
@@ -64,13 +62,13 @@ test "blocking mode open/send/wait API" {
|
||||
// force client's CA cert scan from system.
|
||||
try client.ca_bundle.rescan(client.allocator);
|
||||
|
||||
var headers = try std.http.Headers.initList(alloc, &[_]std.http.Field{});
|
||||
defer headers.deinit();
|
||||
|
||||
var req = try client.open(.GET, try std.Uri.parse(url), headers, .{});
|
||||
var buf: [2014]u8 = undefined;
|
||||
var req = try client.open(.GET, try std.Uri.parse(url), .{
|
||||
.server_header_buffer = &buf,
|
||||
});
|
||||
defer req.deinit();
|
||||
|
||||
try req.send(.{});
|
||||
try req.send();
|
||||
try req.finish();
|
||||
try req.wait();
|
||||
|
||||
@@ -87,7 +85,6 @@ const AsyncClient = struct {
|
||||
|
||||
cli: *Client,
|
||||
uri: std.Uri,
|
||||
headers: std.http.Headers,
|
||||
|
||||
req: ?Request = undefined,
|
||||
state: State = .new,
|
||||
@@ -95,9 +92,10 @@ const AsyncClient = struct {
|
||||
impl: YieldImpl,
|
||||
err: ?anyerror = null,
|
||||
|
||||
buf: [2014]u8 = undefined,
|
||||
|
||||
pub fn deinit(self: *AsyncRequest) void {
|
||||
if (self.req) |*r| r.deinit();
|
||||
self.headers.deinit();
|
||||
}
|
||||
|
||||
pub fn fetch(self: *AsyncRequest) void {
|
||||
@@ -116,11 +114,13 @@ const AsyncClient = struct {
|
||||
switch (self.state) {
|
||||
.new => {
|
||||
self.state = .open;
|
||||
self.req = self.cli.open(.GET, self.uri, self.headers, .{}) catch |e| return self.onerr(e);
|
||||
self.req = self.cli.open(.GET, self.uri, .{
|
||||
.server_header_buffer = &self.buf,
|
||||
}) catch |e| return self.onerr(e);
|
||||
},
|
||||
.open => {
|
||||
self.state = .send;
|
||||
self.req.?.send(.{}) catch |e| return self.onerr(e);
|
||||
self.req.?.send() catch |e| return self.onerr(e);
|
||||
},
|
||||
.send => {
|
||||
self.state = .finish;
|
||||
@@ -164,7 +164,6 @@ const AsyncClient = struct {
|
||||
.impl = YieldImpl.init(self.cli.loop),
|
||||
.cli = &self.cli,
|
||||
.uri = uri,
|
||||
.headers = .{ .allocator = self.cli.allocator, .owned = false },
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -21,7 +21,7 @@ const builtin = @import("builtin");
|
||||
|
||||
const Types = @import("root").Types;
|
||||
|
||||
const parser = @import("../netsurf.zig");
|
||||
const parser = @import("netsurf");
|
||||
const Loader = @import("loader.zig").Loader;
|
||||
const Dump = @import("dump.zig");
|
||||
const Mime = @import("mime.zig");
|
||||
@@ -224,7 +224,7 @@ pub const Page = struct {
|
||||
// own the url
|
||||
if (self.rawuri) |prev| alloc.free(prev);
|
||||
self.rawuri = try alloc.dupe(u8, uri);
|
||||
self.uri = std.Uri.parse(self.rawuri.?) catch try std.Uri.parseWithoutScheme(self.rawuri.?);
|
||||
self.uri = std.Uri.parse(self.rawuri.?) catch try std.Uri.parseAfterScheme("", self.rawuri.?);
|
||||
|
||||
// prepare origin value.
|
||||
var buf = std.ArrayList(u8).init(alloc);
|
||||
@@ -247,29 +247,39 @@ pub const Page = struct {
|
||||
|
||||
// TODO handle redirection
|
||||
if (req.response.status != .ok) {
|
||||
log.debug("{?} {d} {s}\n{any}", .{
|
||||
log.debug("{?} {d} {s}", .{
|
||||
req.response.version,
|
||||
req.response.status,
|
||||
req.response.reason,
|
||||
req.response.headers,
|
||||
// TODO log headers
|
||||
});
|
||||
return error.BadStatusCode;
|
||||
}
|
||||
|
||||
// TODO handle charset
|
||||
// https://html.spec.whatwg.org/#content-type
|
||||
const ct = req.response.headers.getFirstValue("Content-Type") orelse {
|
||||
var it = req.response.iterateHeaders();
|
||||
var ct: ?[]const u8 = null;
|
||||
while (true) {
|
||||
const h = it.next() orelse break;
|
||||
if (std.ascii.eqlIgnoreCase(h.name, "Content-Type")) {
|
||||
ct = try alloc.dupe(u8, h.value);
|
||||
}
|
||||
}
|
||||
if (ct == null) {
|
||||
// no content type in HTTP headers.
|
||||
// TODO try to sniff mime type from the body.
|
||||
log.info("no content-type HTTP header", .{});
|
||||
return;
|
||||
};
|
||||
log.debug("header content-type: {s}", .{ct});
|
||||
const mime = try Mime.parse(ct);
|
||||
}
|
||||
defer alloc.free(ct.?);
|
||||
|
||||
log.debug("header content-type: {s}", .{ct.?});
|
||||
const mime = try Mime.parse(ct.?);
|
||||
if (mime.eql(Mime.HTML)) {
|
||||
try self.loadHTMLDoc(req.reader(), mime.charset orelse "utf-8");
|
||||
} else {
|
||||
log.info("non-HTML document: {s}", .{ct});
|
||||
log.info("non-HTML document: {s}", .{ct.?});
|
||||
|
||||
// save the body into the page.
|
||||
self.raw_data = try req.reader().readAllAlloc(alloc, 16 * 1024 * 1024);
|
||||
@@ -500,22 +510,27 @@ pub const Page = struct {
|
||||
|
||||
log.debug("starting fetch script {s}", .{src});
|
||||
|
||||
const u = std.Uri.parse(src) catch try std.Uri.parseWithoutScheme(src);
|
||||
const ru = try std.Uri.resolve(self.uri, u, false, alloc);
|
||||
var buffer: [1024]u8 = undefined;
|
||||
var b: []u8 = buffer[0..];
|
||||
const u = try std.Uri.resolve_inplace(self.uri, src, &b);
|
||||
|
||||
var fetchres = try self.session.loader.fetch(alloc, ru);
|
||||
var fetchres = try self.session.loader.get(alloc, u);
|
||||
defer fetchres.deinit();
|
||||
|
||||
log.info("fech script {any}: {d}", .{ ru, fetchres.status });
|
||||
const resp = fetchres.req.response;
|
||||
|
||||
if (fetchres.status != .ok) return FetchError.BadStatusCode;
|
||||
log.info("fech script {any}: {d}", .{ u, resp.status });
|
||||
|
||||
if (resp.status != .ok) return FetchError.BadStatusCode;
|
||||
|
||||
// TODO check content-type
|
||||
const body = try fetchres.req.reader().readAllAlloc(alloc, 16 * 1024 * 1024);
|
||||
defer alloc.free(body);
|
||||
|
||||
// check no body
|
||||
if (fetchres.body == null) return FetchError.NoBody;
|
||||
if (body.len == 0) return FetchError.NoBody;
|
||||
|
||||
var res = try self.session.env.execTryCatch(alloc, fetchres.body.?, src);
|
||||
var res = try self.session.env.execTryCatch(alloc, body, src);
|
||||
defer res.deinit(alloc);
|
||||
|
||||
if (res.success) {
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
const std = @import("std");
|
||||
const File = std.fs.File;
|
||||
|
||||
const parser = @import("../netsurf.zig");
|
||||
const parser = @import("netsurf");
|
||||
const Walker = @import("../dom/walker.zig").WalkerChildren;
|
||||
|
||||
// writer must be a std.io.Writer
|
||||
|
||||
@@ -22,6 +22,7 @@ const user_agent = "Lightpanda.io/1.0";
|
||||
|
||||
pub const Loader = struct {
|
||||
client: std.http.Client,
|
||||
server_header_buffer: [1024]u8 = undefined,
|
||||
|
||||
pub const Response = struct {
|
||||
alloc: std.mem.Allocator,
|
||||
@@ -45,46 +46,30 @@ pub const Loader = struct {
|
||||
self.client.deinit();
|
||||
}
|
||||
|
||||
// the caller must deinit the FetchResult.
|
||||
pub fn fetch(self: *Loader, alloc: std.mem.Allocator, uri: std.Uri) !std.http.Client.FetchResult {
|
||||
var headers = try std.http.Headers.initList(alloc, &[_]std.http.Field{
|
||||
.{ .name = "User-Agent", .value = user_agent },
|
||||
.{ .name = "Accept", .value = "*/*" },
|
||||
.{ .name = "Accept-Language", .value = "en-US,en;q=0.5" },
|
||||
});
|
||||
defer headers.deinit();
|
||||
|
||||
return try self.client.fetch(alloc, .{
|
||||
.location = .{ .uri = uri },
|
||||
.headers = headers,
|
||||
.payload = .none,
|
||||
});
|
||||
}
|
||||
|
||||
// see
|
||||
// https://ziglang.org/documentation/master/std/#A;std:http.Client.fetch
|
||||
// for reference.
|
||||
// The caller is responsible for calling `deinit()` on the `Response`.
|
||||
pub fn get(self: *Loader, alloc: std.mem.Allocator, uri: std.Uri) !Response {
|
||||
var headers = try std.http.Headers.initList(alloc, &[_]std.http.Field{
|
||||
.{ .name = "User-Agent", .value = user_agent },
|
||||
.{ .name = "Accept", .value = "*/*" },
|
||||
.{ .name = "Accept-Language", .value = "en-US,en;q=0.5" },
|
||||
});
|
||||
defer headers.deinit();
|
||||
|
||||
var resp = Response{
|
||||
.alloc = alloc,
|
||||
.req = try alloc.create(std.http.Client.Request),
|
||||
};
|
||||
errdefer alloc.destroy(resp.req);
|
||||
|
||||
resp.req.* = try self.client.open(.GET, uri, headers, .{
|
||||
.handle_redirects = true, // TODO handle redirects manually
|
||||
resp.req.* = try self.client.open(.GET, uri, .{
|
||||
.headers = .{
|
||||
.user_agent = .{ .override = user_agent },
|
||||
},
|
||||
.extra_headers = &.{
|
||||
.{ .name = "Accept", .value = "*/*" },
|
||||
.{ .name = "Accept-Language", .value = "en-US,en;q=0.5" },
|
||||
},
|
||||
.server_header_buffer = &self.server_header_buffer,
|
||||
});
|
||||
errdefer resp.req.deinit();
|
||||
|
||||
try resp.req.send(.{});
|
||||
try resp.req.send();
|
||||
try resp.req.finish();
|
||||
try resp.req.wait();
|
||||
|
||||
@@ -92,13 +77,13 @@ pub const Loader = struct {
|
||||
}
|
||||
};
|
||||
|
||||
test "basic url fetch" {
|
||||
test "basic url get" {
|
||||
const alloc = std.testing.allocator;
|
||||
var loader = Loader.init(alloc);
|
||||
defer loader.deinit();
|
||||
|
||||
var result = try loader.fetch(alloc, "https://en.wikipedia.org/wiki/Main_Page");
|
||||
var result = try loader.get(alloc, "https://en.wikipedia.org/wiki/Main_Page");
|
||||
defer result.deinit();
|
||||
|
||||
try std.testing.expect(result.status == std.http.Status.ok);
|
||||
try std.testing.expect(result.req.response.status == std.http.Status.ok);
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const parser = @import("../netsurf.zig");
|
||||
const parser = @import("netsurf");
|
||||
|
||||
// Node implementation with Netsurf Libdom C lib.
|
||||
pub const Node = struct {
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
const std = @import("std");
|
||||
const css = @import("css.zig");
|
||||
const Node = @import("libdom.zig").Node;
|
||||
const parser = @import("../netsurf.zig");
|
||||
const parser = @import("netsurf");
|
||||
|
||||
const Matcher = struct {
|
||||
const Nodes = std.ArrayList(Node);
|
||||
|
||||
@@ -22,7 +22,7 @@ const jsruntime = @import("jsruntime");
|
||||
const Case = jsruntime.test_utils.Case;
|
||||
const checkCases = jsruntime.test_utils.checkCases;
|
||||
|
||||
const parser = @import("../netsurf.zig");
|
||||
const parser = @import("netsurf");
|
||||
|
||||
const Node = @import("node.zig").Node;
|
||||
const DOMException = @import("exceptions.zig").DOMException;
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const parser = @import("../netsurf.zig");
|
||||
const parser = @import("netsurf");
|
||||
|
||||
const Text = @import("text.zig").Text;
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ const Case = jsruntime.test_utils.Case;
|
||||
const checkCases = jsruntime.test_utils.checkCases;
|
||||
const generate = @import("../generate.zig");
|
||||
|
||||
const parser = @import("../netsurf.zig");
|
||||
const parser = @import("netsurf");
|
||||
|
||||
const Node = @import("node.zig").Node;
|
||||
const Comment = @import("comment.zig").Comment;
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
const std = @import("std");
|
||||
|
||||
const parser = @import("../netsurf.zig");
|
||||
const parser = @import("netsurf");
|
||||
|
||||
const jsruntime = @import("jsruntime");
|
||||
const Case = jsruntime.test_utils.Case;
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const parser = @import("../netsurf.zig");
|
||||
const parser = @import("netsurf");
|
||||
|
||||
const css = @import("../css/css.zig");
|
||||
const Node = @import("../css/libdom.zig").Node;
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const parser = @import("../netsurf.zig");
|
||||
const parser = @import("netsurf");
|
||||
|
||||
const jsruntime = @import("jsruntime");
|
||||
const Case = jsruntime.test_utils.Case;
|
||||
@@ -449,7 +449,7 @@ pub fn testExecFn(
|
||||
try checkCases(js_env, &adoptNode);
|
||||
|
||||
const tags = comptime parser.Tag.all();
|
||||
comptime var createElements: [(tags.len) * 2]Case = undefined;
|
||||
var createElements: [(tags.len) * 2]Case = undefined;
|
||||
inline for (tags, 0..) |tag, i| {
|
||||
const tag_name = @tagName(tag);
|
||||
createElements[i * 2] = Case{
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const parser = @import("../netsurf.zig");
|
||||
const parser = @import("netsurf");
|
||||
|
||||
const jsruntime = @import("jsruntime");
|
||||
const Case = jsruntime.test_utils.Case;
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const parser = @import("../netsurf.zig");
|
||||
const parser = @import("netsurf");
|
||||
|
||||
const Node = @import("node.zig").Node;
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const parser = @import("../netsurf.zig");
|
||||
const parser = @import("netsurf");
|
||||
|
||||
const jsruntime = @import("jsruntime");
|
||||
const Case = jsruntime.test_utils.Case;
|
||||
|
||||
@@ -24,7 +24,8 @@ const JSObjectID = jsruntime.JSObjectID;
|
||||
const Case = jsruntime.test_utils.Case;
|
||||
const checkCases = jsruntime.test_utils.checkCases;
|
||||
|
||||
const parser = @import("../netsurf.zig");
|
||||
const parser = @import("netsurf");
|
||||
const EventHandler = @import("../events/event.zig").EventHandler;
|
||||
|
||||
const DOMException = @import("exceptions.zig").DOMException;
|
||||
const Nod = @import("node.zig");
|
||||
@@ -74,6 +75,7 @@ pub const EventTarget = struct {
|
||||
eventType,
|
||||
cbk,
|
||||
capture orelse false,
|
||||
EventHandler,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ const jsruntime = @import("jsruntime");
|
||||
const Case = jsruntime.test_utils.Case;
|
||||
const checkCases = jsruntime.test_utils.checkCases;
|
||||
|
||||
const parser = @import("../netsurf.zig");
|
||||
const parser = @import("netsurf");
|
||||
|
||||
// https://webidl.spec.whatwg.org/#idl-DOMException
|
||||
pub const DOMException = struct {
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const parser = @import("../netsurf.zig");
|
||||
const parser = @import("netsurf");
|
||||
|
||||
const jsruntime = @import("jsruntime");
|
||||
const Case = jsruntime.test_utils.Case;
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const parser = @import("../netsurf.zig");
|
||||
const parser = @import("netsurf");
|
||||
|
||||
const jsruntime = @import("jsruntime");
|
||||
const Case = jsruntime.test_utils.Case;
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const parser = @import("../netsurf.zig");
|
||||
const parser = @import("netsurf");
|
||||
|
||||
const jsruntime = @import("jsruntime");
|
||||
const Case = jsruntime.test_utils.Case;
|
||||
|
||||
@@ -26,7 +26,7 @@ const Variadic = jsruntime.Variadic;
|
||||
|
||||
const generate = @import("../generate.zig");
|
||||
|
||||
const parser = @import("../netsurf.zig");
|
||||
const parser = @import("netsurf");
|
||||
|
||||
const EventTarget = @import("event_target.zig").EventTarget;
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const parser = @import("../netsurf.zig");
|
||||
const parser = @import("netsurf");
|
||||
|
||||
const jsruntime = @import("jsruntime");
|
||||
const Case = jsruntime.test_utils.Case;
|
||||
|
||||
@@ -22,7 +22,7 @@ const jsruntime = @import("jsruntime");
|
||||
const Case = jsruntime.test_utils.Case;
|
||||
const checkCases = jsruntime.test_utils.checkCases;
|
||||
|
||||
const parser = @import("../netsurf.zig");
|
||||
const parser = @import("netsurf");
|
||||
const Node = @import("node.zig").Node;
|
||||
|
||||
// https://dom.spec.whatwg.org/#processinginstruction
|
||||
|
||||
@@ -23,7 +23,7 @@ const Case = jsruntime.test_utils.Case;
|
||||
const checkCases = jsruntime.test_utils.checkCases;
|
||||
const generate = @import("../generate.zig");
|
||||
|
||||
const parser = @import("../netsurf.zig");
|
||||
const parser = @import("netsurf");
|
||||
|
||||
const CharacterData = @import("character_data.zig").CharacterData;
|
||||
const CDATASection = @import("cdata_section.zig").CDATASection;
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const parser = @import("../netsurf.zig");
|
||||
const parser = @import("netsurf");
|
||||
|
||||
const jsruntime = @import("jsruntime");
|
||||
const Case = jsruntime.test_utils.Case;
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const parser = @import("../netsurf.zig");
|
||||
const parser = @import("netsurf");
|
||||
|
||||
pub const Walker = union(enum) {
|
||||
walkerDepthFirst: WalkerDepthFirst,
|
||||
|
||||
@@ -22,10 +22,11 @@ const generate = @import("../generate.zig");
|
||||
|
||||
const jsruntime = @import("jsruntime");
|
||||
const Callback = jsruntime.Callback;
|
||||
const CallbackResult = jsruntime.CallbackResult;
|
||||
const Case = jsruntime.test_utils.Case;
|
||||
const checkCases = jsruntime.test_utils.checkCases;
|
||||
|
||||
const parser = @import("../netsurf.zig");
|
||||
const parser = @import("netsurf");
|
||||
|
||||
const DOMException = @import("../dom/exceptions.zig").DOMException;
|
||||
const EventTarget = @import("../dom/event_target.zig").EventTarget;
|
||||
@@ -33,6 +34,8 @@ const EventTargetUnion = @import("../dom/event_target.zig").Union;
|
||||
|
||||
const ProgressEvent = @import("../xhr/progress_event.zig").ProgressEvent;
|
||||
|
||||
const log = std.log.scoped(.events);
|
||||
|
||||
// Event interfaces
|
||||
pub const Interfaces = generate.Tuple(.{
|
||||
Event,
|
||||
@@ -236,3 +239,33 @@ pub fn testExecFn(
|
||||
};
|
||||
try checkCases(js_env, &remove);
|
||||
}
|
||||
|
||||
pub const EventHandler = struct {
|
||||
fn handle(event: ?*parser.Event, data: ?*anyopaque) callconv(.C) void {
|
||||
if (data) |d| {
|
||||
const func = parser.event_handler_cbk(d);
|
||||
|
||||
// TODO get the allocator by another way?
|
||||
var res = CallbackResult.init(func.nat_ctx.alloc);
|
||||
defer res.deinit();
|
||||
|
||||
if (event) |evt| {
|
||||
func.trycall(.{
|
||||
Event.toInterface(evt) catch unreachable,
|
||||
}, &res) catch |e| log.err("event handler error: {any}", .{e});
|
||||
} else {
|
||||
func.trycall(.{event}, &res) catch |e| log.err("event handler error: {any}", .{e});
|
||||
}
|
||||
|
||||
// in case of function error, we log the result and the trace.
|
||||
if (!res.success) {
|
||||
log.info("event handler error: {s}", .{res.result orelse "unknown"});
|
||||
log.debug("{s}", .{res.stack orelse "no stack trace"});
|
||||
}
|
||||
|
||||
// NOTE: we can not call func.deinit here
|
||||
// b/c the handler can be called several times
|
||||
// either on this dispatch event or in anoter one
|
||||
}
|
||||
}
|
||||
}.handle;
|
||||
|
||||
@@ -35,9 +35,9 @@ fn itoa(comptime i: u8) ![]const u8 {
|
||||
return try std.fmt.bufPrint(buf[0..], "{d}", .{i});
|
||||
}
|
||||
|
||||
fn fmtName(comptime T: type) []const u8 {
|
||||
fn fmtName(comptime T: type) [:0]const u8 {
|
||||
var it = std.mem.splitBackwards(u8, @typeName(T), ".");
|
||||
return it.first();
|
||||
return it.first() ++ "";
|
||||
}
|
||||
|
||||
// Union
|
||||
@@ -168,7 +168,11 @@ pub const Union = struct {
|
||||
T = *T;
|
||||
}
|
||||
union_fields[done] = .{
|
||||
.name = fmtName(member_T),
|
||||
// UnionField.name expect a null terminated string.
|
||||
// concatenate the `[]const u8` string with an empty string
|
||||
// literal (`name ++ ""`) to explicitly coerce it to `[:0]const
|
||||
// u8`.
|
||||
.name = fmtName(member_T) ++ "",
|
||||
.type = T,
|
||||
.alignment = @alignOf(T),
|
||||
};
|
||||
@@ -176,7 +180,7 @@ pub const Union = struct {
|
||||
}
|
||||
}
|
||||
const union_info = std.builtin.Type.Union{
|
||||
.layout = .Auto,
|
||||
.layout = .auto,
|
||||
.tag_type = enum_T,
|
||||
.fields = &union_fields,
|
||||
.decls = &decls,
|
||||
@@ -286,7 +290,11 @@ fn TupleT(comptime tuple: anytype) type {
|
||||
continue;
|
||||
}
|
||||
fields[done] = .{
|
||||
.name = try itoa(done),
|
||||
// StructField.name expect a null terminated string.
|
||||
// concatenate the `[]const u8` string with an empty string
|
||||
// literal (`name ++ ""`) to explicitly coerce it to `[:0]const
|
||||
// u8`.
|
||||
.name = try itoa(done) ++ "",
|
||||
.type = type,
|
||||
.default_value = null,
|
||||
.is_comptime = false,
|
||||
@@ -296,7 +304,7 @@ fn TupleT(comptime tuple: anytype) type {
|
||||
}
|
||||
const decls: [0]std.builtin.Type.Declaration = undefined;
|
||||
const info = std.builtin.Type.Struct{
|
||||
.layout = .Auto,
|
||||
.layout = .auto,
|
||||
.fields = &fields,
|
||||
.decls = &decls,
|
||||
.is_tuple = true,
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const parser = @import("../netsurf.zig");
|
||||
const parser = @import("netsurf");
|
||||
|
||||
const jsruntime = @import("jsruntime");
|
||||
const Case = jsruntime.test_utils.Case;
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
const std = @import("std");
|
||||
|
||||
const parser = @import("../netsurf.zig");
|
||||
const parser = @import("netsurf");
|
||||
const generate = @import("../generate.zig");
|
||||
|
||||
const jsruntime = @import("jsruntime");
|
||||
@@ -246,10 +246,10 @@ pub const HTMLAnchorElement = struct {
|
||||
defer u.deinit(alloc);
|
||||
|
||||
if (p) |pp| {
|
||||
u.uri.host = h;
|
||||
u.uri.host = .{ .raw = h };
|
||||
u.uri.port = pp;
|
||||
} else {
|
||||
u.uri.host = v;
|
||||
u.uri.host = .{ .raw = v };
|
||||
u.uri.port = null;
|
||||
}
|
||||
|
||||
@@ -271,7 +271,7 @@ pub const HTMLAnchorElement = struct {
|
||||
var u = try url(self, alloc);
|
||||
defer u.deinit(alloc);
|
||||
|
||||
u.uri.host = v;
|
||||
u.uri.host = .{ .raw = v };
|
||||
const href = try u.format(alloc);
|
||||
try parser.anchorSetHref(self, href);
|
||||
}
|
||||
@@ -312,7 +312,11 @@ pub const HTMLAnchorElement = struct {
|
||||
var u = try url(self, alloc);
|
||||
defer u.deinit(alloc);
|
||||
|
||||
u.uri.user = v;
|
||||
if (v) |vv| {
|
||||
u.uri.user = .{ .raw = vv };
|
||||
} else {
|
||||
u.uri.user = null;
|
||||
}
|
||||
const href = try u.format(alloc);
|
||||
defer alloc.free(href);
|
||||
|
||||
@@ -331,7 +335,11 @@ pub const HTMLAnchorElement = struct {
|
||||
var u = try url(self, alloc);
|
||||
defer u.deinit(alloc);
|
||||
|
||||
u.uri.password = v;
|
||||
if (v) |vv| {
|
||||
u.uri.password = .{ .raw = vv };
|
||||
} else {
|
||||
u.uri.password = null;
|
||||
}
|
||||
const href = try u.format(alloc);
|
||||
defer alloc.free(href);
|
||||
|
||||
@@ -350,7 +358,7 @@ pub const HTMLAnchorElement = struct {
|
||||
var u = try url(self, alloc);
|
||||
defer u.deinit(alloc);
|
||||
|
||||
u.uri.path = v;
|
||||
u.uri.path = .{ .raw = v };
|
||||
const href = try u.format(alloc);
|
||||
defer alloc.free(href);
|
||||
|
||||
@@ -369,7 +377,11 @@ pub const HTMLAnchorElement = struct {
|
||||
var u = try url(self, alloc);
|
||||
defer u.deinit(alloc);
|
||||
|
||||
u.uri.query = v;
|
||||
if (v) |vv| {
|
||||
u.uri.query = .{ .raw = vv };
|
||||
} else {
|
||||
u.uri.query = null;
|
||||
}
|
||||
const href = try u.format(alloc);
|
||||
defer alloc.free(href);
|
||||
|
||||
@@ -388,7 +400,11 @@ pub const HTMLAnchorElement = struct {
|
||||
var u = try url(self, alloc);
|
||||
defer u.deinit(alloc);
|
||||
|
||||
u.uri.fragment = v;
|
||||
if (v) |vv| {
|
||||
u.uri.fragment = .{ .raw = vv };
|
||||
} else {
|
||||
u.uri.fragment = null;
|
||||
}
|
||||
const href = try u.format(alloc);
|
||||
defer alloc.free(href);
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const parser = @import("../netsurf.zig");
|
||||
const parser = @import("netsurf");
|
||||
|
||||
const EventTarget = @import("../dom/event_target.zig").EventTarget;
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ const std = @import("std");
|
||||
|
||||
const jsruntime = @import("jsruntime");
|
||||
|
||||
const parser = @import("netsurf.zig");
|
||||
const parser = @import("netsurf");
|
||||
const apiweb = @import("apiweb.zig");
|
||||
const Window = @import("html/window.zig").Window;
|
||||
|
||||
@@ -30,7 +30,7 @@ pub const UserContext = apiweb.UserContext;
|
||||
const socket_path = "/tmp/browsercore-server.sock";
|
||||
|
||||
var doc: *parser.DocumentHTML = undefined;
|
||||
var server: std.net.StreamServer = undefined;
|
||||
var server: std.net.Server = undefined;
|
||||
|
||||
fn execJS(
|
||||
alloc: std.mem.Allocator,
|
||||
@@ -91,7 +91,7 @@ pub fn main() !void {
|
||||
// reuse_address (SO_REUSEADDR flag) does not seems to work on unix socket
|
||||
// see: https://gavv.net/articles/unix-socket-reuse/
|
||||
// TODO: use a lock file instead
|
||||
std.os.unlink(socket_path) catch |err| {
|
||||
std.posix.unlink(socket_path) catch |err| {
|
||||
if (err != error.FileNotFound) {
|
||||
return err;
|
||||
}
|
||||
@@ -99,9 +99,8 @@ pub fn main() !void {
|
||||
|
||||
// server
|
||||
const addr = try std.net.Address.initUnix(socket_path);
|
||||
server = std.net.StreamServer.init(.{});
|
||||
server = try addr.listen(.{});
|
||||
defer server.deinit();
|
||||
try server.listen(addr);
|
||||
std.debug.print("Listening on: {s}...\n", .{socket_path});
|
||||
|
||||
try jsruntime.loadEnv(&arena, null, execJS);
|
||||
|
||||
@@ -25,8 +25,8 @@ const apiweb = @import("apiweb.zig");
|
||||
pub const Types = jsruntime.reflect(apiweb.Interfaces);
|
||||
pub const UserContext = apiweb.UserContext;
|
||||
|
||||
pub const std_options = struct {
|
||||
pub const log_level = .debug;
|
||||
pub const std_options = std.Options{
|
||||
.log_level = .debug,
|
||||
};
|
||||
|
||||
const usage =
|
||||
@@ -58,7 +58,7 @@ pub fn main() !void {
|
||||
while (args.next()) |arg| {
|
||||
if (std.mem.eql(u8, "-h", arg) or std.mem.eql(u8, "--help", arg)) {
|
||||
try std.io.getStdErr().writer().print(usage, .{execname});
|
||||
std.os.exit(0);
|
||||
std.posix.exit(0);
|
||||
}
|
||||
if (std.mem.eql(u8, "--dump", arg)) {
|
||||
dump = true;
|
||||
@@ -67,14 +67,14 @@ pub fn main() !void {
|
||||
// allow only one url
|
||||
if (url.len != 0) {
|
||||
try std.io.getStdErr().writer().print(usage, .{execname});
|
||||
std.os.exit(1);
|
||||
std.posix.exit(1);
|
||||
}
|
||||
url = arg;
|
||||
}
|
||||
|
||||
if (url.len == 0) {
|
||||
try std.io.getStdErr().writer().print(usage, .{execname});
|
||||
std.os.exit(1);
|
||||
std.posix.exit(1);
|
||||
}
|
||||
|
||||
const vm = jsruntime.VM.init();
|
||||
|
||||
@@ -20,7 +20,7 @@ const std = @import("std");
|
||||
|
||||
const jsruntime = @import("jsruntime");
|
||||
|
||||
const parser = @import("netsurf.zig");
|
||||
const parser = @import("netsurf");
|
||||
const apiweb = @import("apiweb.zig");
|
||||
const Window = @import("html/window.zig").Window;
|
||||
const storage = @import("storage/storage.zig");
|
||||
|
||||
@@ -76,7 +76,7 @@ pub fn main() !void {
|
||||
while (args.next()) |arg| {
|
||||
if (std.mem.eql(u8, "-h", arg) or std.mem.eql(u8, "--help", arg)) {
|
||||
try std.io.getStdErr().writer().print(usage, .{execname});
|
||||
std.os.exit(0);
|
||||
std.posix.exit(0);
|
||||
}
|
||||
if (std.mem.eql(u8, "--json", arg)) {
|
||||
out = .json;
|
||||
@@ -214,12 +214,12 @@ pub fn main() !void {
|
||||
}
|
||||
|
||||
try std.json.stringify(output.items, .{ .whitespace = .indent_2 }, std.io.getStdOut().writer());
|
||||
std.os.exit(0);
|
||||
std.posix.exit(0);
|
||||
}
|
||||
|
||||
if (out == .text and failures > 0) {
|
||||
std.debug.print("{d}/{d} tests suites failures\n", .{ failures, run });
|
||||
std.os.exit(1);
|
||||
std.posix.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,13 +26,9 @@ const c = @cImport({
|
||||
@cInclude("events/event.h");
|
||||
});
|
||||
|
||||
const mimalloc = @import("mimalloc.zig");
|
||||
const mimalloc = @import("mimalloc");
|
||||
|
||||
const Callback = @import("jsruntime").Callback;
|
||||
const CallbackResult = @import("jsruntime").CallbackResult;
|
||||
const EventToInterface = @import("events/event.zig").Event.toInterface;
|
||||
|
||||
const log = std.log.scoped(.netsurf);
|
||||
|
||||
// init initializes netsurf lib.
|
||||
// init starts a mimalloc heap arena for the netsurf session. The caller must
|
||||
@@ -265,8 +261,8 @@ pub const Tag = enum(u8) {
|
||||
pub fn all() []Tag {
|
||||
comptime {
|
||||
const info = @typeInfo(Tag).Enum;
|
||||
comptime var l: [info.fields.len]Tag = undefined;
|
||||
inline for (info.fields, 0..) |field, i| {
|
||||
var l: [info.fields.len]Tag = undefined;
|
||||
for (info.fields, 0..) |field, i| {
|
||||
l[i] = @as(Tag, @enumFromInt(field.value));
|
||||
}
|
||||
return &l;
|
||||
@@ -277,7 +273,7 @@ pub const Tag = enum(u8) {
|
||||
comptime {
|
||||
const tags = all();
|
||||
var names: [tags.len][]const u8 = undefined;
|
||||
inline for (tags, 0..) |tag, i| {
|
||||
for (tags, 0..) |tag, i| {
|
||||
names[i] = tag.elementName();
|
||||
}
|
||||
return &names;
|
||||
@@ -527,41 +523,11 @@ pub const EventType = enum(u8) {
|
||||
};
|
||||
|
||||
// EventHandler
|
||||
fn event_handler_cbk(data: *anyopaque) *Callback {
|
||||
pub fn event_handler_cbk(data: *anyopaque) *Callback {
|
||||
const ptr: *align(@alignOf(*Callback)) anyopaque = @alignCast(data);
|
||||
return @as(*Callback, @ptrCast(ptr));
|
||||
}
|
||||
|
||||
const event_handler = struct {
|
||||
fn handle(event: ?*Event, data: ?*anyopaque) callconv(.C) void {
|
||||
if (data) |d| {
|
||||
const func = event_handler_cbk(d);
|
||||
|
||||
// TODO get the allocator by another way?
|
||||
var res = CallbackResult.init(func.nat_ctx.alloc);
|
||||
defer res.deinit();
|
||||
|
||||
if (event) |evt| {
|
||||
func.trycall(.{
|
||||
EventToInterface(evt) catch unreachable,
|
||||
}, &res) catch {};
|
||||
} else {
|
||||
func.trycall(.{event}, &res) catch {};
|
||||
}
|
||||
|
||||
// in case of function error, we log the result and the trace.
|
||||
if (!res.success) {
|
||||
log.info("event handler error: {s}", .{res.result orelse "unknown"});
|
||||
log.debug("{s}", .{res.stack orelse "no stack trace"});
|
||||
}
|
||||
|
||||
// NOTE: we can not call func.deinit here
|
||||
// b/c the handler can be called several times
|
||||
// either on this dispatch event or in anoter one
|
||||
}
|
||||
}
|
||||
}.handle;
|
||||
|
||||
// EventListener
|
||||
pub const EventListener = c.dom_event_listener;
|
||||
const EventListenerEntry = c.listener_entry;
|
||||
@@ -642,12 +608,15 @@ pub fn eventTargetHasListener(
|
||||
return null;
|
||||
}
|
||||
|
||||
const EventHandler = fn (event: ?*Event, data: ?*anyopaque) callconv(.C) void;
|
||||
|
||||
pub fn eventTargetAddEventListener(
|
||||
et: *EventTarget,
|
||||
alloc: std.mem.Allocator,
|
||||
typ: []const u8,
|
||||
cbk: Callback,
|
||||
capture: bool,
|
||||
handler: EventHandler,
|
||||
) !void {
|
||||
// this allocation will be removed either on
|
||||
// eventTargetRemoveEventListener or eventTargetRemoveAllEventListeners
|
||||
@@ -661,7 +630,7 @@ pub fn eventTargetAddEventListener(
|
||||
|
||||
const ctx = @as(*anyopaque, @ptrCast(cbk_ptr));
|
||||
var listener: ?*EventListener = undefined;
|
||||
const errLst = c.dom_event_listener_create(event_handler, ctx, &listener);
|
||||
const errLst = c.dom_event_listener_create(handler, ctx, &listener);
|
||||
try DOMErr(errLst);
|
||||
defer c.dom_event_listener_unref(listener);
|
||||
|
||||
@@ -23,7 +23,7 @@ const jsruntime = @import("jsruntime");
|
||||
const generate = @import("generate.zig");
|
||||
const pretty = @import("pretty");
|
||||
|
||||
const parser = @import("netsurf.zig");
|
||||
const parser = @import("netsurf");
|
||||
const apiweb = @import("apiweb.zig");
|
||||
const Window = @import("html/window.zig").Window;
|
||||
const xhr = @import("xhr/xhr.zig");
|
||||
@@ -182,7 +182,7 @@ pub fn main() !void {
|
||||
while (args.next()) |arg| {
|
||||
if (std.mem.eql(u8, "-h", arg) or std.mem.eql(u8, "--help", arg)) {
|
||||
try std.io.getStdErr().writer().print(usage, .{});
|
||||
std.os.exit(0);
|
||||
std.posix.exit(0);
|
||||
}
|
||||
if (std.mem.eql(u8, "--json", arg)) {
|
||||
out = .json;
|
||||
|
||||
@@ -23,7 +23,7 @@ const Case = jsruntime.test_utils.Case;
|
||||
const checkCases = jsruntime.test_utils.checkCases;
|
||||
const generate = @import("../generate.zig");
|
||||
|
||||
const DOMError = @import("../netsurf.zig").DOMError;
|
||||
const DOMError = @import("netsurf").DOMError;
|
||||
|
||||
const log = std.log.scoped(.storage);
|
||||
|
||||
|
||||
@@ -62,7 +62,10 @@ pub const URL = struct {
|
||||
return .{
|
||||
.rawuri = raw,
|
||||
.uri = uri,
|
||||
.search_params = try URLSearchParams.constructor(alloc, uri.query),
|
||||
.search_params = try URLSearchParams.constructor(
|
||||
alloc,
|
||||
uriComponentNullStr(uri.query),
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -102,7 +105,7 @@ pub const URL = struct {
|
||||
var q = std.ArrayList(u8).init(alloc);
|
||||
defer q.deinit();
|
||||
try self.search_params.values.encode(q.writer());
|
||||
self.uri.query = q.items;
|
||||
self.uri.query = .{ .percent_encoded = q.items };
|
||||
|
||||
return try self.format(alloc);
|
||||
}
|
||||
@@ -116,9 +119,9 @@ pub const URL = struct {
|
||||
.scheme = true,
|
||||
.authentication = true,
|
||||
.authority = true,
|
||||
.path = self.uri.path.len > 0,
|
||||
.query = self.uri.query != null and self.uri.query.?.len > 0,
|
||||
.fragment = self.uri.fragment != null and self.uri.fragment.?.len > 0,
|
||||
.path = uriComponentNullStr(self.uri.path).len > 0,
|
||||
.query = uriComponentNullStr(self.uri.query).len > 0,
|
||||
.fragment = uriComponentNullStr(self.uri.fragment).len > 0,
|
||||
}, buf.writer());
|
||||
return try buf.toOwnedSlice();
|
||||
}
|
||||
@@ -131,11 +134,11 @@ pub const URL = struct {
|
||||
}
|
||||
|
||||
pub fn get_username(self: *URL) []const u8 {
|
||||
return self.uri.user orelse "";
|
||||
return uriComponentNullStr(self.uri.user);
|
||||
}
|
||||
|
||||
pub fn get_password(self: *URL) []const u8 {
|
||||
return self.uri.password orelse "";
|
||||
return uriComponentNullStr(self.uri.password);
|
||||
}
|
||||
|
||||
// the caller must free the returned string.
|
||||
@@ -157,7 +160,7 @@ pub const URL = struct {
|
||||
}
|
||||
|
||||
pub fn get_hostname(self: *URL) []const u8 {
|
||||
return self.uri.host orelse "";
|
||||
return uriComponentNullStr(self.uri.host);
|
||||
}
|
||||
|
||||
// the caller must free the returned string.
|
||||
@@ -174,8 +177,8 @@ pub const URL = struct {
|
||||
}
|
||||
|
||||
pub fn get_pathname(self: *URL) []const u8 {
|
||||
if (self.uri.path.len == 0) return "/";
|
||||
return self.uri.path;
|
||||
if (uriComponentStr(self.uri.path).len == 0) return "/";
|
||||
return uriComponentStr(self.uri.path);
|
||||
}
|
||||
|
||||
// the caller must free the returned string.
|
||||
@@ -198,7 +201,7 @@ pub const URL = struct {
|
||||
pub fn get_hash(self: *URL, alloc: std.mem.Allocator) ![]const u8 {
|
||||
if (self.uri.fragment == null) return try alloc.dupe(u8, "");
|
||||
|
||||
return try std.mem.concat(alloc, u8, &[_][]const u8{ "#", self.uri.fragment.? });
|
||||
return try std.mem.concat(alloc, u8, &[_][]const u8{ "#", uriComponentNullStr(self.uri.fragment) });
|
||||
}
|
||||
|
||||
pub fn get_searchParams(self: *URL) *URLSearchParams {
|
||||
@@ -210,6 +213,21 @@ pub const URL = struct {
|
||||
}
|
||||
};
|
||||
|
||||
// uriComponentNullStr converts an optional std.Uri.Component to string value.
|
||||
// The string value can be undecoded.
|
||||
fn uriComponentNullStr(c: ?std.Uri.Component) []const u8 {
|
||||
if (c == null) return "";
|
||||
|
||||
return uriComponentStr(c.?);
|
||||
}
|
||||
|
||||
fn uriComponentStr(c: std.Uri.Component) []const u8 {
|
||||
return switch (c) {
|
||||
.raw => |v| v,
|
||||
.percent_encoded => |v| v,
|
||||
};
|
||||
}
|
||||
|
||||
// https://url.spec.whatwg.org/#interface-urlsearchparams
|
||||
// TODO array like
|
||||
pub const URLSearchParams = struct {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const std = @import("std");
|
||||
const parser = @import("netsurf.zig");
|
||||
const parser = @import("netsurf");
|
||||
const Client = @import("async/Client.zig");
|
||||
|
||||
pub const UserContext = struct {
|
||||
|
||||
@@ -21,7 +21,7 @@ const fspath = std.fs.path;
|
||||
|
||||
const FileLoader = @import("fileloader.zig").FileLoader;
|
||||
|
||||
const parser = @import("../netsurf.zig");
|
||||
const parser = @import("netsurf");
|
||||
|
||||
const jsruntime = @import("jsruntime");
|
||||
const Loop = jsruntime.Loop;
|
||||
|
||||
@@ -22,8 +22,9 @@ const jsruntime = @import("jsruntime");
|
||||
const Callback = jsruntime.Callback;
|
||||
|
||||
const EventTarget = @import("../dom/event_target.zig").EventTarget;
|
||||
const EventHandler = @import("../events/event.zig").EventHandler;
|
||||
|
||||
const parser = @import("../netsurf.zig");
|
||||
const parser = @import("netsurf");
|
||||
|
||||
const log = std.log.scoped(.xhr);
|
||||
|
||||
@@ -41,8 +42,20 @@ pub const XMLHttpRequestEventTarget = struct {
|
||||
ontimeout_cbk: ?Callback = null,
|
||||
onloadend_cbk: ?Callback = null,
|
||||
|
||||
fn register(self: *XMLHttpRequestEventTarget, alloc: std.mem.Allocator, typ: []const u8, cbk: Callback) !void {
|
||||
try parser.eventTargetAddEventListener(@as(*parser.EventTarget, @ptrCast(self)), alloc, typ, cbk, false);
|
||||
fn register(
|
||||
self: *XMLHttpRequestEventTarget,
|
||||
alloc: std.mem.Allocator,
|
||||
typ: []const u8,
|
||||
cbk: Callback,
|
||||
) !void {
|
||||
try parser.eventTargetAddEventListener(
|
||||
@as(*parser.EventTarget, @ptrCast(self)),
|
||||
alloc,
|
||||
typ,
|
||||
cbk,
|
||||
false,
|
||||
EventHandler,
|
||||
);
|
||||
}
|
||||
fn unregister(self: *XMLHttpRequestEventTarget, alloc: std.mem.Allocator, typ: []const u8, cbk: Callback) !void {
|
||||
const et = @as(*parser.EventTarget, @ptrCast(self));
|
||||
|
||||
@@ -22,7 +22,7 @@ const jsruntime = @import("jsruntime");
|
||||
const Case = jsruntime.test_utils.Case;
|
||||
const checkCases = jsruntime.test_utils.checkCases;
|
||||
|
||||
const parser = @import("../netsurf.zig");
|
||||
const parser = @import("netsurf");
|
||||
const Event = @import("../events/event.zig").Event;
|
||||
|
||||
const DOMException = @import("../dom/exceptions.zig").DOMException;
|
||||
|
||||
193
src/xhr/xhr.zig
193
src/xhr/xhr.zig
@@ -23,7 +23,7 @@ const Case = jsruntime.test_utils.Case;
|
||||
const checkCases = jsruntime.test_utils.checkCases;
|
||||
const generate = @import("../generate.zig");
|
||||
|
||||
const DOMError = @import("../netsurf.zig").DOMError;
|
||||
const DOMError = @import("netsurf").DOMError;
|
||||
const DOMException = @import("../dom/exceptions.zig").DOMException;
|
||||
|
||||
const ProgressEvent = @import("progress_event.zig").ProgressEvent;
|
||||
@@ -35,7 +35,7 @@ const Loop = jsruntime.Loop;
|
||||
const YieldImpl = Loop.Yield(XMLHttpRequest);
|
||||
const Client = @import("../async/Client.zig");
|
||||
|
||||
const parser = @import("../netsurf.zig");
|
||||
const parser = @import("netsurf");
|
||||
|
||||
const UserContext = @import("../user_context.zig").UserContext;
|
||||
|
||||
@@ -95,6 +95,50 @@ pub const XMLHttpRequestBodyInit = union(XMLHttpRequestBodyInitTag) {
|
||||
};
|
||||
|
||||
pub const XMLHttpRequest = struct {
|
||||
proto: XMLHttpRequestEventTarget = XMLHttpRequestEventTarget{},
|
||||
alloc: std.mem.Allocator,
|
||||
cli: *Client,
|
||||
impl: YieldImpl,
|
||||
|
||||
priv_state: PrivState = .new,
|
||||
req: ?Client.Request = null,
|
||||
|
||||
method: std.http.Method,
|
||||
state: u16,
|
||||
url: ?[]const u8,
|
||||
uri: std.Uri,
|
||||
// request headers
|
||||
headers: Headers,
|
||||
sync: bool = true,
|
||||
err: ?anyerror = null,
|
||||
|
||||
// TODO uncomment this field causes casting issue with
|
||||
// XMLHttpRequestEventTarget. I think it's dueto an alignement issue, but
|
||||
// not sure. see
|
||||
// https://lightpanda.slack.com/archives/C05TRU6RBM1/p1707819010681019
|
||||
// upload: ?XMLHttpRequestUpload = null,
|
||||
|
||||
// TODO uncomment this field causes casting issue with
|
||||
// XMLHttpRequestEventTarget. I think it's dueto an alignement issue, but
|
||||
// not sure. see
|
||||
// https://lightpanda.slack.com/archives/C05TRU6RBM1/p1707819010681019
|
||||
// timeout: u32 = 0,
|
||||
|
||||
withCredentials: bool = false,
|
||||
// TODO: response readonly attribute any response;
|
||||
response_bytes: ?[]const u8 = null,
|
||||
response_type: ResponseType = .Empty,
|
||||
response_headers: Headers,
|
||||
// used by zig client to parse reponse headers.
|
||||
response_header_buffer: [1024]u8 = undefined,
|
||||
response_status: u10 = 0,
|
||||
response_override_mime_type: ?[]const u8 = null,
|
||||
response_mime: Mime = undefined,
|
||||
response_obj: ?ResponseObj = null,
|
||||
send_flag: bool = false,
|
||||
|
||||
payload: ?[]const u8 = null,
|
||||
|
||||
pub const prototype = *XMLHttpRequestEventTarget;
|
||||
pub const mem_guarantied = true;
|
||||
|
||||
@@ -116,6 +160,91 @@ pub const XMLHttpRequest = struct {
|
||||
|
||||
const JSONValue = std.json.Value;
|
||||
|
||||
const Headers = struct {
|
||||
alloc: std.mem.Allocator,
|
||||
list: List,
|
||||
|
||||
const List = std.ArrayListUnmanaged(std.http.Header);
|
||||
|
||||
fn init(alloc: std.mem.Allocator) Headers {
|
||||
return .{
|
||||
.alloc = alloc,
|
||||
.list = List{},
|
||||
};
|
||||
}
|
||||
|
||||
fn deinit(self: *Headers) void {
|
||||
self.free();
|
||||
self.list.deinit(self.alloc);
|
||||
}
|
||||
|
||||
fn append(self: *Headers, k: []const u8, v: []const u8) !void {
|
||||
// duplicate strings
|
||||
const kk = try self.alloc.dupe(u8, k);
|
||||
const vv = try self.alloc.dupe(u8, v);
|
||||
try self.list.append(self.alloc, .{ .name = kk, .value = vv });
|
||||
}
|
||||
|
||||
// free all strings allocated.
|
||||
fn free(self: *Headers) void {
|
||||
for (self.list.items) |h| {
|
||||
self.alloc.free(h.name);
|
||||
self.alloc.free(h.value);
|
||||
}
|
||||
}
|
||||
|
||||
fn clearAndFree(self: *Headers) void {
|
||||
self.free();
|
||||
self.list.clearAndFree(self.alloc);
|
||||
}
|
||||
|
||||
fn has(self: Headers, k: []const u8) bool {
|
||||
for (self.list.items) |h| {
|
||||
if (std.ascii.eqlIgnoreCase(k, h.name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
fn getFirstValue(self: Headers, k: []const u8) ?[]const u8 {
|
||||
for (self.list.items) |h| {
|
||||
if (std.ascii.eqlIgnoreCase(k, h.name)) {
|
||||
return h.value;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// replace any existing header with the same key
|
||||
fn set(self: *Headers, k: []const u8, v: []const u8) !void {
|
||||
for (self.list.items, 0..) |h, i| {
|
||||
if (std.ascii.eqlIgnoreCase(k, h.name)) {
|
||||
const hh = self.list.swapRemove(i);
|
||||
self.alloc.free(hh.name);
|
||||
self.alloc.free(hh.value);
|
||||
}
|
||||
}
|
||||
self.append(k, v);
|
||||
}
|
||||
|
||||
// TODO
|
||||
fn sort(_: *Headers) void {}
|
||||
|
||||
fn all(self: Headers) []std.http.Header {
|
||||
return self.list.items;
|
||||
}
|
||||
|
||||
fn load(self: *Headers, it: *std.http.HeaderIterator) !void {
|
||||
while (true) {
|
||||
const h = it.next() orelse break;
|
||||
_ = try self.append(h.name, h.value);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const Response = union(ResponseType) {
|
||||
Empty: void,
|
||||
Text: []const u8,
|
||||
@@ -149,49 +278,13 @@ pub const XMLHttpRequest = struct {
|
||||
|
||||
const PrivState = enum { new, open, send, write, finish, wait, done };
|
||||
|
||||
proto: XMLHttpRequestEventTarget = XMLHttpRequestEventTarget{},
|
||||
alloc: std.mem.Allocator,
|
||||
cli: *Client,
|
||||
impl: YieldImpl,
|
||||
|
||||
priv_state: PrivState = .new,
|
||||
req: ?Client.Request = null,
|
||||
|
||||
method: std.http.Method,
|
||||
state: u16,
|
||||
url: ?[]const u8,
|
||||
uri: std.Uri,
|
||||
headers: std.http.Headers,
|
||||
sync: bool = true,
|
||||
err: ?anyerror = null,
|
||||
|
||||
// TODO uncomment this field causes casting issue with
|
||||
// XMLHttpRequestEventTarget. I think it's dueto an alignement issue, but
|
||||
// not sure. see
|
||||
// https://lightpanda.slack.com/archives/C05TRU6RBM1/p1707819010681019
|
||||
// upload: ?XMLHttpRequestUpload = null,
|
||||
|
||||
timeout: u32 = 0,
|
||||
withCredentials: bool = false,
|
||||
// TODO: response readonly attribute any response;
|
||||
response_bytes: ?[]const u8 = null,
|
||||
response_type: ResponseType = .Empty,
|
||||
response_headers: std.http.Headers,
|
||||
response_status: u10 = 0,
|
||||
response_override_mime_type: ?[]const u8 = null,
|
||||
response_mime: Mime = undefined,
|
||||
response_obj: ?ResponseObj = null,
|
||||
send_flag: bool = false,
|
||||
|
||||
payload: ?[]const u8 = null,
|
||||
|
||||
const min_delay: u64 = 50000000; // 50ms
|
||||
|
||||
pub fn constructor(alloc: std.mem.Allocator, loop: *Loop, userctx: UserContext) !XMLHttpRequest {
|
||||
return .{
|
||||
.alloc = alloc,
|
||||
.headers = .{ .allocator = alloc, .owned = true },
|
||||
.response_headers = .{ .allocator = alloc, .owned = true },
|
||||
.headers = Headers.init(alloc),
|
||||
.response_headers = Headers.init(alloc),
|
||||
.impl = YieldImpl.init(loop),
|
||||
.method = undefined,
|
||||
.url = null,
|
||||
@@ -242,16 +335,16 @@ pub const XMLHttpRequest = struct {
|
||||
return self.state;
|
||||
}
|
||||
|
||||
pub fn get_timeout(self: *XMLHttpRequest) u32 {
|
||||
return self.timeout;
|
||||
pub fn get_timeout(_: *XMLHttpRequest) u32 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
pub fn set_timeout(self: *XMLHttpRequest, timeout: u32) !void {
|
||||
// TODO, the value is ignored for now.
|
||||
pub fn set_timeout(_: *XMLHttpRequest, _: u32) !void {
|
||||
// TODO If the current global object is a Window object and this’s
|
||||
// synchronous flag is set, then throw an "InvalidAccessError"
|
||||
// DOMException.
|
||||
// https://xhr.spec.whatwg.org/#dom-xmlhttprequest-timeout
|
||||
self.timeout = timeout;
|
||||
}
|
||||
|
||||
pub fn get_withCredentials(self: *XMLHttpRequest) bool {
|
||||
@@ -385,7 +478,7 @@ pub const XMLHttpRequest = struct {
|
||||
const body_init = XMLHttpRequestBodyInit{ .String = body.? };
|
||||
|
||||
// keep the user content type from request headers.
|
||||
if (self.headers.getFirstEntry("Content-Type") == null) {
|
||||
if (self.headers.has("Content-Type")) {
|
||||
// https://fetch.spec.whatwg.org/#bodyinit-safely-extract
|
||||
try self.headers.append("Content-Type", try body_init.contentType());
|
||||
}
|
||||
@@ -411,14 +504,17 @@ pub const XMLHttpRequest = struct {
|
||||
switch (self.priv_state) {
|
||||
.new => {
|
||||
self.priv_state = .open;
|
||||
self.req = self.cli.open(self.method, self.uri, self.headers, .{}) catch |e| return self.onErr(e);
|
||||
self.req = self.cli.open(self.method, self.uri, .{
|
||||
.server_header_buffer = &self.response_header_buffer,
|
||||
.extra_headers = self.headers.all(),
|
||||
}) catch |e| return self.onErr(e);
|
||||
},
|
||||
.open => {
|
||||
// prepare payload transfert.
|
||||
if (self.payload) |v| self.req.?.transfer_encoding = .{ .content_length = v.len };
|
||||
|
||||
self.priv_state = .send;
|
||||
self.req.?.send(.{}) catch |e| return self.onErr(e);
|
||||
self.req.?.send() catch |e| return self.onErr(e);
|
||||
},
|
||||
.send => {
|
||||
if (self.payload) |payload| {
|
||||
@@ -441,7 +537,8 @@ pub const XMLHttpRequest = struct {
|
||||
log.info("{any} {any} {d}", .{ self.method, self.uri, self.req.?.response.status });
|
||||
|
||||
self.priv_state = .done;
|
||||
self.response_headers = self.req.?.response.headers.clone(self.response_headers.allocator) catch |e| return self.onErr(e);
|
||||
var it = self.req.?.response.iterateHeaders();
|
||||
self.response_headers.load(&it) catch |e| return self.onErr(e);
|
||||
|
||||
// extract a mime type from headers.
|
||||
const ct = self.response_headers.getFirstValue("Content-Type") orelse "text/xml";
|
||||
|
||||
2
vendor/zig-js-runtime
vendored
2
vendor/zig-js-runtime
vendored
Submodule vendor/zig-js-runtime updated: bb01609365...d491f04140
Reference in New Issue
Block a user