From c31e4537fe2578a4f08b836439282080b78ed303 Mon Sep 17 00:00:00 2001 From: Eugene Kabanov Date: Tue, 2 Mar 2021 15:26:07 +0200 Subject: [PATCH] Fix contentType handling code. (#162) Add more respond() aliases. Add responded() to check if response is already sent. --- chronos/apps/http/httpcommon.nim | 4 +++- chronos/apps/http/httpserver.nim | 34 +++++++++++++++++++++++++------- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/chronos/apps/http/httpcommon.nim b/chronos/apps/http/httpcommon.nim index 45fafec..598deca 100644 --- a/chronos/apps/http/httpcommon.nim +++ b/chronos/apps/http/httpcommon.nim @@ -148,7 +148,9 @@ func getContentEncoding*(ch: openarray[string]): HttpResult[ func getContentType*(ch: openarray[string]): HttpResult[string] {. raises: [Defect].} = ## Check and prepare value of ``Content-Type`` header. - if len(ch) > 1: + if len(ch) == 0: + err("No Content-Type values found") + elif len(ch) > 1: err("Multiple Content-Type values found") else: let mparts = ch[0].split(";") diff --git a/chronos/apps/http/httpserver.nim b/chronos/apps/http/httpserver.nim index 797110c..98b4058 100644 --- a/chronos/apps/http/httpserver.nim +++ b/chronos/apps/http/httpserver.nim @@ -93,7 +93,7 @@ type headersTable: HttpTable body: seq[byte] flags: set[HttpResponseFlags] - state: HttpResponseState + state*: HttpResponseState connection*: HttpConnectionRef chunkedWriter: AsyncStreamWriter @@ -111,6 +111,8 @@ type HttpConnectionRef* = ref HttpConnection + ByteChar* = string | seq[byte] + proc init(htype: typedesc[HttpProcessError], error: HTTPServerError, exc: ref CatchableError, remote: TransportAddress, code: HttpCode): HttpProcessError {.raises: [Defect].} = @@ -925,7 +927,7 @@ proc sendBody*(resp: HttpResponseRef, pbytes: pointer, nbytes: int) {.async.} = resp.state = HttpResponseState.Failed raiseHttpCriticalError("Unable to send response") -proc sendBody*[T: string|seq[byte]](resp: HttpResponseRef, data: T) {.async.} = +proc sendBody*(resp: HttpResponseRef, data: ByteChar) {.async.} = ## Send HTTP response at once by using data ``data``. checkPending(resp) let responseHeaders = resp.prepareLengthHeaders(len(data)) @@ -1000,8 +1002,7 @@ proc sendChunk*(resp: HttpResponseRef, pbytes: pointer, nbytes: int) {.async.} = resp.state = HttpResponseState.Failed raiseHttpCriticalError("Unable to send response") -proc sendChunk*[T: string|seq[byte]](resp: HttpResponseRef, - data: T) {.async.} = +proc sendChunk*(resp: HttpResponseRef, data: ByteChar) {.async.} = ## Send single chunk of data ``data``. if HttpResponseFlags.Chunked notin resp.flags: raiseHttpCriticalError("Response was not prepared") @@ -1035,10 +1036,10 @@ proc finish*(resp: HttpResponseRef) {.async.} = resp.state = HttpResponseState.Failed raiseHttpCriticalError("Unable to send response") -proc respond*(req: HttpRequestRef, code: HttpCode, content: string, +proc respond*(req: HttpRequestRef, code: HttpCode, content: ByteChar, headers: HttpTable): Future[HttpResponseRef] {.async.} = - ## Responds to the request with the specified ``HttpCode``, headers and - ## content. + ## Responds to the request with the specified ``HttpCode``, HTTP ``headers`` + ## and ``content``. let response = req.getResponse() response.status = code for k, v in headers.stringItems(): @@ -1046,6 +1047,25 @@ proc respond*(req: HttpRequestRef, code: HttpCode, content: string, await response.sendBody(content) return response +proc respond*(req: HttpRequestRef, code: HttpCode, + content: ByteChar): Future[HttpResponseRef] = + ## Responds to the request with specified ``HttpCode`` and ``content``. + respond(req, code, content, HttpTable.init()) + +proc respond*(req: HttpRequestRef, code: HttpCode): Future[HttpResponseRef] = + ## Reponds to the request with specified ``HttpCode`` only. + respond(req, code, "", HttpTable.init()) + +proc responded*(req: HttpRequestRef): bool = + ## Returns ``true`` if request ``req`` has been responded or responding. + if isSome(req.response): + if req.response.get().state == HttpResponseState.Empty: + false + else: + true + else: + false + proc remoteAddress*(conn: HttpConnectionRef): TransportAddress = ## Returns address of the remote host that established connection ``conn``. conn.transp.remoteAddress()