mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-29 07:03:29 +00:00
add support for 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
|
// https://developer.mozilla.org/en-US/docs/Web/API/RequestInit
|
||||||
pub const RequestInit = struct {
|
pub const RequestInit = struct {
|
||||||
body: ?[]const u8 = null,
|
body: ?[]const u8 = null,
|
||||||
@@ -88,6 +109,7 @@ pub const RequestInit = struct {
|
|||||||
headers: ?HeadersInit = null,
|
headers: ?HeadersInit = null,
|
||||||
integrity: ?[]const u8 = null,
|
integrity: ?[]const u8 = null,
|
||||||
method: ?[]const u8 = null,
|
method: ?[]const u8 = null,
|
||||||
|
mode: ?[]const u8 = null,
|
||||||
};
|
};
|
||||||
|
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/API/Request/Request
|
// https://developer.mozilla.org/en-US/docs/Web/API/Request/Request
|
||||||
@@ -97,6 +119,8 @@ method: Http.Method,
|
|||||||
url: [:0]const u8,
|
url: [:0]const u8,
|
||||||
cache: RequestCache,
|
cache: RequestCache,
|
||||||
credentials: RequestCredentials,
|
credentials: RequestCredentials,
|
||||||
|
// no-cors is default is not built with constructor.
|
||||||
|
mode: RequestMode = .@"no-cors",
|
||||||
headers: Headers,
|
headers: Headers,
|
||||||
body: ?[]const u8,
|
body: ?[]const u8,
|
||||||
body_used: bool = false,
|
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 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 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 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 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: {
|
const method: Http.Method = blk: {
|
||||||
if (options.method) |given_method| {
|
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 .{
|
return .{
|
||||||
.method = method,
|
.method = method,
|
||||||
.url = url,
|
.url = url,
|
||||||
.cache = cache,
|
.cache = cache,
|
||||||
.credentials = credentials,
|
.credentials = credentials,
|
||||||
|
.mode = mode,
|
||||||
.headers = headers,
|
.headers = headers,
|
||||||
.body = body,
|
.body = body,
|
||||||
.integrity = integrity,
|
.integrity = integrity,
|
||||||
@@ -181,6 +213,10 @@ pub fn get_method(self: *const Request) []const u8 {
|
|||||||
return @tagName(self.method);
|
return @tagName(self.method);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_mode(self: *const Request) RequestMode {
|
||||||
|
return self.mode;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_url(self: *const Request) []const u8 {
|
pub fn get_url(self: *const Request) []const u8 {
|
||||||
return self.url;
|
return self.url;
|
||||||
}
|
}
|
||||||
@@ -210,10 +246,7 @@ pub fn _bytes(self: *Response, page: *Page) !Env.Promise {
|
|||||||
return error.TypeError;
|
return error.TypeError;
|
||||||
}
|
}
|
||||||
|
|
||||||
const resolver = Env.PromiseResolver{
|
const resolver = page.main_context.createPromiseResolver();
|
||||||
.js_context = page.main_context,
|
|
||||||
.resolver = v8.PromiseResolver.init(page.main_context.v8_context),
|
|
||||||
};
|
|
||||||
|
|
||||||
try resolver.resolve(self.body);
|
try resolver.resolve(self.body);
|
||||||
self.body_used = true;
|
self.body_used = true;
|
||||||
@@ -225,22 +258,24 @@ pub fn _json(self: *Response, page: *Page) !Env.Promise {
|
|||||||
return error.TypeError;
|
return error.TypeError;
|
||||||
}
|
}
|
||||||
|
|
||||||
const resolver = Env.PromiseResolver{
|
const resolver = page.main_context.createPromiseResolver();
|
||||||
.js_context = page.main_context,
|
|
||||||
.resolver = v8.PromiseResolver.init(page.main_context.v8_context),
|
|
||||||
};
|
|
||||||
|
|
||||||
const p = std.json.parseFromSliceLeaky(
|
if (self.body) |body| {
|
||||||
std.json.Value,
|
const p = std.json.parseFromSliceLeaky(
|
||||||
page.call_arena,
|
std.json.Value,
|
||||||
self.body,
|
page.call_arena,
|
||||||
.{},
|
body,
|
||||||
) catch |e| {
|
.{},
|
||||||
log.info(.browser, "invalid json", .{ .err = e, .source = "Request" });
|
) catch |e| {
|
||||||
return error.SyntaxError;
|
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;
|
self.body_used = true;
|
||||||
return resolver.promise();
|
return resolver.promise();
|
||||||
}
|
}
|
||||||
@@ -250,10 +285,7 @@ pub fn _text(self: *Response, page: *Page) !Env.Promise {
|
|||||||
return error.TypeError;
|
return error.TypeError;
|
||||||
}
|
}
|
||||||
|
|
||||||
const resolver = Env.PromiseResolver{
|
const resolver = page.main_context.createPromiseResolver();
|
||||||
.js_context = page.main_context,
|
|
||||||
.resolver = v8.PromiseResolver.init(page.main_context.v8_context),
|
|
||||||
};
|
|
||||||
|
|
||||||
try resolver.resolve(self.body);
|
try resolver.resolve(self.body);
|
||||||
self.body_used = true;
|
self.body_used = true;
|
||||||
|
|||||||
@@ -41,9 +41,10 @@ status_text: []const u8 = "",
|
|||||||
headers: Headers,
|
headers: Headers,
|
||||||
mime: ?Mime = null,
|
mime: ?Mime = null,
|
||||||
url: []const u8 = "",
|
url: []const u8 = "",
|
||||||
body: []const u8 = "",
|
body: ?[]const u8 = null,
|
||||||
body_used: bool = false,
|
body_used: bool = false,
|
||||||
redirected: bool = false,
|
redirected: bool = false,
|
||||||
|
type: ResponseType = .basic,
|
||||||
|
|
||||||
const ResponseBody = union(enum) {
|
const ResponseBody = union(enum) {
|
||||||
string: []const u8,
|
string: []const u8,
|
||||||
@@ -55,6 +56,28 @@ const ResponseOptions = struct {
|
|||||||
headers: ?HeadersInit = null,
|
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 {
|
pub fn constructor(_input: ?ResponseBody, _options: ?ResponseOptions, page: *Page) !Response {
|
||||||
const arena = page.arena;
|
const arena = page.arena;
|
||||||
|
|
||||||
@@ -68,7 +91,7 @@ pub fn constructor(_input: ?ResponseBody, _options: ?ResponseOptions, page: *Pag
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else {
|
} 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 {
|
pub fn get_body(self: *const Response, page: *Page) !*ReadableStream {
|
||||||
const stream = try ReadableStream.constructor(null, null, page);
|
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;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,6 +138,10 @@ pub fn get_statusText(self: *const Response) []const u8 {
|
|||||||
return self.status_text;
|
return self.status_text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_type(self: *const Response) ResponseType {
|
||||||
|
return self.type;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_url(self: *const Response) []const u8 {
|
pub fn get_url(self: *const Response) []const u8 {
|
||||||
return self.url;
|
return self.url;
|
||||||
}
|
}
|
||||||
@@ -132,6 +161,7 @@ pub fn _clone(self: *const Response) !Response {
|
|||||||
.redirected = self.redirected,
|
.redirected = self.redirected,
|
||||||
.status = self.status,
|
.status = self.status,
|
||||||
.url = self.url,
|
.url = self.url,
|
||||||
|
.type = self.type,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,22 +185,24 @@ pub fn _json(self: *Response, page: *Page) !Env.Promise {
|
|||||||
return error.TypeError;
|
return error.TypeError;
|
||||||
}
|
}
|
||||||
|
|
||||||
const resolver = Env.PromiseResolver{
|
const resolver = page.main_context.createPromiseResolver();
|
||||||
.js_context = page.main_context,
|
|
||||||
.resolver = v8.PromiseResolver.init(page.main_context.v8_context),
|
|
||||||
};
|
|
||||||
|
|
||||||
const p = std.json.parseFromSliceLeaky(
|
if (self.body) |body| {
|
||||||
std.json.Value,
|
const p = std.json.parseFromSliceLeaky(
|
||||||
page.call_arena,
|
std.json.Value,
|
||||||
self.body,
|
page.call_arena,
|
||||||
.{},
|
body,
|
||||||
) catch |e| {
|
.{},
|
||||||
log.info(.browser, "invalid json", .{ .err = e, .source = "Response" });
|
) catch |e| {
|
||||||
return error.SyntaxError;
|
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;
|
self.body_used = true;
|
||||||
return resolver.promise();
|
return resolver.promise();
|
||||||
}
|
}
|
||||||
@@ -180,10 +212,7 @@ pub fn _text(self: *Response, page: *Page) !Env.Promise {
|
|||||||
return error.TypeError;
|
return error.TypeError;
|
||||||
}
|
}
|
||||||
|
|
||||||
const resolver = Env.PromiseResolver{
|
const resolver = page.main_context.createPromiseResolver();
|
||||||
.js_context = page.main_context,
|
|
||||||
.resolver = v8.PromiseResolver.init(page.main_context.v8_context),
|
|
||||||
};
|
|
||||||
|
|
||||||
try resolver.resolve(self.body);
|
try resolver.resolve(self.body);
|
||||||
self.body_used = true;
|
self.body_used = true;
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ pub const FetchContext = struct {
|
|||||||
headers: std.ArrayListUnmanaged([]const u8) = .empty,
|
headers: std.ArrayListUnmanaged([]const u8) = .empty,
|
||||||
status: u16 = 0,
|
status: u16 = 0,
|
||||||
mime: ?Mime = null,
|
mime: ?Mime = null,
|
||||||
|
mode: Request.RequestMode,
|
||||||
transfer: ?*HttpClient.Transfer = null,
|
transfer: ?*HttpClient.Transfer = null,
|
||||||
|
|
||||||
/// This effectively takes ownership of the FetchContext.
|
/// This effectively takes ownership of the FetchContext.
|
||||||
@@ -62,6 +63,19 @@ pub const FetchContext = struct {
|
|||||||
pub fn toResponse(self: *const FetchContext) !Response {
|
pub fn toResponse(self: *const FetchContext) !Response {
|
||||||
var headers: Headers = .{};
|
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
|
// convert into Headers
|
||||||
for (self.headers.items) |hdr| {
|
for (self.headers.items) |hdr| {
|
||||||
var iter = std.mem.splitScalar(u8, hdr, ':');
|
var iter = std.mem.splitScalar(u8, hdr, ':');
|
||||||
@@ -70,12 +84,25 @@ pub const FetchContext = struct {
|
|||||||
try headers.append(name, value, self.arena);
|
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{
|
return Response{
|
||||||
.status = self.status,
|
.status = self.status,
|
||||||
.headers = headers,
|
.headers = headers,
|
||||||
.mime = self.mime,
|
.mime = self.mime,
|
||||||
.body = self.body.items,
|
.body = self.body.items,
|
||||||
.url = self.url,
|
.url = self.url,
|
||||||
|
.type = resp_type,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -110,6 +137,7 @@ pub fn fetch(input: RequestInput, options: ?RequestInit, page: *Page) !Env.Promi
|
|||||||
.promise_resolver = resolver,
|
.promise_resolver = resolver,
|
||||||
.method = req.method,
|
.method = req.method,
|
||||||
.url = req.url,
|
.url = req.url,
|
||||||
|
.mode = req.mode,
|
||||||
};
|
};
|
||||||
|
|
||||||
try page.http_client.request(.{
|
try page.http_client.request(.{
|
||||||
|
|||||||
@@ -2843,7 +2843,7 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
|
|||||||
|
|
||||||
const T = @TypeOf(value);
|
const T = @TypeOf(value);
|
||||||
switch (@typeInfo(T)) {
|
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
|
// Need to do this to keep the compiler happy
|
||||||
// simpleZigValueToJs handles all of these cases.
|
// simpleZigValueToJs handles all of these cases.
|
||||||
unreachable;
|
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 {
|
fn simpleZigValueToJs(isolate: v8.Isolate, value: anytype, comptime fail: bool) if (fail) v8.Value else ?v8.Value {
|
||||||
switch (@typeInfo(@TypeOf(value))) {
|
switch (@typeInfo(@TypeOf(value))) {
|
||||||
.void => return v8.initUndefined(isolate).toValue(),
|
.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)),
|
.bool => return v8.getValue(if (value) v8.initTrue(isolate) else v8.initFalse(isolate)),
|
||||||
.int => |n| switch (n.signedness) {
|
.int => |n| switch (n.signedness) {
|
||||||
.signed => {
|
.signed => {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
testing.expectEqual("no-cache", response2.headers.get("cache-control"));
|
testing.expectEqual("no-cache", response2.headers.get("cache-control"));
|
||||||
|
|
||||||
let response3 = new Response("Created", { status: 201, statusText: "Created" });
|
let response3 = new Response("Created", { status: 201, statusText: "Created" });
|
||||||
|
testing.expectEqual("basic", response3.type);
|
||||||
testing.expectEqual(201, response3.status);
|
testing.expectEqual(201, response3.status);
|
||||||
testing.expectEqual("Created", response3.statusText);
|
testing.expectEqual("Created", response3.statusText);
|
||||||
testing.expectEqual(true, response3.ok);
|
testing.expectEqual(true, response3.ok);
|
||||||
|
|||||||
Reference in New Issue
Block a user