legacy for request/response/fetch

This commit is contained in:
Karl Seguin
2025-12-16 16:24:49 +08:00
parent ea399390ef
commit e47091f9a1
8 changed files with 149 additions and 9 deletions

View File

@@ -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)),

View File

@@ -1,9 +1,9 @@
<script src="../testing.js"></script>
<script id=fetch type=module>
const promise1 = new Promise((resolve) => {
fetch('http://127.0.0.1:9582/xhr/json')
fetch('http://127.0.0.1:9589/xhr/json')
.then((res) => {
testing.expectEqual('cors', res.type);
testing.expectEqual('basic', res.type);
return res.json()
})
.then((json) => {
@@ -18,7 +18,7 @@
<script id=same-origin type=module>
const promise1 = new Promise((resolve) => {
fetch('http://localhost:9582/xhr/json')
fetch('http://localhost:9589/xhr/json')
.then((res) => {
testing.expectEqual('basic', res.type);
return res.json()

View File

@@ -1,8 +1,9 @@
<!DOCTYPE html>
<script src="../testing.js"></script>
<script id=request>
let request = new Request("flower.png");
testing.expectEqual("http://localhost:9582/src/tests/fetch/flower.png", request.url);
testing.expectEqual("http://localhost:9589/fetch/flower.png", request.url);
testing.expectEqual("GET", request.method);
let request2 = new Request("https://google.com", {

View File

@@ -1,3 +1,4 @@
<!DOCTYPE html>
<script src="../testing.js"></script>
<script id=response>
@@ -11,8 +12,8 @@
let response2 = new Response("Error occurred", {
status: 404,
statusText: "Not Found",
headers: {
"Content-Type": "text/plain",
headers: {
"Content-Type": "text/plain",
"X-Custom": "test-value",
"Cache-Control": "no-cache"
}

View File

@@ -108,3 +108,25 @@
}
</script>
<script id=legacy>
{
let request = new Request("flower.png");
testing.expectEqual("http://127.0.0.1:9582/src/browser/tests/net/flower.png", request.url);
testing.expectEqual("GET", request.method);
let request2 = new Request("https://google.com", {
method: "POST",
body: "Hello, World",
cache: "reload",
credentials: "omit",
headers: { "Sender": "me", "Target": "you" }
}
);
testing.expectEqual("https://google.com", request2.url);
testing.expectEqual("POST", request2.method);
testing.expectEqual("omit", request2.credentials);
testing.expectEqual("reload", request2.cache);
testing.expectEqual("me", request2.headers.get("SeNdEr"));
testing.expectEqual("you", request2.headers.get("target"));
}
</script>

View File

@@ -0,0 +1,50 @@
<!DOCTYPE html>
<script src="../testing.js"></script>
<script id=response>
let response = new Response("Hello, World!");
testing.expectEqual(200, response.status);
testing.expectEqual("", response.statusText);
testing.expectEqual(true, response.ok);
testing.expectEqual("", response.url);
testing.expectEqual(false, response.redirected);
let response2 = new Response("Error occurred", {
status: 404,
statusText: "Not Found",
headers: {
"Content-Type": "text/plain",
"X-Custom": "test-value",
"Cache-Control": "no-cache"
}
});
testing.expectEqual(404, response2.status);
testing.expectEqual("Not Found", response2.statusText);
testing.expectEqual(false, response2.ok);
testing.expectEqual("text/plain", response2.headers.get("Content-Type"));
testing.expectEqual("test-value", response2.headers.get("X-Custom"));
testing.expectEqual("no-cache", response2.headers.get("cache-control"));
let response3 = new Response("Created", { status: 201, statusText: "Created" });
testing.expectEqual("basic", response3.type);
testing.expectEqual(201, response3.status);
testing.expectEqual("Created", response3.statusText);
testing.expectEqual(true, response3.ok);
let nullResponse = new Response(null);
testing.expectEqual(200, nullResponse.status);
testing.expectEqual("", nullResponse.statusText);
let emptyResponse = new Response("");
testing.expectEqual(200, emptyResponse.status);
</script>
<script id=json>
testing.async(async () => {
const json = await new Promise((resolve) => {
let response = new Response('[]');
response.json().then(resolve)
});
testing.expectEqual([], json);
});
</script>

View File

@@ -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");

View File

@@ -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", .{});
}