xhr: fix implementation errors

This commit is contained in:
Pierre Tachoire
2024-01-31 14:40:55 +01:00
parent 8b6d7d0db0
commit c2bc48ba0f

View File

@@ -43,16 +43,25 @@ pub const XMLHttpRequestEventTarget = struct {
self.onprogress_cbk = handler; self.onprogress_cbk = handler;
} }
pub fn set_onabort(self: *XMLHttpRequestEventTarget, handler: Callback) void { pub fn set_onabort(self: *XMLHttpRequestEventTarget, handler: Callback) void {
self.onabort = handler; self.onabort_cbk = handler;
} }
pub fn set_onload(self: *XMLHttpRequestEventTarget, handler: Callback) void { pub fn set_onload(self: *XMLHttpRequestEventTarget, handler: Callback) void {
self.onload = handler; self.onload_cbk = handler;
} }
pub fn set_ontimeout(self: *XMLHttpRequestEventTarget, handler: Callback) void { pub fn set_ontimeout(self: *XMLHttpRequestEventTarget, handler: Callback) void {
self.ontimeout = handler; self.ontimeout_cbk = handler;
} }
pub fn set_onloadend(self: *XMLHttpRequestEventTarget, handler: Callback) void { pub fn set_onloadend(self: *XMLHttpRequestEventTarget, handler: Callback) void {
self.onloadend = handler; self.onloadend_cbk = handler;
}
pub fn deinit(self: *XMLHttpRequestEventTarget, alloc: std.mem.Allocator) void {
if (self.onloadstart_cbk) |cbk| cbk.deinit(alloc);
if (self.onprogress_cbk) |cbk| cbk.deinit(alloc);
if (self.onabort_cbk) |cbk| cbk.deinit(alloc);
if (self.onload_cbk) |cbk| cbk.deinit(alloc);
if (self.ontimeout_cbk) |cbk| cbk.deinit(alloc);
if (self.onloadend_cbk) |cbk| cbk.deinit(alloc);
} }
}; };
@@ -77,7 +86,8 @@ pub const XMLHttpRequest = struct {
cli: Client, cli: Client,
impl: YieldImpl, impl: YieldImpl,
readyState: u16 = UNSENT, readyState: u16,
url: ?[]const u8,
uri: std.Uri, uri: std.Uri,
headers: std.http.Headers, headers: std.http.Headers,
asyn: bool = true, asyn: bool = true,
@@ -89,7 +99,9 @@ pub const XMLHttpRequest = struct {
.proto = try XMLHttpRequestEventTarget.constructor(), .proto = try XMLHttpRequestEventTarget.constructor(),
.headers = .{ .allocator = alloc, .owned = false }, .headers = .{ .allocator = alloc, .owned = false },
.impl = undefined, .impl = undefined,
.url = null,
.uri = undefined, .uri = undefined,
.readyState = UNSENT,
// TODO retrieve the HTTP client globally to reuse existing connections. // TODO retrieve the HTTP client globally to reuse existing connections.
.cli = .{ .cli = .{
.allocator = alloc, .allocator = alloc,
@@ -101,7 +113,9 @@ pub const XMLHttpRequest = struct {
} }
pub fn deinit(self: *XMLHttpRequest, alloc: std.mem.Allocator) void { pub fn deinit(self: *XMLHttpRequest, alloc: std.mem.Allocator) void {
self.proto.deinit(alloc);
self.headers.deinit(); self.headers.deinit();
if (self.url) |url| alloc.free(url);
// TODO the client must be shared between requests. // TODO the client must be shared between requests.
self.cli.deinit(); self.cli.deinit();
alloc.destroy(self); alloc.destroy(self);
@@ -113,6 +127,7 @@ pub const XMLHttpRequest = struct {
pub fn _open( pub fn _open(
self: *XMLHttpRequest, self: *XMLHttpRequest,
alloc: std.mem.Allocator,
method: []const u8, method: []const u8,
url: []const u8, url: []const u8,
asyn: ?bool, asyn: ?bool,
@@ -128,8 +143,11 @@ pub const XMLHttpRequest = struct {
try validMethod(method); try validMethod(method);
self.uri = try std.Uri.parse(url); self.url = try alloc.dupe(u8, url);
self.uri = try std.Uri.parse(self.url.?);
self.asyn = if (asyn) |b| b else true; self.asyn = if (asyn) |b| b else true;
self.readyState = OPENED;
} }
const methods = [_][]const u8{ "DELETE", "GET", "HEAD", "OPTIONS", "POST", "PUT" }; const methods = [_][]const u8{ "DELETE", "GET", "HEAD", "OPTIONS", "POST", "PUT" };
@@ -166,14 +184,24 @@ pub const XMLHttpRequest = struct {
var req = self.cli.open(.GET, self.uri, self.headers, .{}) catch |e| return self.onerr(e); var req = self.cli.open(.GET, self.uri, self.headers, .{}) catch |e| return self.onerr(e);
defer req.deinit(); defer req.deinit();
self.readyState = OPENED;
req.send(.{}) catch |e| return self.onerr(e); req.send(.{}) catch |e| return self.onerr(e);
req.finish() catch |e| return self.onerr(e); req.finish() catch |e| return self.onerr(e);
req.wait() catch |e| return self.onerr(e); req.wait() catch |e| return self.onerr(e);
self.readyState = HEADERS_RECEIVED; self.readyState = HEADERS_RECEIVED;
// TODO read response body
self.readyState = LOADING; self.readyState = LOADING;
self.readyState = DONE; self.readyState = DONE;
// TODO use events instead
if (self.proto.onload_cbk) |cbk| {
// TODO pass an EventProgress
cbk.call(null) catch |e| {
std.debug.print("--- CALLBACK ERROR: {any}\n", .{e});
}; // TODO handle error
}
} }
}; };
@@ -182,17 +210,14 @@ pub fn testExecFn(
js_env: *jsruntime.Env, js_env: *jsruntime.Env,
) anyerror!void { ) anyerror!void {
var send = [_]Case{ var send = [_]Case{
.{ .src = .{ .src = "var nb = 0; function cbk(event) { nb ++; }", .ex = "undefined" },
\\var nb = 0; var evt; .{ .src = "const req = new XMLHttpRequest()", .ex = "undefined" },
\\function cbk(event) { .{ .src = "req.onload = cbk", .ex = "function cbk(event) { nb ++; }" },
\\ evt = event; .{ .src = "req.open('GET', 'https://w3.org')", .ex = "undefined" },
\\ nb ++; .{ .src = "req.send(); nb", .ex = "0" },
\\} // Each case executed waits for all loop callaback calls.
, .ex = "undefined" }, // So the url has been retrieved.
.{ .src = "const req = new XMLHttpRequest();", .ex = "undefined" }, .{ .src = "nb", .ex = "1" },
.{ .src = "req.onload = cbk; true;", .ex = "true" },
.{ .src = "req.open('GET', 'https://w3.org');", .ex = "undefined" },
.{ .src = "req.send();", .ex = "undefined" },
}; };
try checkCases(js_env, &send); try checkCases(js_env, &send);
} }