cookies.nim 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. #
  2. #
  3. # Nim's Runtime Library
  4. # (c) Copyright 2012 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## This module implements helper procs for parsing Cookies.
  10. import strtabs, times, options
  11. type
  12. SameSite* {.pure.} = enum ## The SameSite cookie attribute.
  13. ## `Default` means that `setCookie`
  14. ## proc will not set `SameSite` attribute.
  15. Default, None, Lax, Strict
  16. proc parseCookies*(s: string): StringTableRef =
  17. ## Parses cookies into a string table.
  18. ##
  19. ## The proc is meant to parse the Cookie header set by a client, not the
  20. ## "Set-Cookie" header set by servers.
  21. runnableExamples:
  22. import std/strtabs
  23. let cookieJar = parseCookies("a=1; foo=bar")
  24. assert cookieJar["a"] == "1"
  25. assert cookieJar["foo"] == "bar"
  26. result = newStringTable(modeCaseInsensitive)
  27. var i = 0
  28. while true:
  29. while i < s.len and (s[i] == ' ' or s[i] == '\t'): inc(i)
  30. var keystart = i
  31. while i < s.len and s[i] != '=': inc(i)
  32. var keyend = i-1
  33. if i >= s.len: break
  34. inc(i) # skip '='
  35. var valstart = i
  36. while i < s.len and s[i] != ';': inc(i)
  37. result[substr(s, keystart, keyend)] = substr(s, valstart, i-1)
  38. if i >= s.len: break
  39. inc(i) # skip ';'
  40. proc setCookie*(key, value: string, domain = "", path = "",
  41. expires = "", noName = false,
  42. secure = false, httpOnly = false,
  43. maxAge = none(int), sameSite = SameSite.Default): string =
  44. ## Creates a command in the format of
  45. ## `Set-Cookie: key=value; Domain=...; ...`
  46. result = ""
  47. if not noName: result.add("Set-Cookie: ")
  48. result.add key & "=" & value
  49. if domain != "": result.add("; Domain=" & domain)
  50. if path != "": result.add("; Path=" & path)
  51. if expires != "": result.add("; Expires=" & expires)
  52. if secure: result.add("; Secure")
  53. if httpOnly: result.add("; HttpOnly")
  54. if maxAge.isSome: result.add("; Max-Age=" & $maxAge.unsafeGet)
  55. if sameSite != SameSite.Default:
  56. if sameSite == SameSite.None:
  57. doAssert secure, "Cookies with SameSite=None must specify the Secure attribute!"
  58. result.add("; SameSite=" & $sameSite)
  59. proc setCookie*(key, value: string, expires: DateTime|Time,
  60. domain = "", path = "", noName = false,
  61. secure = false, httpOnly = false,
  62. maxAge = none(int), sameSite = SameSite.Default): string =
  63. ## Creates a command in the format of
  64. ## `Set-Cookie: key=value; Domain=...; ...`
  65. result = setCookie(key, value, domain, path,
  66. format(expires.utc, "ddd',' dd MMM yyyy HH:mm:ss 'GMT'"),
  67. noname, secure, httpOnly, maxAge, sameSite)