summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
authorflywind <xzsflywind@gmail.com>2021-02-24 03:14:19 -0600
committerGitHub <noreply@github.com>2021-02-24 10:14:19 +0100
commit46bd222c89c57217d1d4738f84f52de94f092c1d (patch)
treec3c69d9af54a3b8a384fa1f4a2ef1a4d0473af5d /lib
parentb48a32053f2c65b8601ff991bf6f892534241b11 (diff)
downloadNim-46bd222c89c57217d1d4738f84f52de94f092c1d.tar.gz
[stdlib] make cookies module modern (#17116)
* update cookies module
* introduce sameSite.Default

Co-authored-by: hlaaftana <10591326+hlaaftana@users.noreply.github.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/pure/cookies.nim41
1 files changed, 28 insertions, 13 deletions
diff --git a/lib/pure/cookies.nim b/lib/pure/cookies.nim
index 7e686d44f..8d9cc0c95 100644
--- a/lib/pure/cookies.nim
+++ b/lib/pure/cookies.nim
@@ -9,18 +9,25 @@
 
 ## This module implements helper procs for parsing Cookies.
 
-import strtabs, times
+import std/[strtabs, times, options]
+
+
+type
+  SameSite* {.pure.} = enum ## The SameSite cookie attribute.
+                            ## `Default` means that `setCookie`
+                            ## proc will not set `SameSite` attribute.
+    Default, None, Lax, Strict
 
 proc parseCookies*(s: string): StringTableRef =
-  ## parses cookies into a string table.
+  ## Parses cookies into a string table.
   ##
   ## The proc is meant to parse the Cookie header set by a client, not the
   ## "Set-Cookie" header set by servers.
-  ##
-  ## Example:
-  ##
-  ## .. code-block::Nim
-  ##     doAssert parseCookies("a=1; foo=bar") == {"a": 1, "foo": "bar"}.newStringTable
+  runnableExamples:
+    import std/strtabs
+    let cookieJar = parseCookies("a=1; foo=bar") 
+    assert cookieJar["a"] == "1"
+    assert cookieJar["foo"] == "bar"
 
   result = newStringTable(modeCaseInsensitive)
   var i = 0
@@ -39,9 +46,10 @@ proc parseCookies*(s: string): StringTableRef =
 
 proc setCookie*(key, value: string, domain = "", path = "",
                 expires = "", noName = false,
-                secure = false, httpOnly = false): string =
+                secure = false, httpOnly = false, 
+                maxAge = none(int), sameSite = SameSite.Default): string =
   ## Creates a command in the format of
-  ## ``Set-Cookie: key=value; Domain=...; ...``
+  ## `Set-Cookie: key=value; Domain=...; ...`
   result = ""
   if not noName: result.add("Set-Cookie: ")
   result.add key & "=" & value
@@ -50,12 +58,19 @@ proc setCookie*(key, value: string, domain = "", path = "",
   if expires != "": result.add("; Expires=" & expires)
   if secure: result.add("; Secure")
   if httpOnly: result.add("; HttpOnly")
+  if maxAge.isSome: result.add("; Max-Age=" & $maxAge.unsafeGet)
+
+  if sameSite != SameSite.Default:
+    if sameSite == SameSite.None:
+      doAssert secure, "Cookies with SameSite=None must specify the Secure attribute!"
+    result.add("; SameSite=" & $sameSite)
 
 proc setCookie*(key, value: string, expires: DateTime|Time,
                 domain = "", path = "", noName = false,
-                secure = false, httpOnly = false): string =
+                secure = false, httpOnly = false,
+                maxAge = none(int), sameSite = SameSite.Default): string =
   ## Creates a command in the format of
-  ## ``Set-Cookie: key=value; Domain=...; ...``
-  return setCookie(key, value, domain, path,
+  ## `Set-Cookie: key=value; Domain=...; ...`
+  result = setCookie(key, value, domain, path,
                    format(expires.utc, "ddd',' dd MMM yyyy HH:mm:ss 'GMT'"),
-                   noname, secure, httpOnly)
+                   noname, secure, httpOnly, maxAge, sameSite)