mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-03-22 04:34:44 +00:00
Merge pull request #1617 from lightpanda-io/cookie_fixes
Add more cookie tests
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<head id="the_head">
|
<head id="the_head">
|
||||||
|
<meta charset="UTF-8">
|
||||||
<title>Test Document Title</title>
|
<title>Test Document Title</title>
|
||||||
<script src="../testing.js"></script>
|
<script src="../testing.js"></script>
|
||||||
</head>
|
</head>
|
||||||
@@ -176,15 +177,111 @@
|
|||||||
testing.expectEqual(initialLength, anchors.length);
|
testing.expectEqual(initialLength, anchors.length);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script id=cookie>
|
<script id=cookie_basic>
|
||||||
testing.expectEqual('', document.cookie);
|
// Basic cookie operations
|
||||||
document.cookie = 'name=Oeschger;';
|
document.cookie = 'testbasic1=Oeschger';
|
||||||
document.cookie = 'favorite_food=tripe;';
|
testing.expectEqual(true, document.cookie.includes('testbasic1=Oeschger'));
|
||||||
|
|
||||||
testing.expectEqual('name=Oeschger; favorite_food=tripe', document.cookie);
|
document.cookie = 'testbasic2=tripe';
|
||||||
// "" should be returned, but the framework overrules it atm
|
testing.expectEqual(true, document.cookie.includes('testbasic1=Oeschger'));
|
||||||
|
testing.expectEqual(true, document.cookie.includes('testbasic2=tripe'));
|
||||||
|
|
||||||
|
// HttpOnly should be ignored from JavaScript
|
||||||
|
const beforeHttp = document.cookie;
|
||||||
document.cookie = 'IgnoreMy=Ghost; HttpOnly';
|
document.cookie = 'IgnoreMy=Ghost; HttpOnly';
|
||||||
testing.expectEqual('name=Oeschger; favorite_food=tripe', document.cookie);
|
testing.expectEqual(false, document.cookie.includes('IgnoreMy=Ghost'));
|
||||||
|
|
||||||
|
// Clean up
|
||||||
|
document.cookie = 'testbasic1=; Max-Age=0';
|
||||||
|
document.cookie = 'testbasic2=; Max-Age=0';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id=cookie_special_chars>
|
||||||
|
// Test special characters in cookie values
|
||||||
|
document.cookie = 'testspaces=hello world';
|
||||||
|
testing.expectEqual(true, document.cookie.includes('testspaces=hello world'));
|
||||||
|
document.cookie = 'testspaces=; Max-Age=0';
|
||||||
|
|
||||||
|
// Test various allowed special characters
|
||||||
|
document.cookie = 'testspecial=!#$%&\'()*+-./';
|
||||||
|
testing.expectEqual(true, document.cookie.includes('testspecial='));
|
||||||
|
document.cookie = 'testspecial=; Max-Age=0';
|
||||||
|
|
||||||
|
// Semicolon terminates the cookie value
|
||||||
|
document.cookie = 'testsemi=before;after';
|
||||||
|
testing.expectEqual(true, document.cookie.includes('testsemi=before'));
|
||||||
|
testing.expectEqual(false, document.cookie.includes('after'));
|
||||||
|
document.cookie = 'testsemi=; Max-Age=0';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id=cookie_empty_name>
|
||||||
|
// Cookie with empty name (just a value)
|
||||||
|
document.cookie = 'teststandalone';
|
||||||
|
testing.expectEqual(true, document.cookie.includes('teststandalone'));
|
||||||
|
document.cookie = 'teststandalone; Max-Age=0';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id=cookie_whitespace>
|
||||||
|
// Names and values should be trimmed
|
||||||
|
document.cookie = ' testtrim = trimmed_value ';
|
||||||
|
testing.expectEqual(true, document.cookie.includes('testtrim=trimmed_value'));
|
||||||
|
document.cookie = 'testtrim=; Max-Age=0';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id=cookie_max_age>
|
||||||
|
// Max-Age=0 should immediately delete
|
||||||
|
document.cookie = 'testtemp0=value; Max-Age=0';
|
||||||
|
testing.expectEqual(false, document.cookie.includes('testtemp0=value'));
|
||||||
|
|
||||||
|
// Negative Max-Age should also delete
|
||||||
|
document.cookie = 'testinstant=value';
|
||||||
|
testing.expectEqual(true, document.cookie.includes('testinstant=value'));
|
||||||
|
document.cookie = 'testinstant=value; Max-Age=-1';
|
||||||
|
testing.expectEqual(false, document.cookie.includes('testinstant=value'));
|
||||||
|
|
||||||
|
// Positive Max-Age should keep cookie
|
||||||
|
document.cookie = 'testkept=value; Max-Age=3600';
|
||||||
|
testing.expectEqual(true, document.cookie.includes('testkept=value'));
|
||||||
|
document.cookie = 'testkept=; Max-Age=0';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id=cookie_overwrite>
|
||||||
|
// Setting a cookie with the same name should overwrite
|
||||||
|
document.cookie = 'testoverwrite=first';
|
||||||
|
testing.expectEqual(true, document.cookie.includes('testoverwrite=first'));
|
||||||
|
|
||||||
|
document.cookie = 'testoverwrite=second';
|
||||||
|
testing.expectEqual(true, document.cookie.includes('testoverwrite=second'));
|
||||||
|
testing.expectEqual(false, document.cookie.includes('testoverwrite=first'));
|
||||||
|
|
||||||
|
document.cookie = 'testoverwrite=; Max-Age=0';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id=cookie_path>
|
||||||
|
// Path attribute
|
||||||
|
document.cookie = 'testpath1=value; Path=/';
|
||||||
|
testing.expectEqual(true, document.cookie.includes('testpath1=value'));
|
||||||
|
|
||||||
|
// Different path cookie should coexist
|
||||||
|
document.cookie = 'testpath2=value2; Path=/src';
|
||||||
|
testing.expectEqual(true, document.cookie.includes('testpath1=value'));
|
||||||
|
|
||||||
|
document.cookie = 'testpath1=; Max-Age=0; Path=/';
|
||||||
|
document.cookie = 'testpath2=; Max-Age=0; Path=/src';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id=cookie_invalid_chars>
|
||||||
|
// Control characters (< 32 or > 126) should be rejected
|
||||||
|
const beforeBad = document.cookie;
|
||||||
|
|
||||||
|
document.cookie = 'testbad1\x00=value';
|
||||||
|
testing.expectEqual(false, document.cookie.includes('testbad1'));
|
||||||
|
|
||||||
|
document.cookie = 'testbad2\x1F=value';
|
||||||
|
testing.expectEqual(false, document.cookie.includes('testbad2'));
|
||||||
|
|
||||||
|
document.cookie = 'testbad3=val\x7F';
|
||||||
|
testing.expectEqual(false, document.cookie.includes('testbad3'));
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script id=createAttribute>
|
<script id=createAttribute>
|
||||||
|
|||||||
@@ -201,7 +201,10 @@ pub fn setCookie(_: *HTMLDocument, cookie_str: []const u8, page: *Page) ![]const
|
|||||||
// we use the cookie jar's allocator to parse the cookie because it
|
// we use the cookie jar's allocator to parse the cookie because it
|
||||||
// outlives the page's arena.
|
// outlives the page's arena.
|
||||||
const Cookie = @import("storage/Cookie.zig");
|
const Cookie = @import("storage/Cookie.zig");
|
||||||
const c = try Cookie.parse(page._session.cookie_jar.allocator, page.url, cookie_str);
|
const c = Cookie.parse(page._session.cookie_jar.allocator, page.url, cookie_str) catch {
|
||||||
|
// Invalid cookies should be silently ignored, not throw errors
|
||||||
|
return "";
|
||||||
|
};
|
||||||
errdefer c.deinit();
|
errdefer c.deinit();
|
||||||
if (c.http_only) {
|
if (c.http_only) {
|
||||||
c.deinit();
|
c.deinit();
|
||||||
|
|||||||
@@ -49,10 +49,10 @@ pub fn deinit(self: *const Cookie) void {
|
|||||||
|
|
||||||
// There's https://datatracker.ietf.org/doc/html/rfc6265 but browsers are
|
// There's https://datatracker.ietf.org/doc/html/rfc6265 but browsers are
|
||||||
// far less strict. I only found 2 cases where browsers will reject a cookie:
|
// far less strict. I only found 2 cases where browsers will reject a cookie:
|
||||||
// - a byte 0...32 and 127..255 anywhere in the cookie (the HTTP header
|
// - a byte 0...31 and 127...255 anywhere in the cookie (the HTTP header
|
||||||
// parser might take care of this already)
|
// parser might take care of this already)
|
||||||
// - any shenanigans with the domain attribute - it has to be the current
|
// - any shenanigans with the domain attribute - it has to be the current
|
||||||
// domain or one of higher order, exluding TLD.
|
// domain or one of higher order, excluding TLD.
|
||||||
// Anything else, will turn into a cookie.
|
// Anything else, will turn into a cookie.
|
||||||
// Single value? That's a cookie with an emtpy name and a value
|
// Single value? That's a cookie with an emtpy name and a value
|
||||||
// Key or Values with characters the RFC says aren't allowed? Allowed! (
|
// Key or Values with characters the RFC says aren't allowed? Allowed! (
|
||||||
@@ -318,7 +318,7 @@ fn parseNameValue(str: []const u8) !struct { []const u8, []const u8, []const u8
|
|||||||
|
|
||||||
pub fn appliesTo(self: *const Cookie, url: *const PreparedUri, same_site: bool, is_navigation: bool, is_http: bool) bool {
|
pub fn appliesTo(self: *const Cookie, url: *const PreparedUri, same_site: bool, is_navigation: bool, is_http: bool) bool {
|
||||||
if (self.http_only and is_http == false) {
|
if (self.http_only and is_http == false) {
|
||||||
// http only cookies can be accessed from Javascript
|
// http only cookies cannot be accessed from Javascript
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -435,9 +435,9 @@ pub const Jar = struct {
|
|||||||
pub fn removeExpired(self: *Jar, request_time: ?i64) void {
|
pub fn removeExpired(self: *Jar, request_time: ?i64) void {
|
||||||
if (self.cookies.items.len == 0) return;
|
if (self.cookies.items.len == 0) return;
|
||||||
const time = request_time orelse std.time.timestamp();
|
const time = request_time orelse std.time.timestamp();
|
||||||
var i: usize = self.cookies.items.len - 1;
|
var i: usize = self.cookies.items.len ;
|
||||||
while (i > 0) {
|
while (i > 0) {
|
||||||
defer i -= 1;
|
i -= 1;
|
||||||
const cookie = &self.cookies.items[i];
|
const cookie = &self.cookies.items[i];
|
||||||
if (isCookieExpired(cookie, time)) {
|
if (isCookieExpired(cookie, time)) {
|
||||||
self.cookies.swapRemove(i).deinit();
|
self.cookies.swapRemove(i).deinit();
|
||||||
@@ -558,7 +558,7 @@ fn trimLeft(str: []const u8) []const u8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn trimRight(str: []const u8) []const u8 {
|
fn trimRight(str: []const u8) []const u8 {
|
||||||
return std.mem.trimLeft(u8, str, &std.ascii.whitespace);
|
return std.mem.trimRight(u8, str, &std.ascii.whitespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn toLower(str: []u8) []u8 {
|
fn toLower(str: []u8) []u8 {
|
||||||
|
|||||||
Reference in New Issue
Block a user