mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-28 22:53:28 +00:00
Merge pull request #1069 from lightpanda-io/response-gettype
Adds `Response.type`
This commit is contained in:
@@ -80,6 +80,27 @@ pub const RequestCredentials = enum {
|
||||
}
|
||||
};
|
||||
|
||||
pub const RequestMode = enum {
|
||||
cors,
|
||||
@"no-cors",
|
||||
@"same-origin",
|
||||
navigate,
|
||||
|
||||
pub fn fromString(str: []const u8) ?RequestMode {
|
||||
for (std.enums.values(RequestMode)) |cache| {
|
||||
if (std.ascii.eqlIgnoreCase(str, @tagName(cache))) {
|
||||
return cache;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn toString(self: RequestMode) []const u8 {
|
||||
return @tagName(self);
|
||||
}
|
||||
};
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/RequestInit
|
||||
pub const RequestInit = struct {
|
||||
body: ?[]const u8 = null,
|
||||
@@ -88,6 +109,7 @@ pub const RequestInit = struct {
|
||||
headers: ?HeadersInit = null,
|
||||
integrity: ?[]const u8 = null,
|
||||
method: ?[]const u8 = null,
|
||||
mode: ?[]const u8 = null,
|
||||
};
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/Request/Request
|
||||
@@ -97,6 +119,8 @@ method: Http.Method,
|
||||
url: [:0]const u8,
|
||||
cache: RequestCache,
|
||||
credentials: RequestCredentials,
|
||||
// no-cors is default is not built with constructor.
|
||||
mode: RequestMode = .@"no-cors",
|
||||
headers: Headers,
|
||||
body: ?[]const u8,
|
||||
body_used: bool = false,
|
||||
@@ -115,11 +139,11 @@ pub fn constructor(input: RequestInput, _options: ?RequestInit, page: *Page) !Re
|
||||
},
|
||||
};
|
||||
|
||||
const body = if (options.body) |body| try arena.dupe(u8, body) else null;
|
||||
const cache = (if (options.cache) |cache| RequestCache.fromString(cache) else null) orelse RequestCache.default;
|
||||
const credentials = (if (options.credentials) |creds| RequestCredentials.fromString(creds) else null) orelse RequestCredentials.@"same-origin";
|
||||
const integrity = if (options.integrity) |integ| try arena.dupe(u8, integ) else "";
|
||||
const headers: Headers = if (options.headers) |hdrs| try Headers.constructor(hdrs, page) else .{};
|
||||
const mode = (if (options.mode) |mode| RequestMode.fromString(mode) else null) orelse RequestMode.cors;
|
||||
|
||||
const method: Http.Method = blk: {
|
||||
if (options.method) |given_method| {
|
||||
@@ -135,11 +159,19 @@ pub fn constructor(input: RequestInput, _options: ?RequestInit, page: *Page) !Re
|
||||
}
|
||||
};
|
||||
|
||||
// Can't have a body on .GET or .HEAD.
|
||||
const body: ?[]const u8 = blk: {
|
||||
if (method == .GET or method == .HEAD) {
|
||||
break :blk null;
|
||||
} else break :blk if (options.body) |body| try arena.dupe(u8, body) else null;
|
||||
};
|
||||
|
||||
return .{
|
||||
.method = method,
|
||||
.url = url,
|
||||
.cache = cache,
|
||||
.credentials = credentials,
|
||||
.mode = mode,
|
||||
.headers = headers,
|
||||
.body = body,
|
||||
.integrity = integrity,
|
||||
@@ -181,6 +213,10 @@ pub fn get_method(self: *const Request) []const u8 {
|
||||
return @tagName(self.method);
|
||||
}
|
||||
|
||||
pub fn get_mode(self: *const Request) RequestMode {
|
||||
return self.mode;
|
||||
}
|
||||
|
||||
pub fn get_url(self: *const Request) []const u8 {
|
||||
return self.url;
|
||||
}
|
||||
@@ -210,10 +246,7 @@ pub fn _bytes(self: *Response, page: *Page) !Env.Promise {
|
||||
return error.TypeError;
|
||||
}
|
||||
|
||||
const resolver = Env.PromiseResolver{
|
||||
.js_context = page.main_context,
|
||||
.resolver = v8.PromiseResolver.init(page.main_context.v8_context),
|
||||
};
|
||||
const resolver = page.main_context.createPromiseResolver();
|
||||
|
||||
try resolver.resolve(self.body);
|
||||
self.body_used = true;
|
||||
@@ -225,22 +258,24 @@ pub fn _json(self: *Response, page: *Page) !Env.Promise {
|
||||
return error.TypeError;
|
||||
}
|
||||
|
||||
const resolver = Env.PromiseResolver{
|
||||
.js_context = page.main_context,
|
||||
.resolver = v8.PromiseResolver.init(page.main_context.v8_context),
|
||||
};
|
||||
const resolver = page.main_context.createPromiseResolver();
|
||||
|
||||
const p = std.json.parseFromSliceLeaky(
|
||||
std.json.Value,
|
||||
page.call_arena,
|
||||
self.body,
|
||||
.{},
|
||||
) catch |e| {
|
||||
log.info(.browser, "invalid json", .{ .err = e, .source = "Request" });
|
||||
return error.SyntaxError;
|
||||
};
|
||||
if (self.body) |body| {
|
||||
const p = std.json.parseFromSliceLeaky(
|
||||
std.json.Value,
|
||||
page.call_arena,
|
||||
body,
|
||||
.{},
|
||||
) catch |e| {
|
||||
log.info(.browser, "invalid json", .{ .err = e, .source = "Request" });
|
||||
return error.SyntaxError;
|
||||
};
|
||||
|
||||
try resolver.resolve(p);
|
||||
} else {
|
||||
try resolver.resolve(null);
|
||||
}
|
||||
|
||||
try resolver.resolve(p);
|
||||
self.body_used = true;
|
||||
return resolver.promise();
|
||||
}
|
||||
@@ -250,10 +285,7 @@ pub fn _text(self: *Response, page: *Page) !Env.Promise {
|
||||
return error.TypeError;
|
||||
}
|
||||
|
||||
const resolver = Env.PromiseResolver{
|
||||
.js_context = page.main_context,
|
||||
.resolver = v8.PromiseResolver.init(page.main_context.v8_context),
|
||||
};
|
||||
const resolver = page.main_context.createPromiseResolver();
|
||||
|
||||
try resolver.resolve(self.body);
|
||||
self.body_used = true;
|
||||
|
||||
@@ -41,9 +41,10 @@ status_text: []const u8 = "",
|
||||
headers: Headers,
|
||||
mime: ?Mime = null,
|
||||
url: []const u8 = "",
|
||||
body: []const u8 = "",
|
||||
body: ?[]const u8 = null,
|
||||
body_used: bool = false,
|
||||
redirected: bool = false,
|
||||
type: ResponseType = .basic,
|
||||
|
||||
const ResponseBody = union(enum) {
|
||||
string: []const u8,
|
||||
@@ -55,6 +56,28 @@ const ResponseOptions = struct {
|
||||
headers: ?HeadersInit = null,
|
||||
};
|
||||
|
||||
pub const ResponseType = enum {
|
||||
basic,
|
||||
cors,
|
||||
@"error",
|
||||
@"opaque",
|
||||
opaqueredirect,
|
||||
|
||||
pub fn fromString(str: []const u8) ?ResponseType {
|
||||
for (std.enums.values(ResponseType)) |cache| {
|
||||
if (std.ascii.eqlIgnoreCase(str, @tagName(cache))) {
|
||||
return cache;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn toString(self: ResponseType) []const u8 {
|
||||
return @tagName(self);
|
||||
}
|
||||
};
|
||||
|
||||
pub fn constructor(_input: ?ResponseBody, _options: ?ResponseOptions, page: *Page) !Response {
|
||||
const arena = page.arena;
|
||||
|
||||
@@ -68,7 +91,7 @@ pub fn constructor(_input: ?ResponseBody, _options: ?ResponseOptions, page: *Pag
|
||||
},
|
||||
}
|
||||
} else {
|
||||
break :blk "";
|
||||
break :blk null;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -85,7 +108,9 @@ pub fn constructor(_input: ?ResponseBody, _options: ?ResponseOptions, page: *Pag
|
||||
|
||||
pub fn get_body(self: *const Response, page: *Page) !*ReadableStream {
|
||||
const stream = try ReadableStream.constructor(null, null, page);
|
||||
try stream.queue.append(page.arena, self.body);
|
||||
if (self.body) |body| {
|
||||
try stream.queue.append(page.arena, body);
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
@@ -113,6 +138,10 @@ pub fn get_statusText(self: *const Response) []const u8 {
|
||||
return self.status_text;
|
||||
}
|
||||
|
||||
pub fn get_type(self: *const Response) ResponseType {
|
||||
return self.type;
|
||||
}
|
||||
|
||||
pub fn get_url(self: *const Response) []const u8 {
|
||||
return self.url;
|
||||
}
|
||||
@@ -132,6 +161,7 @@ pub fn _clone(self: *const Response) !Response {
|
||||
.redirected = self.redirected,
|
||||
.status = self.status,
|
||||
.url = self.url,
|
||||
.type = self.type,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -155,22 +185,24 @@ pub fn _json(self: *Response, page: *Page) !Env.Promise {
|
||||
return error.TypeError;
|
||||
}
|
||||
|
||||
const resolver = Env.PromiseResolver{
|
||||
.js_context = page.main_context,
|
||||
.resolver = v8.PromiseResolver.init(page.main_context.v8_context),
|
||||
};
|
||||
const resolver = page.main_context.createPromiseResolver();
|
||||
|
||||
const p = std.json.parseFromSliceLeaky(
|
||||
std.json.Value,
|
||||
page.call_arena,
|
||||
self.body,
|
||||
.{},
|
||||
) catch |e| {
|
||||
log.info(.browser, "invalid json", .{ .err = e, .source = "Response" });
|
||||
return error.SyntaxError;
|
||||
};
|
||||
if (self.body) |body| {
|
||||
const p = std.json.parseFromSliceLeaky(
|
||||
std.json.Value,
|
||||
page.call_arena,
|
||||
body,
|
||||
.{},
|
||||
) catch |e| {
|
||||
log.info(.browser, "invalid json", .{ .err = e, .source = "Response" });
|
||||
return error.SyntaxError;
|
||||
};
|
||||
|
||||
try resolver.resolve(p);
|
||||
} else {
|
||||
try resolver.resolve(null);
|
||||
}
|
||||
|
||||
try resolver.resolve(p);
|
||||
self.body_used = true;
|
||||
return resolver.promise();
|
||||
}
|
||||
@@ -180,10 +212,7 @@ pub fn _text(self: *Response, page: *Page) !Env.Promise {
|
||||
return error.TypeError;
|
||||
}
|
||||
|
||||
const resolver = Env.PromiseResolver{
|
||||
.js_context = page.main_context,
|
||||
.resolver = v8.PromiseResolver.init(page.main_context.v8_context),
|
||||
};
|
||||
const resolver = page.main_context.createPromiseResolver();
|
||||
|
||||
try resolver.resolve(self.body);
|
||||
self.body_used = true;
|
||||
|
||||
@@ -53,6 +53,7 @@ pub const FetchContext = struct {
|
||||
headers: std.ArrayListUnmanaged([]const u8) = .empty,
|
||||
status: u16 = 0,
|
||||
mime: ?Mime = null,
|
||||
mode: Request.RequestMode,
|
||||
transfer: ?*HttpClient.Transfer = null,
|
||||
|
||||
/// This effectively takes ownership of the FetchContext.
|
||||
@@ -62,6 +63,19 @@ pub const FetchContext = struct {
|
||||
pub fn toResponse(self: *const FetchContext) !Response {
|
||||
var headers: Headers = .{};
|
||||
|
||||
// If the mode is "no-cors", we need to return this opaque/stripped Response.
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/Response/type
|
||||
if (self.mode == .@"no-cors") {
|
||||
return Response{
|
||||
.status = 0,
|
||||
.headers = headers,
|
||||
.mime = self.mime,
|
||||
.body = null,
|
||||
.url = self.url,
|
||||
.type = .@"opaque",
|
||||
};
|
||||
}
|
||||
|
||||
// convert into Headers
|
||||
for (self.headers.items) |hdr| {
|
||||
var iter = std.mem.splitScalar(u8, hdr, ':');
|
||||
@@ -70,12 +84,25 @@ pub const FetchContext = struct {
|
||||
try headers.append(name, value, self.arena);
|
||||
}
|
||||
|
||||
const resp_type: Response.ResponseType = blk: {
|
||||
if (std.mem.startsWith(u8, self.url, "data:")) {
|
||||
break :blk .basic;
|
||||
}
|
||||
|
||||
break :blk switch (self.mode) {
|
||||
.cors => .cors,
|
||||
.@"same-origin", .navigate => .basic,
|
||||
.@"no-cors" => unreachable,
|
||||
};
|
||||
};
|
||||
|
||||
return Response{
|
||||
.status = self.status,
|
||||
.headers = headers,
|
||||
.mime = self.mime,
|
||||
.body = self.body.items,
|
||||
.url = self.url,
|
||||
.type = resp_type,
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -110,6 +137,7 @@ pub fn fetch(input: RequestInput, options: ?RequestInit, page: *Page) !Env.Promi
|
||||
.promise_resolver = resolver,
|
||||
.method = req.method,
|
||||
.url = req.url,
|
||||
.mode = req.mode,
|
||||
};
|
||||
|
||||
try page.http_client.request(.{
|
||||
|
||||
@@ -2843,7 +2843,7 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
|
||||
|
||||
const T = @TypeOf(value);
|
||||
switch (@typeInfo(T)) {
|
||||
.void, .bool, .int, .comptime_int, .float, .comptime_float, .@"enum" => {
|
||||
.void, .bool, .int, .comptime_int, .float, .comptime_float, .@"enum", .null => {
|
||||
// Need to do this to keep the compiler happy
|
||||
// simpleZigValueToJs handles all of these cases.
|
||||
unreachable;
|
||||
@@ -3634,6 +3634,7 @@ fn jsUnsignedIntToZig(comptime T: type, max: comptime_int, maybe: u32) !T {
|
||||
fn simpleZigValueToJs(isolate: v8.Isolate, value: anytype, comptime fail: bool) if (fail) v8.Value else ?v8.Value {
|
||||
switch (@typeInfo(@TypeOf(value))) {
|
||||
.void => return v8.initUndefined(isolate).toValue(),
|
||||
.null => return v8.initNull(isolate).toValue(),
|
||||
.bool => return v8.getValue(if (value) v8.initTrue(isolate) else v8.initFalse(isolate)),
|
||||
.int => |n| switch (n.signedness) {
|
||||
.signed => {
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user