AsyncHttpServer now supports POST.
This commit is contained in:
parent
9ea0d0c59e
commit
f830aed869
2 changed files with 34 additions and 8 deletions
|
|
@ -779,6 +779,7 @@ proc accept*(socket: TAsyncFD): PFuture[TAsyncFD] =
|
||||||
template createCb*(retFutureSym, iteratorNameSym,
|
template createCb*(retFutureSym, iteratorNameSym,
|
||||||
name: expr): stmt {.immediate.} =
|
name: expr): stmt {.immediate.} =
|
||||||
var nameIterVar = iteratorNameSym
|
var nameIterVar = iteratorNameSym
|
||||||
|
#{.push stackTrace: off.}
|
||||||
proc cb {.closure,gcsafe.} =
|
proc cb {.closure,gcsafe.} =
|
||||||
try:
|
try:
|
||||||
if not nameIterVar.finished:
|
if not nameIterVar.finished:
|
||||||
|
|
@ -791,7 +792,7 @@ template createCb*(retFutureSym, iteratorNameSym,
|
||||||
except:
|
except:
|
||||||
retFutureSym.fail(getCurrentException())
|
retFutureSym.fail(getCurrentException())
|
||||||
cb()
|
cb()
|
||||||
|
#{.pop.}
|
||||||
proc generateExceptionCheck(futSym,
|
proc generateExceptionCheck(futSym,
|
||||||
exceptBranch, rootReceiver: PNimrodNode): PNimrodNode {.compileTime.} =
|
exceptBranch, rootReceiver: PNimrodNode): PNimrodNode {.compileTime.} =
|
||||||
if exceptBranch == nil:
|
if exceptBranch == nil:
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ type
|
||||||
protocol*: tuple[orig: string, major, minor: int]
|
protocol*: tuple[orig: string, major, minor: int]
|
||||||
url*: TURL
|
url*: TURL
|
||||||
hostname*: string ## The hostname of the client that made the request.
|
hostname*: string ## The hostname of the client that made the request.
|
||||||
body*: string # TODO
|
body*: string
|
||||||
|
|
||||||
PAsyncHttpServer* = ref object
|
PAsyncHttpServer* = ref object
|
||||||
socket: PAsyncSocket
|
socket: PAsyncSocket
|
||||||
|
|
@ -78,7 +78,7 @@ proc parseHeader(line: string): tuple[key, value: string] =
|
||||||
i += line.skipWhiteSpace(i)
|
i += line.skipWhiteSpace(i)
|
||||||
i += line.parseUntil(result.value, {'\c', '\L'}, i)
|
i += line.parseUntil(result.value, {'\c', '\L'}, i)
|
||||||
|
|
||||||
proc parseProtocol(protocol: string): tuple[orig: string, major, minor: int] =
|
proc parseProtocol(protocol: string): tuple[orig: string, major, minor: int] =
|
||||||
var i = protocol.skipIgnoreCase("HTTP/")
|
var i = protocol.skipIgnoreCase("HTTP/")
|
||||||
if i != 5:
|
if i != 5:
|
||||||
raise newException(EInvalidValue, "Invalid request protocol. Got: " &
|
raise newException(EInvalidValue, "Invalid request protocol. Got: " &
|
||||||
|
|
@ -88,6 +88,9 @@ proc parseProtocol(protocol: string): tuple[orig: string, major, minor: int] =
|
||||||
i.inc # Skip .
|
i.inc # Skip .
|
||||||
i.inc protocol.parseInt(result.minor, i)
|
i.inc protocol.parseInt(result.minor, i)
|
||||||
|
|
||||||
|
proc sendStatus(client: PAsyncSocket, status: string): PFuture[void] =
|
||||||
|
client.send("HTTP/1.1 " & status & "\c\L")
|
||||||
|
|
||||||
proc processClient(client: PAsyncSocket, address: string,
|
proc processClient(client: PAsyncSocket, address: string,
|
||||||
callback: proc (request: TRequest): PFuture[void]) {.async.} =
|
callback: proc (request: TRequest): PFuture[void]) {.async.} =
|
||||||
# GET /path HTTP/1.1
|
# GET /path HTTP/1.1
|
||||||
|
|
@ -97,6 +100,7 @@ proc processClient(client: PAsyncSocket, address: string,
|
||||||
request.hostname = address
|
request.hostname = address
|
||||||
assert client != nil
|
assert client != nil
|
||||||
request.client = client
|
request.client = client
|
||||||
|
var runCallback = true
|
||||||
|
|
||||||
# First line - GET /path HTTP/1.1
|
# First line - GET /path HTTP/1.1
|
||||||
let line = await client.recvLine() # TODO: Timeouts.
|
let line = await client.recvLine() # TODO: Timeouts.
|
||||||
|
|
@ -106,8 +110,7 @@ proc processClient(client: PAsyncSocket, address: string,
|
||||||
let lineParts = line.split(' ')
|
let lineParts = line.split(' ')
|
||||||
if lineParts.len != 3:
|
if lineParts.len != 3:
|
||||||
request.respond(Http400, "Invalid request. Got: " & line)
|
request.respond(Http400, "Invalid request. Got: " & line)
|
||||||
client.close()
|
runCallback = false
|
||||||
return
|
|
||||||
|
|
||||||
let reqMethod = lineParts[0]
|
let reqMethod = lineParts[0]
|
||||||
let path = lineParts[1]
|
let path = lineParts[1]
|
||||||
|
|
@ -132,13 +135,35 @@ proc processClient(client: PAsyncSocket, address: string,
|
||||||
request.protocol = protocol.parseProtocol()
|
request.protocol = protocol.parseProtocol()
|
||||||
except EInvalidValue:
|
except EInvalidValue:
|
||||||
request.respond(Http400, "Invalid request protocol. Got: " & protocol)
|
request.respond(Http400, "Invalid request protocol. Got: " & protocol)
|
||||||
return
|
runCallback = false
|
||||||
|
|
||||||
|
if reqMethod.normalize == "post":
|
||||||
|
# Check for Expect header
|
||||||
|
if request.headers.hasKey("Expect"):
|
||||||
|
if request.headers["Expect"].toLower == "100-continue":
|
||||||
|
await client.sendStatus("100 Continue")
|
||||||
|
else:
|
||||||
|
await client.sendStatus("417 Expectation Failed")
|
||||||
|
|
||||||
|
# Read the body
|
||||||
|
# - Check for Content-length header
|
||||||
|
if request.headers.hasKey("Content-Length"):
|
||||||
|
var contentLength = 0
|
||||||
|
if parseInt(request.headers["Content-Length"], contentLength) == 0:
|
||||||
|
await request.respond(Http400, "Bad Request. Invalid Content-Length.")
|
||||||
|
else:
|
||||||
|
request.body = await client.recv(contentLength)
|
||||||
|
assert request.body.len == contentLength
|
||||||
|
else:
|
||||||
|
await request.respond(Http400, "Bad Request. No Content-Length.")
|
||||||
|
runCallback = false
|
||||||
|
|
||||||
case reqMethod.normalize
|
case reqMethod.normalize
|
||||||
of "get", "post", "head", "put", "delete", "trace", "options", "connect", "patch":
|
of "get", "post", "head", "put", "delete", "trace", "options", "connect", "patch":
|
||||||
await callback(request)
|
if runCallback:
|
||||||
|
await callback(request)
|
||||||
else:
|
else:
|
||||||
request.respond(Http400, "Invalid request method. Got: " & reqMethod)
|
await request.respond(Http400, "Invalid request method. Got: " & reqMethod)
|
||||||
|
|
||||||
# Persistent connections
|
# Persistent connections
|
||||||
if (request.protocol == HttpVer11 and
|
if (request.protocol == HttpVer11 and
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue