From e47091f9a144b371eded522b1a495dd2ee8c445c Mon Sep 17 00:00:00 2001 From: Karl Seguin Date: Tue, 16 Dec 2025 16:24:49 +0800 Subject: [PATCH] legacy for request/response/fetch --- src/browser/js/Context.zig | 6 +++ src/browser/tests/legacy/fetch/fetch.html | 6 +-- src/browser/tests/legacy/fetch/request.html | 3 +- src/browser/tests/legacy/fetch/response.html | 5 +- src/browser/tests/net/request.html | 22 +++++++++ src/browser/tests/net/response.html | 50 ++++++++++++++++++++ src/browser/webapi/net/Request.zig | 33 +++++++++++++ src/browser/webapi/net/Response.zig | 33 +++++++++++-- 8 files changed, 149 insertions(+), 9 deletions(-) create mode 100644 src/browser/tests/net/response.html diff --git a/src/browser/js/Context.zig b/src/browser/js/Context.zig index dc297b21..1273a4b7 100644 --- a/src/browser/js/Context.zig +++ b/src/browser/js/Context.zig @@ -807,6 +807,12 @@ pub fn jsValueToZig(self: *Context, comptime T: type, js_value: v8.Value) !T { unreachable; }, .@"enum" => |e| { + if (@hasDecl(T, "js_enum_from_string")) { + if (!js_value.isString()) { + return error.InvalidArgument; + } + return std.meta.stringToEnum(T, try self.valueToString(js_value, .{})) orelse return error.InvalidArgument; + } switch (@typeInfo(e.tag_type)) { .int => return std.meta.intToEnum(T, try jsIntToZig(e.tag_type, js_value, self.v8_context)), else => @compileError("unsupported enum parameter type: " ++ @typeName(T)), diff --git a/src/browser/tests/legacy/fetch/fetch.html b/src/browser/tests/legacy/fetch/fetch.html index 877f887b..5e4a46e0 100644 --- a/src/browser/tests/legacy/fetch/fetch.html +++ b/src/browser/tests/legacy/fetch/fetch.html @@ -1,9 +1,9 @@ + diff --git a/src/browser/tests/net/response.html b/src/browser/tests/net/response.html new file mode 100644 index 00000000..c632c3ff --- /dev/null +++ b/src/browser/tests/net/response.html @@ -0,0 +1,50 @@ + + + + + + diff --git a/src/browser/webapi/net/Request.zig b/src/browser/webapi/net/Request.zig index d053b434..235773d7 100644 --- a/src/browser/webapi/net/Request.zig +++ b/src/browser/webapi/net/Request.zig @@ -33,6 +33,8 @@ _method: Http.Method, _headers: ?*Headers, _body: ?[]const u8, _arena: Allocator, +_cache: Cache, +_credentials: Credentials, pub const Input = union(enum) { request: *Request, @@ -43,6 +45,25 @@ pub const InitOpts = struct { method: ?[]const u8 = null, headers: ?Headers.InitOpts = null, body: ?[]const u8 = null, + cache: Cache = .default, + credentials: Credentials = .@"same-origin", +}; + +const Credentials = enum { + omit, + include, + @"same-origin", + pub const js_enum_from_string = true; +}; + +const Cache = enum { + default, + @"no-store", + @"reload", + @"no-cache", + @"force-cache", + @"only-if-cached", + pub const js_enum_from_string = true; }; pub fn init(input: Input, opts_: ?InitOpts, page: *Page) !*Request { @@ -80,6 +101,8 @@ pub fn init(input: Input, opts_: ?InitOpts, page: *Page) !*Request { ._arena = arena, ._method = method, ._headers = headers, + ._cache = opts.cache, + ._credentials = opts.credentials, ._body = body, }); } @@ -111,6 +134,14 @@ pub fn getMethod(self: *const Request) []const u8 { return @tagName(self._method); } +pub fn getCache(self: *const Request) []const u8 { + return @tagName(self._cache); +} + +pub fn getCredentials(self: *const Request) []const u8 { + return @tagName(self._credentials); +} + pub fn getHeaders(self: *Request, page: *Page) !*Headers { if (self._headers) |headers| { return headers; @@ -134,6 +165,8 @@ pub const JsApi = struct { pub const url = bridge.accessor(Request.getUrl, null, .{}); pub const method = bridge.accessor(Request.getMethod, null, .{}); pub const headers = bridge.accessor(Request.getHeaders, null, .{}); + pub const cache = bridge.accessor(Request.getCache, null, .{}); + pub const credentials = bridge.accessor(Request.getCredentials, null, .{}); }; const testing = @import("../../../testing.zig"); diff --git a/src/browser/webapi/net/Response.zig b/src/browser/webapi/net/Response.zig index dffa4c60..68dd8ed7 100644 --- a/src/browser/webapi/net/Response.zig +++ b/src/browser/webapi/net/Response.zig @@ -39,10 +39,11 @@ _arena: Allocator, _headers: *Headers, _body: ?[]const u8, _type: Type, +_status_text: []const u8, const InitOpts = struct { status: u16 = 200, - headers: ?*Headers = null, + headers: ?Headers.InitOpts = null, statusText: ?[]const u8 = null, }; @@ -51,13 +52,15 @@ pub fn init(body_: ?[]const u8, opts_: ?InitOpts, page: *Page) !*Response { // Store empty string as empty string, not null const body = if (body_) |b| try page.arena.dupe(u8, b) else null; + const status_text = if (opts.statusText) |st| try page.dupeString(st) else ""; return page._factory.create(Response{ ._arena = page.arena, ._status = opts.status, + ._status_text = status_text, ._body = body, - ._headers = opts.headers orelse try Headers.init(null, page), - ._type = .basic, // @ZIGDOM: todo + ._type = .basic, + ._headers = try Headers.init(opts.headers, page), }); } @@ -65,6 +68,21 @@ pub fn getStatus(self: *const Response) u16 { return self._status; } +pub fn getStatusText(self: *const Response) []const u8 { + // This property is meant to actually capture the response status text, not + // just return the text representation of self._status. If we do, + // new Response(null, {status: 200}).statusText, we should get empty string. + return self._status_text; +} + +pub fn getURL(_: *const Response) []const u8 { + return ""; +} + +pub fn isRedirected(_: *const Response) bool { + return false; +} + pub fn getHeaders(self: *const Response) *Headers { return self._headers; } @@ -90,6 +108,7 @@ pub fn isOK(self: *const Response) bool { return self._status >= 200 and self._status <= 299; } + pub fn getText(self: *const Response, page: *Page) !js.Promise { const body = self._body orelse ""; return page.js.resolvePromise(body); @@ -120,9 +139,17 @@ pub const JsApi = struct { pub const constructor = bridge.constructor(Response.init, .{}); pub const ok = bridge.accessor(Response.isOK, null, .{}); pub const status = bridge.accessor(Response.getStatus, null, .{}); + pub const statusText = bridge.accessor(Response.getStatusText, null, .{}); pub const @"type" = bridge.accessor(Response.getType, null, .{}); pub const text = bridge.function(Response.getText, .{}); pub const json = bridge.function(Response.getJson, .{}); pub const headers = bridge.accessor(Response.getHeaders, null, .{}); pub const body = bridge.accessor(Response.getBody, null, .{}); + pub const url = bridge.accessor(Response.getURL, null, .{}); + pub const redirected = bridge.accessor(Response.isRedirected, null, .{}); }; + +const testing = @import("../../../testing.zig"); +test "WebApi: Response" { + try testing.htmlRunner("net/response.html", .{}); +}