-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
Option to allow the request body to be processed outside the asynchttpserver library. #13147
Changes from 4 commits
4fdbf8f
36e708f
6437c7a
5c8dbf0
f458d0c
83cc79c
c110f90
a8ac8a5
2dfcae4
dbc527e
7ca4441
e5a2aed
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,6 +37,7 @@ export httpcore except parseHeader | |
|
||
const | ||
maxLine = 8*1024 | ||
chunkSize = 1048 | ||
|
||
# TODO: If it turns out that the decisions that asynchttpserver makes | ||
# explicitly, about whether to close the client sockets or upgrade them are | ||
|
@@ -52,6 +53,7 @@ type | |
url*: Uri | ||
hostname*: string ## The hostname of the client that made the request. | ||
body*: string | ||
bodyStream*: FutureStream[string] | ||
|
||
AsyncHttpServer* = ref object | ||
socket: AsyncSocket | ||
|
@@ -128,6 +130,20 @@ 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") | ||
|
||
proc parseUppercaseMethod(name: string): HttpMethod = | ||
result = | ||
case name | ||
of "GET": HttpGet | ||
of "POST": HttpPost | ||
of "HEAD": HttpHead | ||
of "PUT": HttpPut | ||
of "DELETE": HttpDelete | ||
of "PATCH": HttpPatch | ||
of "OPTIONS": HttpOptions | ||
of "CONNECT": HttpConnect | ||
of "TRACE": HttpTrace | ||
else: raise newException(ValueError, "Invalid HTTP method " & name) | ||
|
||
proc processRequest( | ||
server: AsyncHttpServer, | ||
req: FutureVar[Request], | ||
|
@@ -149,6 +165,7 @@ proc processRequest( | |
request.hostname.shallowCopy(address) | ||
assert client != nil | ||
request.client = client | ||
request.bodyStream = newFutureStream[string]() | ||
|
||
# We should skip at least one empty line before the request | ||
# https://tools.ietf.org/html/rfc7230#section-3.5 | ||
|
@@ -173,17 +190,9 @@ proc processRequest( | |
for linePart in lineFut.mget.split(' '): | ||
case i | ||
of 0: | ||
case linePart | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I liked the inline There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I didn't touch this part of the library. Maybe Dominik Picheta can see this part. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you based your patch on something else but There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I based my patch on nim devel. |
||
of "GET": request.reqMethod = HttpGet | ||
of "POST": request.reqMethod = HttpPost | ||
of "HEAD": request.reqMethod = HttpHead | ||
of "PUT": request.reqMethod = HttpPut | ||
of "DELETE": request.reqMethod = HttpDelete | ||
of "PATCH": request.reqMethod = HttpPatch | ||
of "OPTIONS": request.reqMethod = HttpOptions | ||
of "CONNECT": request.reqMethod = HttpConnect | ||
of "TRACE": request.reqMethod = HttpTrace | ||
else: | ||
try: | ||
request.reqMethod = parseUppercaseMethod(linePart) | ||
except ValueError: | ||
asyncCheck request.respondError(Http400) | ||
return true # Retry processing of request | ||
of 1: | ||
|
@@ -236,17 +245,36 @@ proc processRequest( | |
# - Check for Content-length header | ||
if request.headers.hasKey("Content-Length"): | ||
var contentLength = 0 | ||
if parseSaturatedNatural(request.headers["Content-Length"], contentLength) == 0: | ||
if parseSaturatedNatural(request.headers["Content-Length"], | ||
contentLength) == 0: | ||
await request.respond(Http400, "Bad Request. Invalid Content-Length.") | ||
return true | ||
else: | ||
if contentLength > server.maxBody: | ||
await request.respondError(Http413) | ||
return false | ||
request.body = await client.recv(contentLength) | ||
if request.body.len != contentLength: | ||
|
||
var remainder = contentLength | ||
while remainder > 0: | ||
let read_size = if remainder < chunkSize: remainder else: chunkSize | ||
mrhdias marked this conversation as resolved.
Show resolved
Hide resolved
|
||
let data = await client.recv(read_size) | ||
if data.len != read_size: | ||
await request.respond(Http500, "Internal Server Error. An error occurred while reading the request body.") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How do you know it's not
|
||
return true | ||
await request.bodyStream.write(data) | ||
remainder -= data.len | ||
|
||
if remainder > 0: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. By construction we know that |
||
await request.respond(Http400, "Bad Request. Content-Length does not match actual.") | ||
return true | ||
|
||
request.bodyStream.complete() | ||
|
||
## 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 | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I put the annotation I get this error:
Error: constant expression expected
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bah, what's up with that...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Works if outside of type declaration