diff options
Diffstat (limited to 'lib/pure/cookies.nim')
-rw-r--r-- | lib/pure/cookies.nim | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/lib/pure/cookies.nim b/lib/pure/cookies.nim new file mode 100644 index 000000000..f628aaf6b --- /dev/null +++ b/lib/pure/cookies.nim @@ -0,0 +1,81 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2012 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module implements helper procs for parsing Cookies. + +import std/[strtabs, times, options] + +when defined(nimPreviewSlimSystem): + import std/assertions + + +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. + ## + ## The proc is meant to parse the Cookie header set by a client, not the + ## "Set-Cookie" header set by servers. + 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 + while true: + while i < s.len and (s[i] == ' ' or s[i] == '\t'): inc(i) + var keystart = i + while i < s.len and s[i] != '=': inc(i) + var keyend = i-1 + if i >= s.len: break + inc(i) # skip '=' + var valstart = i + while i < s.len and s[i] != ';': inc(i) + result[substr(s, keystart, keyend)] = substr(s, valstart, i-1) + if i >= s.len: break + inc(i) # skip ';' + +proc setCookie*(key, value: string, domain = "", path = "", + expires = "", noName = false, + secure = false, httpOnly = false, + maxAge = none(int), sameSite = SameSite.Default): string = + ## Creates a command in the format of + ## `Set-Cookie: key=value; Domain=...; ...` + ## + ## .. tip:: Cookies can be vulnerable. Consider setting `secure=true`, `httpOnly=true` and `sameSite=Strict`. + result = "" + if not noName: result.add("Set-Cookie: ") + result.add key & "=" & value + if domain != "": result.add("; Domain=" & domain) + if path != "": result.add("; Path=" & 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, + maxAge = none(int), sameSite = SameSite.Default): string = + ## Creates a command in the format of + ## `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, maxAge, sameSite) |