Skip to content

Commit f767997

Browse files
committed
expires dashes and f64
1 parent b96ea74 commit f767997

File tree

2 files changed

+32
-16
lines changed

2 files changed

+32
-16
lines changed

src/browser/storage/cookie.zig

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ pub const Jar = struct {
129129

130130
fn isCookieExpired(cookie: *const Cookie, now: i64) bool {
131131
const ce = cookie.expires orelse return false;
132-
return ce <= now;
132+
return ce <= @as(f64, @floatFromInt(now));
133133
}
134134

135135
fn areCookiesEqual(a: *const Cookie, b: *const Cookie) bool {
@@ -174,7 +174,7 @@ pub const Cookie = struct {
174174
value: []const u8,
175175
domain: []const u8,
176176
path: []const u8,
177-
expires: ?i64,
177+
expires: ?f64,
178178
secure: bool = false,
179179
http_only: bool = false,
180180
same_site: SameSite = .none,
@@ -226,7 +226,7 @@ pub const Cookie = struct {
226226
var secure: ?bool = null;
227227
var max_age: ?i64 = null;
228228
var http_only: ?bool = null;
229-
var expires: ?DateTime = null;
229+
var expires: ?[]const u8 = null;
230230
var same_site: ?Cookie.SameSite = null;
231231

232232
var it = std.mem.splitScalar(u8, rest, ';');
@@ -258,7 +258,7 @@ pub const Cookie = struct {
258258
.domain => domain = value,
259259
.secure => secure = true,
260260
.@"max-age" => max_age = std.fmt.parseInt(i64, value, 10) catch continue,
261-
.expires => expires = DateTime.parse(value, .rfc822) catch continue,
261+
.expires => expires = value,
262262
.httponly => http_only = true,
263263
.samesite => {
264264
same_site = std.meta.stringToEnum(Cookie.SameSite, std.ascii.lowerString(&scrap, value)) orelse continue;
@@ -278,13 +278,25 @@ pub const Cookie = struct {
278278
const owned_path = try parsePath(aa, uri, path);
279279
const owned_domain = try parseDomain(aa, uri, domain);
280280

281-
var normalized_expires: ?i64 = null;
281+
var normalized_expires: ?f64 = null;
282282
if (max_age) |ma| {
283-
normalized_expires = std.time.timestamp() + ma;
283+
normalized_expires = @floatFromInt(std.time.timestamp() + ma);
284284
} else {
285285
// max age takes priority over expires
286-
if (expires) |e| {
287-
normalized_expires = e.sub(DateTime.now(), .seconds);
286+
if (expires) |expires_| {
287+
var exp_dt = DateTime.parse(expires_, .rfc822) catch null;
288+
if (exp_dt == null) {
289+
if ((expires_.len > 11 and expires_[7] == '-' and expires_[11] == '-')) {
290+
// Replace dashes and try again
291+
const output = try aa.dupe(u8, expires_);
292+
output[7] = ' ';
293+
output[11] = ' ';
294+
exp_dt = DateTime.parse(output, .rfc822) catch null;
295+
}
296+
}
297+
if (exp_dt) |dt| {
298+
normalized_expires = @floatFromInt(dt.unix(.seconds));
299+
} else std.debug.print("Invalid cookie expires value: {s}\n", .{expires_});
288300
}
289301
}
290302

@@ -838,7 +850,8 @@ test "Cookie: parse expires" {
838850
try expectAttribute(.{ .expires = null }, null, "b;expires=13.22");
839851
try expectAttribute(.{ .expires = null }, null, "b;expires=33");
840852

841-
try expectAttribute(.{ .expires = 1918798080 - std.time.timestamp() }, null, "b;expires=Wed, 21 Oct 2030 07:28:00 GMT");
853+
try expectAttribute(.{ .expires = 1918798080 }, null, "b;expires=Wed, 21 Oct 2030 07:28:00 GMT");
854+
try expectAttribute(.{ .expires = 1784275395 }, null, "b;expires=Fri, 17-Jul-2026 08:03:15 GMT");
842855
// max-age has priority over expires
843856
try expectAttribute(.{ .expires = std.time.timestamp() + 10 }, null, "b;Max-Age=10; expires=Wed, 21 Oct 2030 07:28:00 GMT");
844857
}
@@ -858,7 +871,7 @@ test "Cookie: parse all" {
858871
.http_only = true,
859872
.secure = true,
860873
.domain = ".lightpanda.io",
861-
.expires = std.time.timestamp() + 30,
874+
.expires = @floatFromInt(std.time.timestamp() + 30),
862875
}, "https://lightpanda.io/cms/users", "user-id=9000; HttpOnly; Max-Age=30; Secure; path=/; Domain=lightpanda.io");
863876

864877
try expectCookie(.{
@@ -869,7 +882,7 @@ test "Cookie: parse all" {
869882
.secure = false,
870883
.domain = ".localhost",
871884
.same_site = .lax,
872-
.expires = std.time.timestamp() + 7200,
885+
.expires = @floatFromInt(std.time.timestamp() + 7200),
873886
}, "http://localhost:8000/login", "app_session=123; Max-Age=7200; path=/; domain=localhost; httponly; samesite=lax");
874887
}
875888

@@ -896,7 +909,7 @@ const ExpectedCookie = struct {
896909
value: []const u8,
897910
path: []const u8,
898911
domain: []const u8,
899-
expires: ?i64 = null,
912+
expires: ?f64 = null,
900913
secure: bool = false,
901914
http_only: bool = false,
902915
same_site: Cookie.SameSite = .lax,
@@ -915,7 +928,7 @@ fn expectCookie(expected: ExpectedCookie, url: []const u8, set_cookie: []const u
915928
try testing.expectEqual(expected.path, cookie.path);
916929
try testing.expectEqual(expected.domain, cookie.domain);
917930

918-
try testing.expectDelta(expected.expires, cookie.expires, 2);
931+
try testing.expectDelta(expected.expires, cookie.expires, 2.0);
919932
}
920933

921934
fn expectAttribute(expected: anytype, url: ?[]const u8, set_cookie: []const u8) !void {
@@ -925,7 +938,10 @@ fn expectAttribute(expected: anytype, url: ?[]const u8, set_cookie: []const u8)
925938

926939
inline for (@typeInfo(@TypeOf(expected)).@"struct".fields) |f| {
927940
if (comptime std.mem.eql(u8, f.name, "expires")) {
928-
try testing.expectDelta(expected.expires, cookie.expires, 1);
941+
switch (@typeInfo(@TypeOf(expected.expires))) {
942+
.int, .comptime_int => try testing.expectDelta(@as(f64, @floatFromInt(expected.expires)), cookie.expires, 1.0),
943+
else => try testing.expectDelta(expected.expires, cookie.expires, 1.0),
944+
}
929945
} else {
930946
try testing.expectEqual(@field(expected, f.name), @field(cookie, f.name));
931947
}

src/cdp/domains/storage.zig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ pub const CdpCookie = struct {
121121
secure: ?bool = null, // default: https://www.rfc-editor.org/rfc/rfc6265#section-5.3
122122
httpOnly: bool = false, // default: https://www.rfc-editor.org/rfc/rfc6265#section-5.3
123123
sameSite: SameSite = .None, // default: https://datatracker.ietf.org/doc/html/draft-west-first-party-cookies
124-
expires: ?i64 = null, // -1? says google
124+
expires: ?f64 = null, // -1? says google
125125
priority: CookiePriority = .Medium, // default: https://datatracker.ietf.org/doc/html/draft-west-cookie-priority-00
126126
sameParty: ?bool = null,
127127
sourceScheme: ?CookieSourceScheme = null,
@@ -296,7 +296,7 @@ pub const ResCookie = struct {
296296
value: []const u8,
297297
domain: []const u8,
298298
path: []const u8 = "/",
299-
expires: i32 = -1,
299+
expires: f64 = -1,
300300
httpOnly: bool = false,
301301
secure: bool = false,
302302
sameSite: []const u8 = "None",

0 commit comments

Comments
 (0)