mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-29 23:23:28 +00:00
move fetch() into fetch.zig
This commit is contained in:
@@ -16,8 +16,166 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
const std = @import("std");
|
||||
const log = @import("../../log.zig");
|
||||
|
||||
const v8 = @import("v8");
|
||||
const Env = @import("../env.zig").Env;
|
||||
const Page = @import("../page.zig").Page;
|
||||
|
||||
const Http = @import("../../http/Http.zig");
|
||||
const HttpClient = @import("../../http/Client.zig");
|
||||
const Mime = @import("../mime.zig").Mime;
|
||||
|
||||
const RequestInput = @import("Request.zig").RequestInput;
|
||||
const RequestInit = @import("Request.zig").RequestInit;
|
||||
const Request = @import("Request.zig");
|
||||
const Response = @import("./Response.zig");
|
||||
|
||||
pub const Interfaces = .{
|
||||
@import("Headers.zig"),
|
||||
@import("Request.zig"),
|
||||
@import("Response.zig"),
|
||||
};
|
||||
|
||||
const FetchContext = struct {
|
||||
arena: std.mem.Allocator,
|
||||
js_ctx: *Env.JsContext,
|
||||
promise_resolver: v8.Persistent(v8.PromiseResolver),
|
||||
|
||||
method: Http.Method,
|
||||
url: []const u8,
|
||||
body: std.ArrayListUnmanaged(u8) = .empty,
|
||||
headers: std.ArrayListUnmanaged([]const u8) = .empty,
|
||||
status: u16 = 0,
|
||||
mime: ?Mime = null,
|
||||
transfer: ?*HttpClient.Transfer = null,
|
||||
|
||||
/// This effectively takes ownership of the FetchContext.
|
||||
///
|
||||
/// We just return the underlying slices used for `headers`
|
||||
/// and for `body` here to avoid an allocation.
|
||||
pub fn toResponse(self: *const FetchContext) !Response {
|
||||
return Response{
|
||||
.status = self.status,
|
||||
.headers = self.headers.items,
|
||||
.mime = self.mime,
|
||||
.body = self.body.items,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/Window/fetch
|
||||
pub fn fetch(input: RequestInput, options: ?RequestInit, page: *Page) !Env.Promise {
|
||||
const arena = page.arena;
|
||||
|
||||
const req = try Request.constructor(input, options, page);
|
||||
|
||||
const resolver = Env.PromiseResolver{
|
||||
.js_context = page.main_context,
|
||||
.resolver = v8.PromiseResolver.init(page.main_context.v8_context),
|
||||
};
|
||||
|
||||
var headers = try Http.Headers.init();
|
||||
try page.requestCookie(.{}).headersForRequest(arena, req.url, &headers);
|
||||
|
||||
const fetch_ctx = try arena.create(FetchContext);
|
||||
fetch_ctx.* = .{
|
||||
.arena = arena,
|
||||
.js_ctx = page.main_context,
|
||||
.promise_resolver = v8.Persistent(v8.PromiseResolver).init(
|
||||
page.main_context.isolate,
|
||||
resolver.resolver,
|
||||
),
|
||||
.method = req.method,
|
||||
.url = req.url,
|
||||
};
|
||||
|
||||
try page.http_client.request(.{
|
||||
.ctx = @ptrCast(fetch_ctx),
|
||||
.url = req.url,
|
||||
.method = req.method,
|
||||
.headers = headers,
|
||||
.body = req.body,
|
||||
.cookie_jar = page.cookie_jar,
|
||||
.resource_type = .fetch,
|
||||
|
||||
.start_callback = struct {
|
||||
fn startCallback(transfer: *HttpClient.Transfer) !void {
|
||||
const self: *FetchContext = @ptrCast(@alignCast(transfer.ctx));
|
||||
log.debug(.http, "request start", .{ .method = self.method, .url = self.url, .source = "fetch" });
|
||||
|
||||
self.transfer = transfer;
|
||||
}
|
||||
}.startCallback,
|
||||
.header_callback = struct {
|
||||
fn headerCallback(transfer: *HttpClient.Transfer) !void {
|
||||
const self: *FetchContext = @ptrCast(@alignCast(transfer.ctx));
|
||||
|
||||
const header = &transfer.response_header.?;
|
||||
|
||||
log.debug(.http, "request header", .{
|
||||
.source = "fetch",
|
||||
.method = self.method,
|
||||
.url = self.url,
|
||||
.status = header.status,
|
||||
});
|
||||
|
||||
if (header.contentType()) |ct| {
|
||||
self.mime = Mime.parse(ct) catch {
|
||||
return error.MimeParsing;
|
||||
};
|
||||
}
|
||||
|
||||
var it = transfer.responseHeaderIterator();
|
||||
while (it.next()) |hdr| {
|
||||
const joined = try std.fmt.allocPrint(self.arena, "{s}: {s}", .{ hdr.name, hdr.value });
|
||||
try self.headers.append(self.arena, joined);
|
||||
}
|
||||
|
||||
self.status = header.status;
|
||||
}
|
||||
}.headerCallback,
|
||||
.data_callback = struct {
|
||||
fn dataCallback(transfer: *HttpClient.Transfer, data: []const u8) !void {
|
||||
const self: *FetchContext = @ptrCast(@alignCast(transfer.ctx));
|
||||
try self.body.appendSlice(self.arena, data);
|
||||
}
|
||||
}.dataCallback,
|
||||
.done_callback = struct {
|
||||
fn doneCallback(ctx: *anyopaque) !void {
|
||||
const self: *FetchContext = @ptrCast(@alignCast(ctx));
|
||||
|
||||
log.info(.http, "request complete", .{
|
||||
.source = "fetch",
|
||||
.method = self.method,
|
||||
.url = self.url,
|
||||
.status = self.status,
|
||||
});
|
||||
|
||||
const response = try self.toResponse();
|
||||
const promise_resolver: Env.PromiseResolver = .{
|
||||
.js_context = self.js_ctx,
|
||||
.resolver = self.promise_resolver.castToPromiseResolver(),
|
||||
};
|
||||
|
||||
try promise_resolver.resolve(response);
|
||||
}
|
||||
}.doneCallback,
|
||||
.error_callback = struct {
|
||||
fn errorCallback(ctx: *anyopaque, err: anyerror) void {
|
||||
const self: *FetchContext = @ptrCast(@alignCast(ctx));
|
||||
|
||||
self.transfer = null;
|
||||
const promise_resolver: Env.PromiseResolver = .{
|
||||
.js_context = self.js_ctx,
|
||||
.resolver = self.promise_resolver.castToPromiseResolver(),
|
||||
};
|
||||
|
||||
promise_resolver.reject(@errorName(err)) catch unreachable;
|
||||
}
|
||||
}.errorCallback,
|
||||
});
|
||||
|
||||
return resolver.promise();
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ const JsObject = Env.JsObject;
|
||||
|
||||
const v8 = @import("v8");
|
||||
const Request = @import("../fetch/Request.zig");
|
||||
const fetchFn = @import("../fetch/fetch.zig").fetch;
|
||||
|
||||
const storage = @import("../storage/storage.zig");
|
||||
|
||||
@@ -99,7 +100,7 @@ pub const Window = struct {
|
||||
}
|
||||
|
||||
pub fn _fetch(_: *Window, input: Request.RequestInput, options: ?Request.RequestInit, page: *Page) !Env.Promise {
|
||||
return Request.fetch(input, options, page);
|
||||
return fetchFn(input, options, page);
|
||||
}
|
||||
|
||||
pub fn get_window(self: *Window) *Window {
|
||||
|
||||
Reference in New Issue
Block a user