mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-29 07:03:29 +00:00
expand Request/Response interfaces
This commit is contained in:
@@ -23,8 +23,8 @@ const URL = @import("../../url.zig").URL;
|
|||||||
const Page = @import("../page.zig").Page;
|
const Page = @import("../page.zig").Page;
|
||||||
|
|
||||||
const Response = @import("./Response.zig");
|
const Response = @import("./Response.zig");
|
||||||
|
|
||||||
const Http = @import("../../http/Http.zig");
|
const Http = @import("../../http/Http.zig");
|
||||||
|
const ReadableStream = @import("../streams/ReadableStream.zig");
|
||||||
|
|
||||||
const v8 = @import("v8");
|
const v8 = @import("v8");
|
||||||
const Env = @import("../env.zig").Env;
|
const Env = @import("../env.zig").Env;
|
||||||
@@ -37,12 +37,49 @@ pub const RequestInput = union(enum) {
|
|||||||
request: *Request,
|
request: *Request,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const RequestCache = enum {
|
||||||
|
default,
|
||||||
|
@"no-store",
|
||||||
|
reload,
|
||||||
|
@"no-cache",
|
||||||
|
@"force-cache",
|
||||||
|
@"only-if-cached",
|
||||||
|
|
||||||
|
pub fn fromString(str: []const u8) ?RequestCache {
|
||||||
|
for (std.enums.values(RequestCache)) |cache| {
|
||||||
|
if (std.ascii.eqlIgnoreCase(str, @tagName(cache))) {
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const RequestCredentials = enum {
|
||||||
|
omit,
|
||||||
|
@"same-origin",
|
||||||
|
include,
|
||||||
|
|
||||||
|
pub fn fromString(str: []const u8) ?RequestCredentials {
|
||||||
|
for (std.enums.values(RequestCredentials)) |cache| {
|
||||||
|
if (std.ascii.eqlIgnoreCase(str, @tagName(cache))) {
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 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 {
|
||||||
method: ?[]const u8 = null,
|
|
||||||
body: ?[]const u8 = null,
|
body: ?[]const u8 = null,
|
||||||
integrity: ?[]const u8 = null,
|
cache: ?[]const u8 = null,
|
||||||
|
credentials: ?[]const u8 = null,
|
||||||
headers: ?HeadersInit = null,
|
headers: ?HeadersInit = null,
|
||||||
|
integrity: ?[]const u8 = null,
|
||||||
|
method: ?[]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
|
||||||
@@ -50,6 +87,8 @@ const Request = @This();
|
|||||||
|
|
||||||
method: Http.Method,
|
method: Http.Method,
|
||||||
url: [:0]const u8,
|
url: [:0]const u8,
|
||||||
|
cache: RequestCache,
|
||||||
|
credentials: RequestCredentials,
|
||||||
headers: Headers,
|
headers: Headers,
|
||||||
body: ?[]const u8,
|
body: ?[]const u8,
|
||||||
body_used: bool = false,
|
body_used: bool = false,
|
||||||
@@ -68,6 +107,12 @@ 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 = if (options.headers) |hdrs| try Headers.constructor(hdrs, page) else Headers{};
|
||||||
|
|
||||||
const method: Http.Method = blk: {
|
const method: Http.Method = blk: {
|
||||||
if (options.method) |given_method| {
|
if (options.method) |given_method| {
|
||||||
for (std.enums.values(Http.Method)) |method| {
|
for (std.enums.values(Http.Method)) |method| {
|
||||||
@@ -82,27 +127,33 @@ pub fn constructor(input: RequestInput, _options: ?RequestInit, page: *Page) !Re
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const body = if (options.body) |body| try arena.dupe(u8, body) else null;
|
|
||||||
const integrity = if (options.integrity) |integ| try arena.dupe(u8, integ) else "";
|
|
||||||
const headers = if (options.headers) |hdrs| try Headers.constructor(hdrs, page) else Headers{};
|
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.method = method,
|
.method = method,
|
||||||
.url = url,
|
.url = url,
|
||||||
|
.cache = cache,
|
||||||
|
.credentials = credentials,
|
||||||
.headers = headers,
|
.headers = headers,
|
||||||
.body = body,
|
.body = body,
|
||||||
.integrity = integrity,
|
.integrity = integrity,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn get_body(self: *const Request) ?[]const u8 {
|
pub fn get_body(self: *const Request, page: *Page) !?*ReadableStream {
|
||||||
// return self.body;
|
if (self.body) |body| {
|
||||||
// }
|
const stream = try ReadableStream.constructor(null, null, page);
|
||||||
|
try stream.queue.append(page.arena, body);
|
||||||
|
return stream;
|
||||||
|
} else return null;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_bodyUsed(self: *const Request) bool {
|
pub fn get_bodyUsed(self: *const Request) bool {
|
||||||
return self.body_used;
|
return self.body_used;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_cache(self: *const Request) RequestCache {
|
||||||
|
return self.cache;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_headers(self: *Request) *Headers {
|
pub fn get_headers(self: *Request) *Headers {
|
||||||
return &self.headers;
|
return &self.headers;
|
||||||
}
|
}
|
||||||
@@ -133,6 +184,8 @@ pub fn _clone(self: *Request, page: *Page) !Request {
|
|||||||
return Request{
|
return Request{
|
||||||
.body = if (self.body) |body| try arena.dupe(u8, body) else null,
|
.body = if (self.body) |body| try arena.dupe(u8, body) else null,
|
||||||
.body_used = self.body_used,
|
.body_used = self.body_used,
|
||||||
|
.cache = self.cache,
|
||||||
|
.credentials = self.credentials,
|
||||||
.headers = try self.headers.clone(arena),
|
.headers = try self.headers.clone(arena),
|
||||||
.method = self.method,
|
.method = self.method,
|
||||||
.integrity = try arena.dupe(u8, self.integrity),
|
.integrity = try arena.dupe(u8, self.integrity),
|
||||||
|
|||||||
@@ -24,6 +24,11 @@ const v8 = @import("v8");
|
|||||||
const HttpClient = @import("../../http/Client.zig");
|
const HttpClient = @import("../../http/Client.zig");
|
||||||
const Http = @import("../../http/Http.zig");
|
const Http = @import("../../http/Http.zig");
|
||||||
const URL = @import("../../url.zig").URL;
|
const URL = @import("../../url.zig").URL;
|
||||||
|
|
||||||
|
const ReadableStream = @import("../streams/ReadableStream.zig");
|
||||||
|
const Headers = @import("Headers.zig");
|
||||||
|
const HeadersInit = @import("Headers.zig").HeadersInit;
|
||||||
|
|
||||||
const Env = @import("../env.zig").Env;
|
const Env = @import("../env.zig").Env;
|
||||||
const Mime = @import("../mime.zig").Mime;
|
const Mime = @import("../mime.zig").Mime;
|
||||||
const Page = @import("../page.zig").Page;
|
const Page = @import("../page.zig").Page;
|
||||||
@@ -32,26 +37,28 @@ const Page = @import("../page.zig").Page;
|
|||||||
const Response = @This();
|
const Response = @This();
|
||||||
|
|
||||||
status: u16 = 0,
|
status: u16 = 0,
|
||||||
headers: []const []const u8,
|
headers: Headers = .{},
|
||||||
mime: ?Mime = null,
|
mime: ?Mime = null,
|
||||||
body: []const u8,
|
url: []const u8 = "",
|
||||||
|
body: []const u8 = "",
|
||||||
body_used: bool = false,
|
body_used: bool = false,
|
||||||
redirected: bool = false,
|
redirected: bool = false,
|
||||||
|
|
||||||
const ResponseInput = union(enum) {
|
const ResponseBody = union(enum) {
|
||||||
string: []const u8,
|
string: []const u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
const ResponseOptions = struct {
|
const ResponseOptions = struct {
|
||||||
status: u16 = 200,
|
status: u16 = 200,
|
||||||
statusText: []const u8 = "",
|
statusText: []const u8 = "",
|
||||||
// List of header pairs.
|
headers: ?HeadersInit = null,
|
||||||
headers: []const []const u8 = &[][].{},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn constructor(_input: ?ResponseInput, page: *Page) !Response {
|
pub fn constructor(_input: ?ResponseBody, _options: ?ResponseOptions, page: *Page) !Response {
|
||||||
const arena = page.arena;
|
const arena = page.arena;
|
||||||
|
|
||||||
|
const options: ResponseOptions = _options orelse .{};
|
||||||
|
|
||||||
const body = blk: {
|
const body = blk: {
|
||||||
if (_input) |input| {
|
if (_input) |input| {
|
||||||
switch (input) {
|
switch (input) {
|
||||||
@@ -64,20 +71,32 @@ pub fn constructor(_input: ?ResponseInput, page: *Page) !Response {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const headers: Headers = if (options.headers) |hdrs| try Headers.constructor(hdrs, page) else .{};
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.body = body,
|
.body = body,
|
||||||
.headers = &[_][]const u8{},
|
.headers = headers,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_ok(self: *const Response) bool {
|
pub fn get_body(self: *const Response, page: *Page) !*ReadableStream {
|
||||||
return self.status >= 200 and self.status <= 299;
|
const stream = try ReadableStream.constructor(null, null, page);
|
||||||
|
try stream.queue.append(page.arena, self.body);
|
||||||
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_bodyUsed(self: *const Response) bool {
|
pub fn get_bodyUsed(self: *const Response) bool {
|
||||||
return self.body_used;
|
return self.body_used;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_headers(self: *Response) *Headers {
|
||||||
|
return &self.headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_ok(self: *const Response) bool {
|
||||||
|
return self.status >= 200 and self.status <= 299;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_redirected(self: *const Response) bool {
|
pub fn get_redirected(self: *const Response) bool {
|
||||||
return self.redirected;
|
return self.redirected;
|
||||||
}
|
}
|
||||||
@@ -86,6 +105,28 @@ pub fn get_status(self: *const Response) u16 {
|
|||||||
return self.status;
|
return self.status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_url(self: *const Response) []const u8 {
|
||||||
|
return self.url;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn _clone(self: *const Response, page: *Page) !Response {
|
||||||
|
if (self.body_used) {
|
||||||
|
return error.TypeError;
|
||||||
|
}
|
||||||
|
|
||||||
|
const arena = page.arena;
|
||||||
|
|
||||||
|
return Response{
|
||||||
|
.body = try arena.dupe(u8, self.body),
|
||||||
|
.body_used = self.body_used,
|
||||||
|
.mime = if (self.mime) |mime| try mime.clone(arena) else null,
|
||||||
|
.headers = try self.headers.clone(arena),
|
||||||
|
.redirected = self.redirected,
|
||||||
|
.status = self.status,
|
||||||
|
.url = try arena.dupe(u8, self.url),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub fn _bytes(self: *Response, page: *Page) !Env.Promise {
|
pub fn _bytes(self: *Response, page: *Page) !Env.Promise {
|
||||||
if (self.body_used) {
|
if (self.body_used) {
|
||||||
return error.TypeError;
|
return error.TypeError;
|
||||||
|
|||||||
@@ -290,6 +290,22 @@ pub const Mime = struct {
|
|||||||
fn trimRight(s: []const u8) []const u8 {
|
fn trimRight(s: []const u8) []const u8 {
|
||||||
return std.mem.trimRight(u8, s, &std.ascii.whitespace);
|
return std.mem.trimRight(u8, s, &std.ascii.whitespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn clone(self: *const Mime, allocator: Allocator) !Mime {
|
||||||
|
return Mime{
|
||||||
|
.content_type = blk: {
|
||||||
|
switch (self.content_type) {
|
||||||
|
.other => |data| break :blk ContentType{ .other = .{
|
||||||
|
.type = try allocator.dupe(u8, data.type),
|
||||||
|
.sub_type = try allocator.dupe(u8, data.sub_type),
|
||||||
|
} },
|
||||||
|
else => break :blk self.content_type,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.params = try allocator.dupe(u8, self.params),
|
||||||
|
.charset = if (self.charset) |charset| try allocator.dupeZ(u8, charset) else null,
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const testing = @import("../testing.zig");
|
const testing = @import("../testing.zig");
|
||||||
|
|||||||
@@ -34,11 +34,10 @@ const State = union(enum) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// This promise resolves when a stream is canceled.
|
// This promise resolves when a stream is canceled.
|
||||||
cancel_resolver: Env.PromiseResolver,
|
cancel_resolver: v8.Persistent(v8.PromiseResolver),
|
||||||
locked: bool = false,
|
locked: bool = false,
|
||||||
state: State = .readable,
|
state: State = .readable,
|
||||||
|
|
||||||
// A queue would be ideal here but I don't want to pay the cost of the priority operation.
|
|
||||||
queue: std.ArrayListUnmanaged([]const u8) = .empty,
|
queue: std.ArrayListUnmanaged([]const u8) = .empty,
|
||||||
|
|
||||||
const UnderlyingSource = struct {
|
const UnderlyingSource = struct {
|
||||||
@@ -56,10 +55,10 @@ const QueueingStrategy = struct {
|
|||||||
pub fn constructor(underlying: ?UnderlyingSource, strategy: ?QueueingStrategy, page: *Page) !*ReadableStream {
|
pub fn constructor(underlying: ?UnderlyingSource, strategy: ?QueueingStrategy, page: *Page) !*ReadableStream {
|
||||||
_ = strategy;
|
_ = strategy;
|
||||||
|
|
||||||
const cancel_resolver = Env.PromiseResolver{
|
const cancel_resolver = v8.Persistent(v8.PromiseResolver).init(
|
||||||
.js_context = page.main_context,
|
page.main_context.isolate,
|
||||||
.resolver = v8.PromiseResolver.init(page.main_context.v8_context),
|
v8.PromiseResolver.init(page.main_context.v8_context),
|
||||||
};
|
);
|
||||||
|
|
||||||
const stream = try page.arena.create(ReadableStream);
|
const stream = try page.arena.create(ReadableStream);
|
||||||
stream.* = ReadableStream{ .cancel_resolver = cancel_resolver };
|
stream.* = ReadableStream{ .cancel_resolver = cancel_resolver };
|
||||||
@@ -76,8 +75,13 @@ pub fn constructor(underlying: ?UnderlyingSource, strategy: ?QueueingStrategy, p
|
|||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn _cancel(self: *const ReadableStream) Env.Promise {
|
pub fn _cancel(self: *const ReadableStream, page: *Page) Env.Promise {
|
||||||
return self.cancel_resolver.promise();
|
const resolver = Env.PromiseResolver{
|
||||||
|
.js_context = page.main_context,
|
||||||
|
.resolver = self.cancel_resolver.castToPromiseResolver(),
|
||||||
|
};
|
||||||
|
|
||||||
|
return resolver.promise();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_locked(self: *const ReadableStream) bool {
|
pub fn get_locked(self: *const ReadableStream) bool {
|
||||||
|
|||||||
@@ -47,8 +47,8 @@ pub fn get_closed(self: *const ReadableStreamDefaultReader) Env.Promise {
|
|||||||
return self.closed_resolver.promise();
|
return self.closed_resolver.promise();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn _cancel(self: *ReadableStreamDefaultReader) Env.Promise {
|
pub fn _cancel(self: *ReadableStreamDefaultReader, page: *Page) Env.Promise {
|
||||||
return self.stream._cancel();
|
return self.stream._cancel(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const ReadableStreamReadResult = struct {
|
pub const ReadableStreamReadResult = struct {
|
||||||
|
|||||||
Reference in New Issue
Block a user