From dac9d7c05d89e8763613dd6734365daf15fd3a62 Mon Sep 17 00:00:00 2001 From: jaina heartles Date: Thu, 17 Nov 2022 19:39:24 -0800 Subject: [PATCH] Support cookies --- src/http/headers.zig | 32 ++++++++++++++++++++++++++++++-- src/http/server/response.zig | 7 +++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/http/headers.zig b/src/http/headers.zig index 4f45029..f459ed6 100644 --- a/src/http/headers.zig +++ b/src/http/headers.zig @@ -89,8 +89,8 @@ pub const Fields = struct { } }; - pub fn getList(self: Fields, key: []const u8) ?ListIterator { - return if (self.unmanaged.get(key)) |hdr| ListIterator{ .remaining = hdr } else null; + pub fn getList(self: Fields, key: []const u8) ListIterator { + return if (self.unmanaged.get(key)) |hdr| ListIterator{ .remaining = hdr } else ListIterator{ .remaining = "" }; } pub fn put(self: *Fields, key: []const u8, val: []const u8) !void { @@ -121,4 +121,32 @@ pub const Fields = struct { pub fn count(self: Fields) usize { return self.unmanaged.count(); } + + pub const CookieOptions = struct { + Secure: bool = false, + HttpOnly: bool = false, + SameSite: ?enum { + Strict, + Lax, + None, + } = null, + }; + + pub fn setCookie(self: *Fields, name: []const u8, value: []const u8, opt: CookieOptions) !void { + const cookie = try std.fmt.printAlloc( + self.allocator, + "{s}={s}{s}{s}{s}", + .{ + name, + value, + if (opt.Secure) "; Secure" else "", + if (opt.HttpOnly) "; HttpOnly" else "", + if (opt.SameSite) |same_site| "; SameSite=" ++ @tagName(same_site) else "", + }, + ); + defer self.allocator.free(cookie); + + // TODO: reduce unnecessary allocations + self.append("Set-Cookie", cookie); + } }; diff --git a/src/http/server/response.zig b/src/http/server/response.zig index 296382d..0da7ab0 100644 --- a/src/http/server/response.zig +++ b/src/http/server/response.zig @@ -43,8 +43,15 @@ fn writeFields(writer: anytype, headers: *const Fields) !void { if (ch == '\r' or ch == '\n') @panic("newlines not yet supported in headers"); } + if (std.ascii.eqlIgnoreCase("Set-Cookie", header.key_ptr.*)) continue; + try writer.print("{s}: {s}\r\n", .{ header.key_ptr.*, header.value_ptr.* }); } + + var cookie_iter = headers.getList("Set-Cookie"); + while (cookie_iter.next()) |cookie| { + try writer.print("Set-Cookie: {s}\r\n", .{cookie}); + } } fn writeChunk(writer: anytype, contents: []const u8) @TypeOf(writer).Error!void {