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,
|
cache: ?[]const u8 = null,
|
||||||
as_typed_array: bool = false,
|
as_typed_array: bool = false,
|
||||||
null_as_undefined: 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 {
|
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) {
|
if (comptime opts.static) {
|
||||||
caller.function(T, getter, handle.?, .{
|
caller.function(T, getter, handle.?, .{
|
||||||
.cache = opts.cache,
|
.cache = opts.cache,
|
||||||
|
.dom_exception = opts.dom_exception,
|
||||||
.as_typed_array = opts.as_typed_array,
|
.as_typed_array = opts.as_typed_array,
|
||||||
.null_as_undefined = opts.null_as_undefined,
|
.null_as_undefined = opts.null_as_undefined,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
caller.method(T, getter, handle.?, .{
|
caller.method(T, getter, handle.?, .{
|
||||||
.cache = opts.cache,
|
.cache = opts.cache,
|
||||||
|
.dom_exception = opts.dom_exception,
|
||||||
.as_typed_array = opts.as_typed_array,
|
.as_typed_array = opts.as_typed_array,
|
||||||
.null_as_undefined = opts.null_as_undefined,
|
.null_as_undefined = opts.null_as_undefined,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ _response_type: ResponseType = .text,
|
|||||||
|
|
||||||
_ready_state: ReadyState = .unsent,
|
_ready_state: ReadyState = .unsent,
|
||||||
_on_ready_state_change: ?js.Function.Temp = null,
|
_on_ready_state_change: ?js.Function.Temp = null,
|
||||||
|
_with_credentials: bool = false,
|
||||||
|
|
||||||
const ReadyState = enum(u8) {
|
const ReadyState = enum(u8) {
|
||||||
unsent = 0,
|
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: this takes an optional 3 more parameters
|
||||||
// TODO: url should be a union, as it can be multiple things
|
// 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 {
|
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 page = self._page;
|
||||||
const http_client = page._session.browser.http_client;
|
const http_client = page._session.browser.http_client;
|
||||||
var headers = try http_client.newHeaders();
|
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 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(.{
|
try http_client.request(.{
|
||||||
.ctx = self,
|
.ctx = self,
|
||||||
@@ -207,7 +225,7 @@ pub fn send(self: *XMLHttpRequest, body_: ?[]const u8) !void {
|
|||||||
.method = self._method,
|
.method = self._method,
|
||||||
.headers = headers,
|
.headers = headers,
|
||||||
.body = self._request_body,
|
.body = self._request_body,
|
||||||
.cookie_jar = &page._session.cookie_jar,
|
.cookie_jar = if (cookie_support) &page._session.cookie_jar else null,
|
||||||
.resource_type = .xhr,
|
.resource_type = .xhr,
|
||||||
.notification = page._session.notification,
|
.notification = page._session.notification,
|
||||||
.start_callback = httpStartCallback,
|
.start_callback = httpStartCallback,
|
||||||
@@ -541,6 +559,7 @@ pub const JsApi = struct {
|
|||||||
pub const DONE = bridge.property(@intFromEnum(XMLHttpRequest.ReadyState.done));
|
pub const DONE = bridge.property(@intFromEnum(XMLHttpRequest.ReadyState.done));
|
||||||
|
|
||||||
pub const onreadystatechange = bridge.accessor(XMLHttpRequest.getOnReadyStateChange, XMLHttpRequest.setOnReadyStateChange, .{});
|
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 open = bridge.function(XMLHttpRequest.open, .{});
|
||||||
pub const send = bridge.function(XMLHttpRequest.send, .{ .dom_exception = true });
|
pub const send = bridge.function(XMLHttpRequest.send, .{ .dom_exception = true });
|
||||||
pub const responseType = bridge.accessor(XMLHttpRequest.getResponseType, XMLHttpRequest.setResponseType, .{});
|
pub const responseType = bridge.accessor(XMLHttpRequest.getResponseType, XMLHttpRequest.setResponseType, .{});
|
||||||
|
|||||||
@@ -783,7 +783,7 @@ pub const Request = struct {
|
|||||||
url: [:0]const u8,
|
url: [:0]const u8,
|
||||||
headers: Http.Headers,
|
headers: Http.Headers,
|
||||||
body: ?[]const u8 = null,
|
body: ?[]const u8 = null,
|
||||||
cookie_jar: *CookieJar,
|
cookie_jar: ?*CookieJar,
|
||||||
resource_type: ResourceType,
|
resource_type: ResourceType,
|
||||||
credentials: ?[:0]const u8 = null,
|
credentials: ?[:0]const u8 = null,
|
||||||
notification: *Notification,
|
notification: *Notification,
|
||||||
@@ -1057,13 +1057,15 @@ pub const Transfer = struct {
|
|||||||
const arena = transfer.arena.allocator();
|
const arena = transfer.arena.allocator();
|
||||||
|
|
||||||
// retrieve cookies from the redirect's response.
|
// retrieve cookies from the redirect's response.
|
||||||
var i: usize = 0;
|
if (req.cookie_jar) |jar| {
|
||||||
while (true) {
|
var i: usize = 0;
|
||||||
const ct = getResponseHeader(easy, "set-cookie", i);
|
while (true) {
|
||||||
if (ct == null) break;
|
const ct = getResponseHeader(easy, "set-cookie", i);
|
||||||
try req.cookie_jar.populateFromResponse(transfer.url, ct.?.value);
|
if (ct == null) break;
|
||||||
i += 1;
|
try jar.populateFromResponse(transfer.url, ct.?.value);
|
||||||
if (i >= ct.?.amount) break;
|
i += 1;
|
||||||
|
if (i >= ct.?.amount) break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// set cookies for the following redirection's request.
|
// 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, .{});
|
const url = try URL.resolve(arena, std.mem.span(base_url), location.value, .{});
|
||||||
transfer.url = url;
|
transfer.url = url;
|
||||||
|
|
||||||
var cookies: std.ArrayList(u8) = .{};
|
if (req.cookie_jar) |jar| {
|
||||||
try req.cookie_jar.forRequest(url, cookies.writer(arena), .{
|
var cookies: std.ArrayList(u8) = .{};
|
||||||
.is_http = true,
|
try jar.forRequest(url, cookies.writer(arena), .{
|
||||||
.origin_url = url,
|
.is_http = true,
|
||||||
// used to enforce samesite cookie rules
|
.origin_url = url,
|
||||||
.is_navigation = req.resource_type == .document,
|
// 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))));
|
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.
|
// 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]);
|
@memcpy(hdr._content_type[0..len], value[0..len]);
|
||||||
}
|
}
|
||||||
|
|
||||||
var i: usize = 0;
|
if (transfer.req.cookie_jar) |jar| {
|
||||||
while (true) {
|
var i: usize = 0;
|
||||||
const ct = getResponseHeader(easy, "set-cookie", i);
|
while (true) {
|
||||||
if (ct == null) break;
|
const ct = getResponseHeader(easy, "set-cookie", i);
|
||||||
transfer.req.cookie_jar.populateFromResponse(transfer.url, ct.?.value) catch |err| {
|
if (ct == null) break;
|
||||||
log.err(.http, "set cookie", .{ .err = err, .req = transfer });
|
jar.populateFromResponse(transfer.url, ct.?.value) catch |err| {
|
||||||
return err;
|
log.err(.http, "set cookie", .{ .err = err, .req = transfer });
|
||||||
};
|
return err;
|
||||||
i += 1;
|
};
|
||||||
if (i >= ct.?.amount) break;
|
i += 1;
|
||||||
|
if (i >= ct.?.amount) break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const proceed = transfer.req.header_callback(transfer) catch |err| {
|
const proceed = transfer.req.header_callback(transfer) catch |err| {
|
||||||
|
|||||||
Reference in New Issue
Block a user