diff options
author | wonderix <ulrich.kramer@web.de> | 2020-04-22 17:43:39 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-22 17:43:39 +0200 |
commit | 5571d48c327e8bc9667d95b46f87e73c643a94a6 (patch) | |
tree | 1d619280948c174f95a3062250a3c8f50823836f /lib/pure | |
parent | 269a458d74e9abbc126d96c506b730c37af0932a (diff) | |
download | Nim-5571d48c327e8bc9667d95b46f87e73c643a94a6.tar.gz |
Add the ability to pass title case headers to an HTTP server (#13968)
* Add the ability to pass title case headers to an HTTP server * Remove unnecessary type spec of titleCase * Replace convert member proc by isTitleCase Co-authored-by: wonderix <wonderix@googlemail.com>
Diffstat (limited to 'lib/pure')
-rw-r--r-- | lib/pure/httpcore.nim | 50 |
1 files changed, 38 insertions, 12 deletions
diff --git a/lib/pure/httpcore.nim b/lib/pure/httpcore.nim index 8916aa17d..78cb66ded 100644 --- a/lib/pure/httpcore.nim +++ b/lib/pure/httpcore.nim @@ -17,6 +17,7 @@ import tables, strutils, parseutils type HttpHeaders* = ref object table*: TableRef[string, seq[string]] + isTitleCase: bool HttpHeaderValues* = distinct seq[string] @@ -100,16 +101,32 @@ const const httpNewLine* = "\c\L" const headerLimit* = 10_000 -proc newHttpHeaders*(): HttpHeaders = +proc toTitleCase(s: string): string = + result = newString(len(s)) + var upper = true + for i in 0..len(s) - 1: + result[i] = if upper: toUpperAscii(s[i]) else: toLowerAscii(s[i]) + upper = s[i] == '-' + +proc toCaseInsensitive(headers: HttpHeaders, s: string): string {.inline.} = + return if headers.isTitleCase: toTitleCase(s) else: toLowerAscii(s) + +proc newHttpHeaders*(titleCase=false): HttpHeaders = + ## Returns a new ``HttpHeaders`` object. if ``titleCase`` is set to true, + ## headers are passed to the server in title case (e.g. "Content-Length") new result result.table = newTable[string, seq[string]]() + result.isTitleCase = titleCase proc newHttpHeaders*(keyValuePairs: - openArray[tuple[key: string, val: string]]): HttpHeaders = + openArray[tuple[key: string, val: string]], titleCase=false): HttpHeaders = + ## Returns a new ``HttpHeaders`` object from an array. if ``titleCase`` is set to true, + ## headers are passed to the server in title case (e.g. "Content-Length") new result result.table = newTable[string, seq[string]]() + result.isTitleCase = titleCase for pair in keyValuePairs: - let key = pair.key.toLowerAscii() + let key = result.toCaseInsensitive(pair.key) if key in result.table: result.table[key].add(pair.val) else: @@ -130,7 +147,7 @@ proc `[]`*(headers: HttpHeaders, key: string): HttpHeaderValues = ## ## To access multiple values of a key, use the overloaded ``[]`` below or ## to get all of them access the ``table`` field directly. - return headers.table[key.toLowerAscii].HttpHeaderValues + return headers.table[headers.toCaseInsensitive(key)].HttpHeaderValues converter toString*(values: HttpHeaderValues): string = return seq[string](values)[0] @@ -139,30 +156,30 @@ proc `[]`*(headers: HttpHeaders, key: string, i: int): string = ## Returns the ``i``'th value associated with the given key. If there are ## no values associated with the key or the ``i``'th value doesn't exist, ## an exception is raised. - return headers.table[key.toLowerAscii][i] + return headers.table[headers.toCaseInsensitive(key)][i] proc `[]=`*(headers: HttpHeaders, key, value: string) = ## Sets the header entries associated with ``key`` to the specified value. ## Replaces any existing values. - headers.table[key.toLowerAscii] = @[value] + headers.table[headers.toCaseInsensitive(key)] = @[value] proc `[]=`*(headers: HttpHeaders, key: string, value: seq[string]) = ## Sets the header entries associated with ``key`` to the specified list of ## values. ## Replaces any existing values. - headers.table[key.toLowerAscii] = value + headers.table[headers.toCaseInsensitive(key)] = value proc add*(headers: HttpHeaders, key, value: string) = ## Adds the specified value to the specified key. Appends to any existing ## values associated with the key. - if not headers.table.hasKey(key.toLowerAscii): - headers.table[key.toLowerAscii] = @[value] + if not headers.table.hasKey(headers.toCaseInsensitive(key)): + headers.table[headers.toCaseInsensitive(key)] = @[value] else: - headers.table[key.toLowerAscii].add(value) + headers.table[headers.toCaseInsensitive(key)].add(value) proc del*(headers: HttpHeaders, key: string) = ## Delete the header entries associated with ``key`` - headers.table.del(key.toLowerAscii) + headers.table.del(headers.toCaseInsensitive(key)) iterator pairs*(headers: HttpHeaders): tuple[key, value: string] = ## Yields each key, value pair. @@ -177,7 +194,7 @@ proc contains*(values: HttpHeaderValues, value: string): bool = if val.toLowerAscii == value.toLowerAscii: return true proc hasKey*(headers: HttpHeaders, key: string): bool = - return headers.table.hasKey(key.toLowerAscii()) + return headers.table.hasKey(headers.toCaseInsensitive(key)) proc getOrDefault*(headers: HttpHeaders, key: string, default = @[""].HttpHeaderValues): HttpHeaderValues = @@ -336,3 +353,12 @@ when isMainModule: doAssert test["foobar"] == "" doAssert parseHeader("foobar:") == ("foobar", @[""]) + + block: # test title case + var testTitleCase = newHttpHeaders(titleCase=true) + testTitleCase.add("content-length", "1") + doAssert testTitleCase.hasKey("Content-Length") + for key, val in testTitleCase: + doAssert key == "Content-Length" + + |