mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-03-22 04:34:44 +00:00
Add support for XHR's withCredentials
XHR should only send and receive cookies for same-origin requests or if withCredentials is true.
This commit is contained in:
@@ -197,6 +197,7 @@ pub const Accessor = struct {
|
||||
cache: ?[]const u8 = null,
|
||||
as_typed_array: bool = false,
|
||||
null_as_undefined: bool = false,
|
||||
dom_exception: bool = false,
|
||||
};
|
||||
|
||||
fn init(comptime T: type, comptime getter: anytype, comptime setter: anytype, comptime opts: Opts) Accessor {
|
||||
@@ -215,12 +216,14 @@ pub const Accessor = struct {
|
||||
if (comptime opts.static) {
|
||||
caller.function(T, getter, handle.?, .{
|
||||
.cache = opts.cache,
|
||||
.dom_exception = opts.dom_exception,
|
||||
.as_typed_array = opts.as_typed_array,
|
||||
.null_as_undefined = opts.null_as_undefined,
|
||||
});
|
||||
} else {
|
||||
caller.method(T, getter, handle.?, .{
|
||||
.cache = opts.cache,
|
||||
.dom_exception = opts.dom_exception,
|
||||
.as_typed_array = opts.as_typed_array,
|
||||
.null_as_undefined = opts.null_as_undefined,
|
||||
});
|
||||
|
||||
@@ -56,6 +56,7 @@ _response_type: ResponseType = .text,
|
||||
|
||||
_ready_state: ReadyState = .unsent,
|
||||
_on_ready_state_change: ?js.Function.Temp = null,
|
||||
_with_credentials: bool = false,
|
||||
|
||||
const ReadyState = enum(u8) {
|
||||
unsent = 0,
|
||||
@@ -150,6 +151,17 @@ pub fn setOnReadyStateChange(self: *XMLHttpRequest, cb_: ?js.Function) !void {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getWithCredentials(self: *const XMLHttpRequest) bool {
|
||||
return self._with_credentials;
|
||||
}
|
||||
|
||||
pub fn setWithCredentials(self: *XMLHttpRequest, value: bool) !void {
|
||||
if (self._ready_state != .unsent and self._ready_state != .opened) {
|
||||
return error.InvalidStateError;
|
||||
}
|
||||
self._with_credentials = value;
|
||||
}
|
||||
|
||||
// TODO: this takes an optional 3 more parameters
|
||||
// TODO: url should be a union, as it can be multiple things
|
||||
pub fn open(self: *XMLHttpRequest, method_: []const u8, url: [:0]const u8) !void {
|
||||
@@ -198,8 +210,14 @@ pub fn send(self: *XMLHttpRequest, body_: ?[]const u8) !void {
|
||||
const page = self._page;
|
||||
const http_client = page._session.browser.http_client;
|
||||
var headers = try http_client.newHeaders();
|
||||
|
||||
// Only add cookies for same-origin or when withCredentials is true
|
||||
const cookie_support = self._with_credentials or try page.isSameOrigin(self._url);
|
||||
|
||||
try self._request_headers.populateHttpHeader(page.call_arena, &headers);
|
||||
try page.headersForRequest(self._arena, self._url, &headers);
|
||||
if (cookie_support) {
|
||||
try page.headersForRequest(self._arena, self._url, &headers);
|
||||
}
|
||||
|
||||
try http_client.request(.{
|
||||
.ctx = self,
|
||||
@@ -207,7 +225,7 @@ pub fn send(self: *XMLHttpRequest, body_: ?[]const u8) !void {
|
||||
.method = self._method,
|
||||
.headers = headers,
|
||||
.body = self._request_body,
|
||||
.cookie_jar = &page._session.cookie_jar,
|
||||
.cookie_jar = if (cookie_support) &page._session.cookie_jar else null,
|
||||
.resource_type = .xhr,
|
||||
.notification = page._session.notification,
|
||||
.start_callback = httpStartCallback,
|
||||
@@ -541,6 +559,7 @@ pub const JsApi = struct {
|
||||
pub const DONE = bridge.property(@intFromEnum(XMLHttpRequest.ReadyState.done));
|
||||
|
||||
pub const onreadystatechange = bridge.accessor(XMLHttpRequest.getOnReadyStateChange, XMLHttpRequest.setOnReadyStateChange, .{});
|
||||
pub const withCredentials = bridge.accessor(XMLHttpRequest.getWithCredentials, XMLHttpRequest.setWithCredentials, .{ .dom_exception = true });
|
||||
pub const open = bridge.function(XMLHttpRequest.open, .{});
|
||||
pub const send = bridge.function(XMLHttpRequest.send, .{ .dom_exception = true });
|
||||
pub const responseType = bridge.accessor(XMLHttpRequest.getResponseType, XMLHttpRequest.setResponseType, .{});
|
||||
|
||||
@@ -783,7 +783,7 @@ pub const Request = struct {
|
||||
url: [:0]const u8,
|
||||
headers: Http.Headers,
|
||||
body: ?[]const u8 = null,
|
||||
cookie_jar: *CookieJar,
|
||||
cookie_jar: ?*CookieJar,
|
||||
resource_type: ResourceType,
|
||||
credentials: ?[:0]const u8 = null,
|
||||
notification: *Notification,
|
||||
@@ -1057,13 +1057,15 @@ pub const Transfer = struct {
|
||||
const arena = transfer.arena.allocator();
|
||||
|
||||
// retrieve cookies from the redirect's response.
|
||||
var i: usize = 0;
|
||||
while (true) {
|
||||
const ct = getResponseHeader(easy, "set-cookie", i);
|
||||
if (ct == null) break;
|
||||
try req.cookie_jar.populateFromResponse(transfer.url, ct.?.value);
|
||||
i += 1;
|
||||
if (i >= ct.?.amount) break;
|
||||
if (req.cookie_jar) |jar| {
|
||||
var i: usize = 0;
|
||||
while (true) {
|
||||
const ct = getResponseHeader(easy, "set-cookie", i);
|
||||
if (ct == null) break;
|
||||
try jar.populateFromResponse(transfer.url, ct.?.value);
|
||||
i += 1;
|
||||
if (i >= ct.?.amount) break;
|
||||
}
|
||||
}
|
||||
|
||||
// set cookies for the following redirection's request.
|
||||
@@ -1077,15 +1079,17 @@ pub const Transfer = struct {
|
||||
const url = try URL.resolve(arena, std.mem.span(base_url), location.value, .{});
|
||||
transfer.url = url;
|
||||
|
||||
var cookies: std.ArrayList(u8) = .{};
|
||||
try req.cookie_jar.forRequest(url, cookies.writer(arena), .{
|
||||
.is_http = true,
|
||||
.origin_url = url,
|
||||
// used to enforce samesite cookie rules
|
||||
.is_navigation = req.resource_type == .document,
|
||||
});
|
||||
try cookies.append(arena, 0); //null terminate
|
||||
try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_COOKIE, @as([*c]const u8, @ptrCast(cookies.items.ptr))));
|
||||
if (req.cookie_jar) |jar| {
|
||||
var cookies: std.ArrayList(u8) = .{};
|
||||
try jar.forRequest(url, cookies.writer(arena), .{
|
||||
.is_http = true,
|
||||
.origin_url = url,
|
||||
// used to enforce samesite cookie rules
|
||||
.is_navigation = req.resource_type == .document,
|
||||
});
|
||||
try cookies.append(arena, 0); //null terminate
|
||||
try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_COOKIE, @as([*c]const u8, @ptrCast(cookies.items.ptr))));
|
||||
}
|
||||
}
|
||||
|
||||
// headerDoneCallback is called once the headers have been read.
|
||||
@@ -1107,16 +1111,18 @@ pub const Transfer = struct {
|
||||
@memcpy(hdr._content_type[0..len], value[0..len]);
|
||||
}
|
||||
|
||||
var i: usize = 0;
|
||||
while (true) {
|
||||
const ct = getResponseHeader(easy, "set-cookie", i);
|
||||
if (ct == null) break;
|
||||
transfer.req.cookie_jar.populateFromResponse(transfer.url, ct.?.value) catch |err| {
|
||||
log.err(.http, "set cookie", .{ .err = err, .req = transfer });
|
||||
return err;
|
||||
};
|
||||
i += 1;
|
||||
if (i >= ct.?.amount) break;
|
||||
if (transfer.req.cookie_jar) |jar| {
|
||||
var i: usize = 0;
|
||||
while (true) {
|
||||
const ct = getResponseHeader(easy, "set-cookie", i);
|
||||
if (ct == null) break;
|
||||
jar.populateFromResponse(transfer.url, ct.?.value) catch |err| {
|
||||
log.err(.http, "set cookie", .{ .err = err, .req = transfer });
|
||||
return err;
|
||||
};
|
||||
i += 1;
|
||||
if (i >= ct.?.amount) break;
|
||||
}
|
||||
}
|
||||
|
||||
const proceed = transfer.req.header_callback(transfer) catch |err| {
|
||||
|
||||
Reference in New Issue
Block a user