diff options
author | Henrique Dias <mrhdias@gmail.com> | 2020-02-04 20:13:25 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-02-04 21:13:25 +0100 |
commit | 955465e5f42b1353f69f3bd884908a7ef91ce13b (patch) | |
tree | 9d06255bcfda193677c13afcf4a08cf518c4d85f | |
parent | bfe96e069bbdfbbb7ee8979648abeaba233dfe19 (diff) | |
download | Nim-955465e5f42b1353f69f3bd884908a7ef91ce13b.tar.gz |
Option to allow the request body to be processed outside the asynchttpserver library. (#13147)
Allow the request body to be processed outside the asynchttpserver library to break big files into chunks of data. This change does not break anything.
-rw-r--r-- | changelog.md | 1 | ||||
-rw-r--r-- | lib/pure/asynchttpserver.nim | 64 |
2 files changed, 49 insertions, 16 deletions
diff --git a/changelog.md b/changelog.md index 3e498e7f8..36b8ef3d4 100644 --- a/changelog.md +++ b/changelog.md @@ -57,6 +57,7 @@ ## Library changes +- `asynchttpserver` now the request body is a FutureStream. - `asyncdispatch.drain` now properly takes into account `selector.hasPendingOperations` and only returns once all pending async operations are guaranteed to have completed. - `asyncdispatch.drain` now consistently uses the passed timeout value for all diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index 186f0da41..2754b128b 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -35,24 +35,41 @@ import httpcore export httpcore except parseHeader -const - maxLine = 8*1024 - # TODO: If it turns out that the decisions that asynchttpserver makes # explicitly, about whether to close the client sockets or upgrade them are # wrong, then add a return value which determines what to do for the callback. # Also, maybe move `client` out of `Request` object and into the args for # the proc. -type - Request* = object - client*: AsyncSocket # TODO: Separate this into a Response object? - reqMethod*: HttpMethod - headers*: HttpHeaders - protocol*: tuple[orig: string, major, minor: int] - url*: Uri - hostname*: string ## The hostname of the client that made the request. - body*: string +const + maxLine = 8*1024 + +when (NimMajor, NimMinor) >= (1, 1): + const + chunkSize = 8*1048 ## This seems perfectly reasonable for default chunkSize. + + type + Request* = object + client*: AsyncSocket # TODO: Separate this into a Response object? + reqMethod*: HttpMethod + headers*: HttpHeaders + protocol*: tuple[orig: string, major, minor: int] + url*: Uri + hostname*: string ## The hostname of the client that made the request. + body*: string + bodyStream*: FutureStream[string] +else: + type + Request* = object + client*: AsyncSocket # TODO: Separate this into a Response object? + reqMethod*: HttpMethod + headers*: HttpHeaders + protocol*: tuple[orig: string, major, minor: int] + url*: Uri + hostname*: string ## The hostname of the client that made the request. + body*: string + +type AsyncHttpServer* = ref object socket: AsyncSocket reuseAddr: bool @@ -149,6 +166,8 @@ proc processRequest( request.hostname.shallowCopy(address) assert client != nil request.client = client + when (NimMajor, NimMinor) >= (1, 1): + request.bodyStream = newFutureStream[string]() # We should skip at least one empty line before the request # https://tools.ietf.org/html/rfc7230#section-3.5 @@ -243,10 +262,23 @@ proc processRequest( if contentLength > server.maxBody: await request.respondError(Http413) return false - request.body = await client.recv(contentLength) - if request.body.len != contentLength: - await request.respond(Http400, "Bad Request. Content-Length does not match actual.") - return true + + when (NimMajor, NimMinor) >= (1, 1): + var remainder = contentLength + while remainder > 0: + let readSize = min(remainder, chunkSize) + let data = await client.recv(read_size) + if data.len != read_size: + await request.respond(Http400, "Bad Request. Content-Length does not match actual.") + return true + await request.bodyStream.write(data) + remainder -= data.len + request.bodyStream.complete() + else: + request.body = await client.recv(contentLength) + if request.body.len != contentLength: + await request.respond(Http400, "Bad Request. Content-Length does not match actual.") + return true elif request.reqMethod == HttpPost: await request.respond(Http411, "Content-Length required.") return true |