mirror of
https://github.com/status-im/nim-chronos.git
synced 2025-01-20 16:29:12 +00:00
Enable comma as array delimiter and adding tests. (#191)
* Enable comma as array delimiter and adding tests. * Bump version to 3.0.4.
This commit is contained in:
parent
67f0f1224f
commit
7ccb170f7a
@ -1,5 +1,5 @@
|
||||
packageName = "chronos"
|
||||
version = "3.0.3"
|
||||
version = "3.0.4"
|
||||
author = "Status Research & Development GmbH"
|
||||
description = "Chronos"
|
||||
license = "Apache License 2.0 or MIT"
|
||||
|
@ -53,12 +53,20 @@ type
|
||||
HttpRedirectError* = object of HttpError
|
||||
HttpAddressError* = object of HttpError
|
||||
|
||||
KeyValueTuple* = tuple
|
||||
key: string
|
||||
value: string
|
||||
|
||||
TransferEncodingFlags* {.pure.} = enum
|
||||
Identity, Chunked, Compress, Deflate, Gzip
|
||||
|
||||
ContentEncodingFlags* {.pure.} = enum
|
||||
Identity, Br, Compress, Deflate, Gzip
|
||||
|
||||
QueryParamsFlag* {.pure.} = enum
|
||||
CommaSeparatedArray ## Enable usage of comma symbol as separator of array
|
||||
## items
|
||||
|
||||
proc raiseHttpCriticalError*(msg: string,
|
||||
code = Http400) {.noinline, noreturn.} =
|
||||
raise (ref HttpCriticalError)(code: code, msg: msg)
|
||||
@ -99,7 +107,8 @@ template newHttpReadError*(message: string): ref HttpReadError =
|
||||
template newHttpWriteError*(message: string): ref HttpWriteError =
|
||||
newException(HttpWriteError, message)
|
||||
|
||||
iterator queryParams*(query: string): tuple[key: string, value: string] {.
|
||||
iterator queryParams*(query: string,
|
||||
flags: set[QueryParamsFlag] = {}): KeyValueTuple {.
|
||||
raises: [Defect].} =
|
||||
## Iterate over url-encoded query string.
|
||||
for pair in query.split('&'):
|
||||
@ -107,7 +116,12 @@ iterator queryParams*(query: string): tuple[key: string, value: string] {.
|
||||
let k = items[0]
|
||||
if len(k) > 0:
|
||||
let v = if len(items) > 1: items[1] else: ""
|
||||
yield (decodeUrl(k), decodeUrl(v))
|
||||
if CommaSeparatedArray in flags:
|
||||
let key = decodeUrl(k)
|
||||
for av in decodeUrl(v).split(','):
|
||||
yield (k, av)
|
||||
else:
|
||||
yield (decodeUrl(k), decodeUrl(v))
|
||||
|
||||
func getTransferEncoding*(ch: openarray[string]): HttpResult[
|
||||
set[TransferEncodingFlags]] {.
|
||||
|
@ -16,7 +16,15 @@ export httptable, httpcommon, httputils, multipart, asyncstream,
|
||||
|
||||
type
|
||||
HttpServerFlags* {.pure.} = enum
|
||||
Secure, NoExpectHandler, NotifyDisconnect
|
||||
Secure,
|
||||
## Internal flag which indicates that server working in secure TLS mode
|
||||
NoExpectHandler,
|
||||
## Do not handle `Expect` header automatically
|
||||
NotifyDisconnect,
|
||||
## Notify user-callback when remote client disconnects.
|
||||
QueryCommaSeparatedArray
|
||||
## Enable usage of comma as an array item delimiter in url-encoded
|
||||
## entities (e.g. query string or POST body).
|
||||
|
||||
HttpServerError* {.pure.} = enum
|
||||
TimeoutError, CatchableError, RecoverableError, CriticalError,
|
||||
@ -49,7 +57,8 @@ type
|
||||
|
||||
HttpConnectionCallback* =
|
||||
proc(server: HttpServerRef,
|
||||
transp: StreamTransport): Future[HttpConnectionRef] {.gcsafe, raises: [Defect].}
|
||||
transp: StreamTransport): Future[HttpConnectionRef] {.
|
||||
gcsafe, raises: [Defect].}
|
||||
|
||||
HttpServer* = object of RootObj
|
||||
instance*: StreamServer
|
||||
@ -275,8 +284,13 @@ proc prepareRequest(conn: HttpConnectionRef,
|
||||
|
||||
request.query =
|
||||
block:
|
||||
let queryFlags =
|
||||
if QueryCommaSeparatedArray in conn.server.flags:
|
||||
{QueryParamsFlag.CommaSeparatedArray}
|
||||
else:
|
||||
{}
|
||||
var table = HttpTable.init()
|
||||
for key, value in queryParams(request.uri.query):
|
||||
for key, value in queryParams(request.uri.query, queryFlags):
|
||||
table.add(key, value)
|
||||
table
|
||||
|
||||
@ -775,6 +789,11 @@ proc post*(req: HttpRequestRef): Future[HttpTable] {.async.} =
|
||||
return HttpTable.init()
|
||||
|
||||
if UrlencodedForm in req.requestFlags:
|
||||
let queryFlags =
|
||||
if QueryCommaSeparatedArray in req.connection.server.flags:
|
||||
{QueryParamsFlag.CommaSeparatedArray}
|
||||
else:
|
||||
{}
|
||||
var table = HttpTable.init()
|
||||
# getBody() will handle `Expect`.
|
||||
var body = await req.getBody()
|
||||
@ -783,7 +802,7 @@ proc post*(req: HttpRequestRef): Future[HttpTable] {.async.} =
|
||||
var strbody = newString(len(body))
|
||||
if len(body) > 0:
|
||||
copyMem(addr strbody[0], addr body[0], len(body))
|
||||
for key, value in queryParams(strbody):
|
||||
for key, value in queryParams(strbody, queryFlags):
|
||||
table.add(key, value)
|
||||
req.postTable = some(table)
|
||||
return table
|
||||
|
@ -7,7 +7,8 @@
|
||||
# MIT license (LICENSE-MIT)
|
||||
import std/[strutils, algorithm, strutils]
|
||||
import unittest2
|
||||
import ../chronos, ../chronos/apps/http/httpserver
|
||||
import ../chronos, ../chronos/apps/http/httpserver,
|
||||
../chronos/apps/http/httpcommon
|
||||
import stew/base10
|
||||
|
||||
when defined(nimHasUsed): {.used.}
|
||||
@ -819,6 +820,41 @@ suite "HTTP server testing suite":
|
||||
getContentEncoding([]).tryGet() == { ContentEncodingFlags.Identity }
|
||||
getContentEncoding(["", ""]).tryGet() == { ContentEncodingFlags.Identity }
|
||||
|
||||
test "queryParams() test":
|
||||
const Vectors = [
|
||||
("id=1&id=2&id=3&id=4", {}, "id:1,id:2,id:3,id:4"),
|
||||
("id=1,2,3,4", {}, "id:1,2,3,4"),
|
||||
("id=1%2C2%2C3%2C4", {}, "id:1,2,3,4"),
|
||||
("id=", {}, "id:"),
|
||||
("id=&id=", {}, "id:,id:"),
|
||||
("id=1&id=2&id=3&id=4", {QueryParamsFlag.CommaSeparatedArray},
|
||||
"id:1,id:2,id:3,id:4"),
|
||||
("id=1,2,3,4", {QueryParamsFlag.CommaSeparatedArray},
|
||||
"id:1,id:2,id:3,id:4"),
|
||||
("id=1%2C2%2C3%2C4", {QueryParamsFlag.CommaSeparatedArray},
|
||||
"id:1,id:2,id:3,id:4"),
|
||||
("id=", {QueryParamsFlag.CommaSeparatedArray}, "id:"),
|
||||
("id=&id=", {QueryParamsFlag.CommaSeparatedArray}, "id:,id:"),
|
||||
("id=,", {QueryParamsFlag.CommaSeparatedArray}, "id:,id:"),
|
||||
("id=,,", {QueryParamsFlag.CommaSeparatedArray}, "id:,id:,id:"),
|
||||
("id=1&id=2&id=3,4,5,6&id=7%2C8%2C9%2C10",
|
||||
{QueryParamsFlag.CommaSeparatedArray},
|
||||
"id:1,id:2,id:3,id:4,id:5,id:6,id:7,id:8,id:9,id:10")
|
||||
]
|
||||
|
||||
proc toString(ht: HttpTable): string =
|
||||
var res: seq[string]
|
||||
for key, value in ht.items():
|
||||
for item in value:
|
||||
res.add(key & ":" & item)
|
||||
res.join(",")
|
||||
|
||||
for vector in Vectors:
|
||||
var table = HttpTable.init()
|
||||
for key, value in queryParams(vector[0], vector[1]):
|
||||
table.add(key, value)
|
||||
check toString(table) == vector[2]
|
||||
|
||||
test "Leaks test":
|
||||
check:
|
||||
getTracker("async.stream.reader").isLeaked() == false
|
||||
|
Loading…
x
Reference in New Issue
Block a user