mirror of
https://github.com/nim-lang/Nim.git
synced 2026-07-22 00:41:28 +00:00
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.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user