Skip to content

Commit

Permalink
llow the request body to be processed outside the asynchttpserver lib…
Browse files Browse the repository at this point in the history
…rary.

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.

Example:

import asyncnet, asynchttpserver, asyncdispatch

proc test_page(): string =
  return """
<!Doctype html>
<html lang="en">
<head>
<meta charset="utf-8"/>
</head>
<body>
<form action="/test" method="post">
  Test: <input type="text" name="test" value="post test"><br/>
  <input type="submit">
</form>
</body>
</html>
"""

const chunkSize = 1024

var server = newAsyncHttpServer(maxBody=102400, handleBody=false)
proc cb(req: Request) {.async.} =
  if req.reqMethod == HttpPost:
    var body = ""
    var remainder = req.content_length
    while remainder > 0:
      let data = await req.client.recv(if remainder < chunkSize: remainder else: chunkSize)
      if data.len == 0:
        break
      body.add(data)
      remainder -= data.len

    if body.len != req.contentLength:
      await req.respond(Http400, "Bad Request. Content-Length does not match actual.")
    else:
      await req.respond(Http200, body)
    # req.client.close()
  else:
    await req.respond(Http200, test_page())

waitFor server.serve(Port(8080), cb)
  • Loading branch information
mrhdias authored Jan 14, 2020
1 parent 9fc04a5 commit 4fdbf8f
Showing 1 changed file with 13 additions and 5 deletions.
18 changes: 13 additions & 5 deletions lib/pure/asynchttpserver.nim
Original file line number Diff line number Diff line change
Expand Up @@ -52,20 +52,23 @@ type
url*: Uri
hostname*: string ## The hostname of the client that made the request.
body*: string
contentLength*: int

AsyncHttpServer* = ref object
socket: AsyncSocket
reuseAddr: bool
reusePort: bool
maxBody: int ## The maximum content-length that will be read for the body.
handleBody: bool ## if false leave the body for the developer to do whatever he wants with it.

proc newAsyncHttpServer*(reuseAddr = true, reusePort = false,
maxBody = 8388608): AsyncHttpServer =
maxBody = 8388608, handleBody = true): AsyncHttpServer =
## Creates a new ``AsyncHttpServer`` instance.
new result
result.reuseAddr = reuseAddr
result.reusePort = reusePort
result.maxBody = maxBody
result.handleBody = handleBody

proc addHeaders(msg: var string, headers: HttpHeaders) =
for k, v in headers:
Expand Down Expand Up @@ -146,6 +149,7 @@ proc processRequest(
# \n
request.headers.clear()
request.body = ""
request.contentLength = 0
request.hostname.shallowCopy(address)
assert client != nil
request.client = client
Expand Down Expand Up @@ -243,10 +247,14 @@ 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

request.contentLength = contentLength
if server.handleBody == true: # if false leave the body for the developer to do whatever he wants with it.
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
Expand Down

0 comments on commit 4fdbf8f

Please sign in to comment.