Skip to content

Commit

Permalink
Add support for Transfer-Encoding: chunked (#16636)
Browse files Browse the repository at this point in the history
* Add support for Transfer-Encoding: chunked

* Minor whitespace fixes

* Use recv instead of recvLineInto

* Undo changes to httpcore, inline changes
  • Loading branch information
vabresto committed Jan 10, 2021
1 parent dbff2cd commit 65df576
Showing 1 changed file with 44 additions and 0 deletions.
44 changes: 44 additions & 0 deletions lib/pure/asynchttpserver.nim
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,17 @@ proc parseProtocol(protocol: string): tuple[orig: string, major, minor: int] =
proc sendStatus(client: AsyncSocket, status: string): Future[void] =
client.send("HTTP/1.1 " & status & "\c\L\c\L")

func hasChunkedEncoding(request: Request): bool =
## Searches for a chunked transfer encoding
const transferEncoding = "Transfer-Encoding"

if request.headers.hasKey(transferEncoding):
for encoding in seq[string](request.headers[transferEncoding]):
if "chunked" == encoding.strip:
# Returns true if it is both an HttpPost and has chunked encoding
return request.reqMethod == HttpPost
return false

proc processRequest(
server: AsyncHttpServer,
req: FutureVar[Request],
Expand Down Expand Up @@ -261,6 +272,39 @@ proc processRequest(
if request.body.len != contentLength:
await request.respond(Http400, "Bad Request. Content-Length does not match actual.")
return true
elif hasChunkedEncoding(request):
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Transfer-Encoding
var sizeOrData = 0
var bytesToRead = 0
request.body = ""

while true:
lineFut.mget.setLen(0)
lineFut.clean()

# The encoding format alternates between specifying a number of bytes to read
# and the data to be read, of the previously specified size
if sizeOrData mod 2 == 0:
# Expect a number of chars to read
await client.recvLineInto(lineFut, maxLength = maxLine)
try:
bytesToRead = lineFut.mget.parseHexInt
except ValueError:
# Malformed request
await request.respond(Http411, ("Invalid chunked transfer encoding - " &
"chunk data size must be hex encoded"))
return true
else:
if bytesToRead == 0:
# Done reading chunked data
break

# Read bytesToRead and add to body
# Note we add +2 because the line must be terminated by \r\n
let chunk = await client.recv(bytesToRead + 2)
request.body = request.body & chunk

inc sizeOrData
elif request.reqMethod == HttpPost:
await request.respond(Http411, "Content-Length required.")
return true
Expand Down

0 comments on commit 65df576

Please sign in to comment.