about summary refs log tree commit diff stats
path: root/src/types
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2022-10-19 11:24:45 +0200
committerbptato <nincsnevem662@gmail.com>2022-10-19 11:25:56 +0200
commit08a758ed7a06e1bff8994c01d6c5d317d400ccf9 (patch)
treecb53cf39ebd323491715eb569cc509c00edcae91 /src/types
parentc4e2de9cd8cad7e28b33e68b1b76f9044fe510be (diff)
downloadchawan-08a758ed7a06e1bff8994c01d6c5d317d400ccf9.tar.gz
Implement tree buffers, fix a js bug, refactor
Diffstat (limited to 'src/types')
-rw-r--r--src/types/cookie.nim137
1 files changed, 137 insertions, 0 deletions
diff --git a/src/types/cookie.nim b/src/types/cookie.nim
new file mode 100644
index 00000000..b0578e44
--- /dev/null
+++ b/src/types/cookie.nim
@@ -0,0 +1,137 @@
+import options
+import strutils
+import times
+
+import js/javascript
+import utils/twtstr
+
+type Cookie = ref object of RootObj
+  name {.jsget.}: string
+  value {.jsget.}: string
+  expires {.jsget.}: int64 # unix time
+  maxAge {.jsget.}: int64
+  secure {.jsget.}: bool
+  httponly {.jsget.}: bool
+  samesite {.jsget.}: bool
+  domain {.jsget.}: string
+  path {.jsget.}: string
+
+proc parseCookieDate(val: string): Option[DateTime] =
+  # cookie-date
+  const Delimiters = {'\t', ' '..'/', ';'..'@', '['..'`', '{'..'~'}
+  const NonDigit = AllChars - AsciiDigit
+  var foundTime = false
+  var foundDayOfMonth = false
+  var foundMonth = false
+  var foundYear = false
+  # date-token-list
+  var time: array[3, int]
+  var dayOfMonth: int
+  var month: int
+  var year: int
+  for dateToken in val.split(Delimiters):
+    if dateToken == "": continue # *delimiter
+    if not foundTime:
+      block timeBlock: # test for time
+        let hmsTime = dateToken.until(NonDigit - {':'})
+        var i = 0
+        for timeField in hmsTime.split(':'):
+          if i > 2: break timeBlock # too many time fields
+          # 1*2DIGIT
+          if timeField.len != 1 and timeField.len != 2: break timeBlock
+          var timeFields: array[3, int]
+          for c in timeField:
+            if c notin AsciiDigit: break timeBlock
+            timeFields[i] *= 10
+            timeFields[i] += c.decValue
+          time = timeFields
+          inc i
+        if i != 3: break timeBlock
+        foundTime = true
+        continue
+    if not foundDayOfMonth:
+      block dayOfMonthBlock: # test for day-of-month
+        let digits = dateToken.until(NonDigit)
+        if digits.len != 1 and digits.len != 2: break dayOfMonthBlock
+        var n = 0
+        for c in digits:
+          if c notin AsciiDigit: break dayOfMonthBlock
+          n *= 10
+          n += c.decValue
+        dayOfMonth = n
+        foundDayOfMonth = true
+        continue
+    if not foundMonth:
+      block monthBlock: # test for month
+        if dateToken.len < 3: break monthBlock
+        case dateToken.substr(0, 2).toLower()
+        of "jan": month = 1
+        of "feb": month = 2
+        of "mar": month = 3
+        of "apr": month = 4
+        of "may": month = 5
+        of "jun": month = 6
+        of "jul": month = 7
+        of "aug": month = 8
+        of "sep": month = 9
+        of "oct": month = 10
+        of "nov": month = 11
+        of "dec": month = 12
+        else: break monthBlock
+        foundMonth = true
+        continue
+    if not foundYear:
+      block yearBlock: # test for year
+        let digits = dateToken.until(NonDigit)
+        if digits.len != 2 and digits.len != 4: break yearBlock
+        var n = 0
+        for c in digits:
+          if c notin AsciiDigit: break yearBlock
+          n *= 10
+          n += c.decValue
+        year = n
+        foundYear = true
+        continue
+  if not (foundDayOfMonth and foundMonth and foundYear and foundTime): return none(DateTime)
+  if dayOfMonth notin 0..31: return none(DateTime)
+  if year < 1601: return none(DateTime)
+  if time[0] > 23: return none(DateTime)
+  if time[1] > 59: return none(DateTime)
+  if time[2] > 59: return none(DateTime)
+  var dateTime = dateTime(year, Month(month), MonthdayRange(dayOfMonth), HourRange(time[0]), MinuteRange(time[1]), SecondRange(time[2]))
+  return some(dateTime)
+
+proc newCookie(str: string): Cookie {.jsctor.} =
+  let cookie = new(Cookie)
+  var first = true
+  for part in str.split(';'):
+    if first:
+      cookie.name = part.until('=')
+      cookie.value = part.after('=')
+      first = false
+      continue
+    let part = percentDecode(part).strip(leading = true, trailing = false, AsciiWhitespace)
+    var n = 0
+    for i in 0..part.high:
+      if part[i] == '=':
+        n = i
+        break
+    if n == 0:
+      continue
+    let key = part.substr(0, n - 1)
+    let val = part.substr(n + 1)
+    case key.toLower()
+    of "expires":
+      let date = parseCookieDate(val)
+      if date.issome:
+        cookie.expires = date.get.toTime().toUnix()
+    of "max-age": cookie.maxAge = parseInt64(val)
+    of "secure": cookie.secure = true
+    of "httponly": cookie.httponly = true
+    of "samesite": cookie.samesite = true
+    of "path": cookie.path = val
+    of "domain": cookie.domain = val
+  return cookie
+
+proc addCookieModule*(ctx: JSContext) =
+  ctx.registerType(Cookie)