diff options
Diffstat (limited to 'lib/pure/cookies.nim')
-rw-r--r-- | lib/pure/cookies.nim | 73 |
1 files changed, 62 insertions, 11 deletions
diff --git a/lib/pure/cookies.nim b/lib/pure/cookies.nim index eed6c7512..f628aaf6b 100644 --- a/lib/pure/cookies.nim +++ b/lib/pure/cookies.nim @@ -1,7 +1,7 @@ # # -# Nimrod's Runtime Library -# (c) Copyright 2010 Andreas Rumpf +# Nim's Runtime Library +# (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -9,22 +9,73 @@ ## This module implements helper procs for parsing Cookies. -import strtabs +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" -proc parseCookies*(s: string): PStringTable = - ## parses cookies into a string table. result = newStringTable(modeCaseInsensitive) var i = 0 while true: - while s[i] == ' ' or s[i] == '\t': inc(i) + while i < s.len and (s[i] == ' ' or s[i] == '\t'): inc(i) var keystart = i - while s[i] != '=' and s[i] != '\0': inc(i) + while i < s.len and s[i] != '=': inc(i) var keyend = i-1 - if s[i] == '\0': break + if i >= s.len: break inc(i) # skip '=' var valstart = i - while s[i] != ';' and s[i] != '\0': inc(i) - result[copy(s, keystart, keyend)] = copy(s, valstart, i-1) - if s[i] == '\0': break + 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) |