nim-chronos/chronos/apps/http/httptable.nim

125 lines
3.2 KiB
Nim
Raw Normal View History

2021-01-27 06:14:17 +00:00
#
# Chronos HTTP/S case-insensitive non-unique
# key-value memory storage
# (c) Copyright 2019-Present
# Status Research & Development GmbH
#
# Licensed under either of
# Apache License, version 2.0, (LICENSE-APACHEv2)
# MIT license (LICENSE-MIT)
import std/[tables, strutils]
type
HttpTable* = object
table: Table[string, seq[string]]
HttpTableRef* = ref HttpTable
HttpTables* = HttpTable | HttpTableRef
proc `-`(x: uint32): uint32 {.inline.} =
(0xFFFF_FFFF'u32 - x) + 1'u32
proc LT(x, y: uint32): uint32 {.inline.} =
let z = x - y
(z xor ((y xor x) and (y xor z))) shr 31
proc decValue(c: byte): int =
let x = uint32(c) - 0x30'u32
let r = ((x + 1'u32) and -LT(x, 10))
int(r) - 1
proc bytesToDec*[T: byte|char](src: openarray[T]): uint64 =
var v = 0'u64
for i in 0 ..< len(src):
let d =
when T is byte:
decValue(src[i])
else:
decValue(byte(src[i]))
if d < 0:
# non-decimal character encountered
return v
else:
let nv = ((v shl 3) + (v shl 1)) + uint64(d)
if nv < v:
# overflow happened
return v
else:
v = nv
v
proc add*(ht: var HttpTables, key: string, value: string) =
let lowkey = key.toLowerAscii()
var nitem = @[value]
if ht.table.hasKeyOrPut(lowkey, nitem):
var oitem = ht.table[lowkey]
oitem.add(value)
ht.table[lowkey] = oitem
proc add*(ht: var HttpTables, key: string, value: SomeInteger) =
ht.add(key, $value)
proc contains*(ht: var HttpTables, key: string): bool =
ht.table.contains(key.toLowerAscii())
proc getList*(ht: HttpTables, key: string): seq[string] =
var default: seq[string]
ht.table.getOrDefault(key.toLowerAscii(), default)
proc getString*(ht: HttpTables, key: string): string =
var default: seq[string]
ht.table.getOrDefault(key.toLowerAscii(), default).join(",")
proc count*(ht: HttpTables, key: string): int =
var default: seq[string]
len(ht.table.getOrDefault(key, default))
proc getInt*(ht: HttpTables, key: string): uint64 =
bytesToDec(ht.getString(key))
proc getLastString*(ht: HttpTables, key: string): string =
var default: seq[string]
let item = ht.table.getOrDefault(key.toLowerAscii(), default)
if len(item) == 0:
""
else:
item[^1]
proc getLastInt*(ht: HttpTables, key: string): uint64 =
bytesToDec(ht.getLastString())
proc init*(htt: typedesc[HttpTable]): HttpTable =
HttpTable(table: initTable[string, seq[string]]())
proc new*(htt: typedesc[HttpTableRef]): HttpTableRef =
HttpTableRef(table: initTable[string, seq[string]]())
proc normalizeHeaderName*(value: string): string =
var res = value.toLowerAscii()
var k = 0
while k < len(res):
if k == 0:
res[k] = toUpperAscii(res[k])
inc(k, 1)
else:
if res[k] == '-':
if k + 1 < len(res):
res[k + 1] = toUpperAscii(res[k + 1])
inc(k, 2)
else:
break
else:
inc(k, 1)
res
proc `$`*(ht: HttpTables): string =
var res = ""
for key, value in ht.table.pairs():
for item in value:
res.add(key.normalizeHeaderName())
res.add(": ")
res.add(item)
res.add("\p")
res