mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-29 07:03:29 +00:00
proper fetch method and body setting
This commit is contained in:
@@ -38,8 +38,8 @@ pub const RequestInput = union(enum) {
|
|||||||
|
|
||||||
// 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 = "GET",
|
method: ?[]const u8 = null,
|
||||||
body: []const u8 = "",
|
body: ?[]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
|
||||||
@@ -47,7 +47,7 @@ const Request = @This();
|
|||||||
|
|
||||||
method: Http.Method,
|
method: Http.Method,
|
||||||
url: [:0]const u8,
|
url: [:0]const u8,
|
||||||
body: []const u8,
|
body: ?[]const u8,
|
||||||
|
|
||||||
pub fn constructor(input: RequestInput, _options: ?RequestInit, page: *Page) !Request {
|
pub fn constructor(input: RequestInput, _options: ?RequestInit, page: *Page) !Request {
|
||||||
const arena = page.arena;
|
const arena = page.arena;
|
||||||
@@ -62,15 +62,21 @@ pub fn constructor(input: RequestInput, _options: ?RequestInit, page: *Page) !Re
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const method: Http.Method = blk: for (std.enums.values(Http.Method)) |method| {
|
const method: Http.Method = blk: {
|
||||||
if (std.ascii.eqlIgnoreCase(options.method, @tagName(method))) {
|
if (options.method) |given_method| {
|
||||||
break :blk method;
|
for (std.enums.values(Http.Method)) |method| {
|
||||||
|
if (std.ascii.eqlIgnoreCase(given_method, @tagName(method))) {
|
||||||
|
break :blk method;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return error.TypeError;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break :blk Http.Method.GET;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return error.InvalidMethod;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const body = try arena.dupe(u8, options.body);
|
const body = if (options.body) |body| try arena.dupe(u8, body) else null;
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.method = method,
|
.method = method,
|
||||||
@@ -87,9 +93,9 @@ pub fn get_method(self: *const Request) []const u8 {
|
|||||||
return @tagName(self.method);
|
return @tagName(self.method);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_body(self: *const Request) []const u8 {
|
// pub fn get_body(self: *const Request) ?[]const u8 {
|
||||||
return self.body;
|
// return self.body;
|
||||||
}
|
// }
|
||||||
|
|
||||||
const FetchContext = struct {
|
const FetchContext = struct {
|
||||||
arena: std.mem.Allocator,
|
arena: std.mem.Allocator,
|
||||||
@@ -123,13 +129,14 @@ pub fn fetch(input: RequestInput, options: ?RequestInit, page: *Page) !Env.Promi
|
|||||||
const arena = page.arena;
|
const arena = page.arena;
|
||||||
|
|
||||||
const req = try Request.constructor(input, options, page);
|
const req = try Request.constructor(input, options, page);
|
||||||
|
|
||||||
const resolver = Env.PromiseResolver{
|
const resolver = Env.PromiseResolver{
|
||||||
.js_context = page.main_context,
|
.js_context = page.main_context,
|
||||||
.resolver = v8.PromiseResolver.init(page.main_context.v8_context),
|
.resolver = v8.PromiseResolver.init(page.main_context.v8_context),
|
||||||
};
|
};
|
||||||
|
|
||||||
const client = page.http_client;
|
var headers = try Http.Headers.init();
|
||||||
const headers = try HttpClient.Headers.init();
|
try page.requestCookie(.{}).headersForRequest(arena, req.url, &headers);
|
||||||
|
|
||||||
const fetch_ctx = try arena.create(FetchContext);
|
const fetch_ctx = try arena.create(FetchContext);
|
||||||
fetch_ctx.* = .{
|
fetch_ctx.* = .{
|
||||||
@@ -143,47 +150,51 @@ pub fn fetch(input: RequestInput, options: ?RequestInit, page: *Page) !Env.Promi
|
|||||||
.url = req.url,
|
.url = req.url,
|
||||||
};
|
};
|
||||||
|
|
||||||
try client.request(.{
|
try page.http_client.request(.{
|
||||||
.method = req.method,
|
.ctx = @ptrCast(fetch_ctx),
|
||||||
.url = req.url,
|
.url = req.url,
|
||||||
|
.method = req.method,
|
||||||
.headers = headers,
|
.headers = headers,
|
||||||
.body = req.body,
|
.body = req.body,
|
||||||
.cookie_jar = page.cookie_jar,
|
.cookie_jar = page.cookie_jar,
|
||||||
.ctx = @ptrCast(fetch_ctx),
|
.resource_type = .fetch,
|
||||||
|
|
||||||
.start_callback = struct {
|
.start_callback = struct {
|
||||||
fn startCallback(transfer: *HttpClient.Transfer) !void {
|
fn startCallback(transfer: *HttpClient.Transfer) !void {
|
||||||
const self: *FetchContext = @alignCast(@ptrCast(transfer.ctx));
|
const self: *FetchContext = @alignCast(@ptrCast(transfer.ctx));
|
||||||
log.debug(.http, "request start", .{ .method = self.method, .url = self.url, .source = "fetch" });
|
log.debug(.http, "request start", .{ .method = self.method, .url = self.url, .source = "fetch" });
|
||||||
|
|
||||||
self.transfer = transfer;
|
self.transfer = transfer;
|
||||||
}
|
}
|
||||||
}.startCallback,
|
}.startCallback,
|
||||||
.header_callback = struct {
|
.header_callback = struct {
|
||||||
fn headerCallback(transfer: *HttpClient.Transfer, header: []const u8) !void {
|
fn headerCallback(transfer: *HttpClient.Transfer) !void {
|
||||||
const self: *FetchContext = @alignCast(@ptrCast(transfer.ctx));
|
|
||||||
try self.headers.append(self.arena, try self.arena.dupe(u8, header));
|
|
||||||
}
|
|
||||||
}.headerCallback,
|
|
||||||
.header_done_callback = struct {
|
|
||||||
fn headerDoneCallback(transfer: *HttpClient.Transfer) !void {
|
|
||||||
const self: *FetchContext = @alignCast(@ptrCast(transfer.ctx));
|
const self: *FetchContext = @alignCast(@ptrCast(transfer.ctx));
|
||||||
|
|
||||||
const header = &transfer.response_header.?;
|
const header = &transfer.response_header.?;
|
||||||
|
|
||||||
log.debug(.http, "request header", .{
|
log.debug(.http, "request header", .{
|
||||||
.source = "fetch",
|
.source = "fetch",
|
||||||
|
.method = self.method,
|
||||||
.url = self.url,
|
.url = self.url,
|
||||||
.status = header.status,
|
.status = header.status,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (header.contentType()) |ct| {
|
if (header.contentType()) |ct| {
|
||||||
self.mime = Mime.parse(ct) catch {
|
self.mime = Mime.parse(ct) catch {
|
||||||
return error.Todo;
|
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;
|
self.status = header.status;
|
||||||
}
|
}
|
||||||
}.headerDoneCallback,
|
}.headerCallback,
|
||||||
.data_callback = struct {
|
.data_callback = struct {
|
||||||
fn dataCallback(transfer: *HttpClient.Transfer, data: []const u8) !void {
|
fn dataCallback(transfer: *HttpClient.Transfer, data: []const u8) !void {
|
||||||
const self: *FetchContext = @alignCast(@ptrCast(transfer.ctx));
|
const self: *FetchContext = @alignCast(@ptrCast(transfer.ctx));
|
||||||
@@ -196,6 +207,7 @@ pub fn fetch(input: RequestInput, options: ?RequestInit, page: *Page) !Env.Promi
|
|||||||
|
|
||||||
log.info(.http, "request complete", .{
|
log.info(.http, "request complete", .{
|
||||||
.source = "fetch",
|
.source = "fetch",
|
||||||
|
.method = self.method,
|
||||||
.url = self.url,
|
.url = self.url,
|
||||||
.status = self.status,
|
.status = self.status,
|
||||||
});
|
});
|
||||||
@@ -212,6 +224,8 @@ pub fn fetch(input: RequestInput, options: ?RequestInit, page: *Page) !Env.Promi
|
|||||||
.error_callback = struct {
|
.error_callback = struct {
|
||||||
fn errorCallback(ctx: *anyopaque, err: anyerror) void {
|
fn errorCallback(ctx: *anyopaque, err: anyerror) void {
|
||||||
const self: *FetchContext = @alignCast(@ptrCast(ctx));
|
const self: *FetchContext = @alignCast(@ptrCast(ctx));
|
||||||
|
|
||||||
|
self.transfer = null;
|
||||||
const promise_resolver: Env.PromiseResolver = .{
|
const promise_resolver: Env.PromiseResolver = .{
|
||||||
.js_context = self.js_ctx,
|
.js_context = self.js_ctx,
|
||||||
.resolver = self.promise_resolver.castToPromiseResolver(),
|
.resolver = self.promise_resolver.castToPromiseResolver(),
|
||||||
|
|||||||
@@ -19,6 +19,9 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const URL = @import("../../url.zig").URL;
|
const URL = @import("../../url.zig").URL;
|
||||||
const Page = @import("../page.zig").Page;
|
const Page = @import("../page.zig").Page;
|
||||||
|
const Env = @import("../env.zig").Env;
|
||||||
|
|
||||||
|
const v8 = @import("v8");
|
||||||
|
|
||||||
const Http = @import("../../http/Http.zig");
|
const Http = @import("../../http/Http.zig");
|
||||||
const HttpClient = @import("../../http/Client.zig");
|
const HttpClient = @import("../../http/Client.zig");
|
||||||
@@ -36,13 +39,26 @@ const ResponseInput = union(enum) {
|
|||||||
string: []const u8,
|
string: []const u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn constructor(input: ResponseInput, page: *Page) !Response {
|
const ResponseOptions = struct {
|
||||||
|
status: u16 = 200,
|
||||||
|
statusText: []const u8 = "",
|
||||||
|
// List of header pairs.
|
||||||
|
headers: []const []const u8 = &[][].{},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn constructor(_input: ?ResponseInput, page: *Page) !Response {
|
||||||
const arena = page.arena;
|
const arena = page.arena;
|
||||||
|
|
||||||
const body = blk: switch (input) {
|
const body = blk: {
|
||||||
.string => |str| {
|
if (_input) |input| {
|
||||||
break :blk try arena.dupe(u8, str);
|
switch (input) {
|
||||||
},
|
.string => |str| {
|
||||||
|
break :blk try arena.dupe(u8, str);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break :blk "";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
@@ -55,6 +71,16 @@ pub fn get_ok(self: *const Response) bool {
|
|||||||
return self.status >= 200 and self.status <= 299;
|
return self.status >= 200 and self.status <= 299;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn _text(self: *const Response, page: *Page) !Env.Promise {
|
||||||
|
const resolver = Env.PromiseResolver{
|
||||||
|
.js_context = page.main_context,
|
||||||
|
.resolver = v8.PromiseResolver.init(page.main_context.v8_context),
|
||||||
|
};
|
||||||
|
|
||||||
|
try resolver.resolve(self.body);
|
||||||
|
return resolver.promise();
|
||||||
|
}
|
||||||
|
|
||||||
const testing = @import("../../testing.zig");
|
const testing = @import("../../testing.zig");
|
||||||
test "fetch: response" {
|
test "fetch: response" {
|
||||||
var runner = try testing.jsRunner(testing.tracking_allocator, .{ .url = "https://lightpanda.io" });
|
var runner = try testing.jsRunner(testing.tracking_allocator, .{ .url = "https://lightpanda.io" });
|
||||||
|
|||||||
@@ -200,6 +200,7 @@ pub fn requestIntercept(arena: Allocator, bc: anytype, intercept: *const Notific
|
|||||||
.script => "Script",
|
.script => "Script",
|
||||||
.xhr => "XHR",
|
.xhr => "XHR",
|
||||||
.document => "Document",
|
.document => "Document",
|
||||||
|
.fetch => "Fetch",
|
||||||
},
|
},
|
||||||
.networkId = try std.fmt.allocPrint(arena, "REQ-{d}", .{transfer.id}),
|
.networkId = try std.fmt.allocPrint(arena, "REQ-{d}", .{transfer.id}),
|
||||||
}, .{ .session_id = session_id });
|
}, .{ .session_id = session_id });
|
||||||
|
|||||||
@@ -649,6 +649,7 @@ pub const Request = struct {
|
|||||||
document,
|
document,
|
||||||
xhr,
|
xhr,
|
||||||
script,
|
script,
|
||||||
|
fetch,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user