Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Transfer-Encoding: chunked #16636

Merged
merged 4 commits into from
Jan 10, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,18 @@ 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
var isChunked = false
for encoding in request.headers.iter("Transfer-Encoding"):
if "chunked" == encoding.strip:
isChunked = true
break

return (request.reqMethod == HttpPost and
request.headers.hasKey("Transfer-Encoding") and
isChunked)

proc processRequest(
server: AsyncHttpServer,
req: FutureVar[Request],
Expand Down Expand Up @@ -261,6 +273,38 @@ 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
await client.recvLineInto(lineFut, maxLength = bytesToRead)
vabresto marked this conversation as resolved.
Show resolved Hide resolved
request.body = request.body & lineFut.mget

inc sizeOrData
elif request.reqMethod == HttpPost:
await request.respond(Http411, "Content-Length required.")
return true
Expand Down
7 changes: 7 additions & 0 deletions lib/pure/httpcore.nim
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,13 @@ proc `[]=`*(headers: HttpHeaders, key, value: string) =
## Replaces any existing values.
headers.table[headers.toCaseInsensitive(key)] = @[value]

iterator iter*(headers: HttpHeaders, key: string): string =
## Yields each value associated with the requested key
## If no such key exists, this does nothing.
if headers.table.contains(headers.toCaseInsensitive(key)):
for value in headers.table[headers.toCaseInsensitive(key)]:
yield value

vabresto marked this conversation as resolved.
Show resolved Hide resolved
proc `[]=`*(headers: HttpHeaders, key: string, value: seq[string]) =
## Sets the header entries associated with ``key`` to the specified list of
## values. Replaces any existing values. If ``value`` is empty,
Expand Down