Add support for Transfer-Encoding: chunked (#16636)

* Add support for Transfer-Encoding: chunked

* Minor whitespace fixes

* Use recv instead of recvLineInto

* Undo changes to httpcore, inline changes
This commit is contained in:
vabresto
2021-01-10 06:42:23 -05:00
committed by GitHub
parent dbff2cd938
commit 65df5762a1

View File

@@ -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],
@@ -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