From 7c75b4f499b1ea9ceabd98fdf56246dbfe31ae86 Mon Sep 17 00:00:00 2001 From: Bob Farrell Date: Sun, 4 May 2025 15:11:36 +0100 Subject: [PATCH] Cookie deletion Allow "deleting" a cookie (overwrite with a blank value and expiry in the past). --- src/jetzig/http/Cookies.zig | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/jetzig/http/Cookies.zig b/src/jetzig/http/Cookies.zig index 214bb79..95844a4 100644 --- a/src/jetzig/http/Cookies.zig +++ b/src/jetzig/http/Cookies.zig @@ -107,10 +107,12 @@ pub fn deinit(self: *Cookies) void { self.arena.deinit(); } +/// Fetch a cookie by name. pub fn get(self: *Cookies, key: []const u8) ?*Cookie { return self.cookies.get(key); } +/// Put a cookie into the cookie store. pub fn put(self: *Cookies, cookie: Cookie) !void { self.modified = true; @@ -127,6 +129,18 @@ pub fn put(self: *Cookies, cookie: Cookie) !void { try self.cookies.put(key, ptr); } +/// Overwrite a cookie with an empty string and expiry of 0. The browser should then no longer +/// send the specified cookie value. +/// +/// > Notice that servers can delete cookies by sending the user agent a new cookie with an +/// > Expires attribute with a value in the past. +/// - https://www.rfc-editor.org/rfc/rfc6265.html +pub fn delete(self: *Cookies, key: []const u8) !void { + self.modified = true; + + try self.put(.{ .name = key, .value = "", .expires = 0 }); +} + pub const HeaderIterator = struct { allocator: std.mem.Allocator, cookies_iterator: std.StringArrayHashMap(*Cookie).Iterator, @@ -434,3 +448,17 @@ test "default flags" { try std.testing.expect(cookie.expires == null); try std.testing.expect(cookie.max_age == null); } + +test "delete" { + const allocator = std.testing.allocator; + var cookies = Cookies.init(allocator, "foo=bar;"); + defer cookies.deinit(); + + try cookies.parse(); + + try cookies.delete("foo"); + const cookie = cookies.get("foo").?; + + try std.testing.expectEqualStrings(cookie.value, ""); + try std.testing.expectEqual(cookie.expires.?, 0); +}