From 64ace436841439606e4002b69ae75970119cbe1a Mon Sep 17 00:00:00 2001 From: floscodes Date: Wed, 10 May 2023 21:19:33 +0200 Subject: [PATCH] add Response cookie --- src/res_cookie.zig | 35 +++++++++++++++++++++++++++++++++++ src/server.zig | 14 ++++++++++++-- src/types.zig | 3 +++ 3 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 src/res_cookie.zig diff --git a/src/res_cookie.zig b/src/res_cookie.zig new file mode 100644 index 0000000..5312a0c --- /dev/null +++ b/src/res_cookie.zig @@ -0,0 +1,35 @@ +const std = @import("std"); +const types = @import("types.zig"); + +pub const Cookie = struct { + name: []const u8, + value: []const u8, + path: []const u8 = "/", + domain: []const u8 = "", + maxAge: i64 = 0, + secure: bool = true, + httpOnly: bool = true, + sameSite: SameSite = .lax, + + pub fn stringify(self: Cookie, allocator: std.mem.Allocator) ![]const u8 { + const domain = if (std.mem.eql(u8, self.domain, "")) self.domain else try std.fmt.allocPrint(allocator, "Domain={s}; ", .{self.domain}); + defer allocator.free(domain); + const secure = if (self.secure) "Secure; " else ""; + const httpOnly = if (self.httpOnly) "HttpOnly; " else ""; + return try std.fmt.allocPrint(allocator, "Set-Cookie: {s}={s}; {s}Max-Age={}; {s}{s}{s}\n", .{ self.name, self.value, domain, self.maxAge, secure, httpOnly, getSameSite(&self) }); + } +}; + +pub const SameSite = enum { + lax, + strict, + none, +}; + +pub fn getSameSite(c: *const Cookie) []const u8 { + switch (c.sameSite) { + .lax => return "SameSite=Lax;", + .strict => return "SameSite=Strict;", + .none => return "SameSite=None;", + } +} diff --git a/src/server.zig b/src/server.zig index 66c0c1b..3041a13 100644 --- a/src/server.zig +++ b/src/server.zig @@ -136,13 +136,19 @@ fn stringifyResponse(r: Response, allocator: std.mem.Allocator) ![]const u8 { try res.append(' '); try res.appendSlice(r.status.stringify()); try res.appendSlice("\r\n"); - + // Add headers for (r.headers) |header| { try res.appendSlice(header.key); try res.appendSlice(": "); try res.appendSlice(header.value); try res.appendSlice("\n"); } + // Add cookie-headers + for (r.cookies) |cookie| { + const c = try cookie.stringify(allocator); + defer allocator.free(c); + if (!eql(u8, cookie.name, "") and !eql(u8, cookie.value, "")) try res.appendSlice(c); + } try res.appendSlice("\r\n\r\n"); try res.appendSlice(r.body); @@ -159,10 +165,14 @@ test "stringify Response" { } test "Run server" { + // Set route const rt = [_]types.Route{.{ "/", handlefn }}; try Server.listen("0.0.0.0", 8080, &rt, std.testing.allocator); } // Function for test "Run Server" fn handlefn(_: *types.Request) types.Response { - return types.Response.write("

Run Server Test OK!

"); + // create Response and add cookie to test cookie setting + const rc = @import("./res_cookie.zig"); + var res = types.Response{ .body = "

Run Server Test OK!

", .cookies = &[_]rc.Cookie{.{ .name = "Test-Cookie", .value = "Test", .domain = "localhost:8080" }} }; + return res; } diff --git a/src/types.zig b/src/types.zig index 3a6b01e..0641eb6 100644 --- a/src/types.zig +++ b/src/types.zig @@ -3,6 +3,7 @@ const tuple = std.meta.Tuple; const allocator = std.heap.page_allocator; const eql = std.mem.eql; const stat = @import("./status.zig"); +const rc = @import("./res_cookie.zig"); /// Route is a touple that consists of the path and the function that shall handle it. /// e.g. `const rt = Route{"/home", home};` @@ -103,6 +104,8 @@ pub const Response = struct { status: stat.Status = stat.Status.OK, /// Response eaders sent by the server headers: []const Header = &[_]Header{.{ .key = "Content-Type", .value = "text/html; charset=utf-8" }}, + /// Cookies to be sent + cookies: []const rc.Cookie = &[_]rc.Cookie{.{ .name = "", .value = "" }}, /// Response body sent by the server body: []const u8 = "",