mirror of
https://github.com/logos-storage/nim-chronos.git
synced 2026-01-05 23:13:08 +00:00
Asyncraises HTTP layer V3 (#482)
* No Critical and Recoverable errors anymore. * Recover raiseHttpCriticalError() * Post-rebase fixes. * Remove deprecated ResponseFence and getResponseFence(). * HttpProcessCallback and 2. * Fix callback holder. * Fix test issue. * Fix backwards compatibility of `HttpResponse.state` field.
This commit is contained in:
parent
e38ceb5378
commit
c41599a6d6
@ -43,30 +43,48 @@ const
|
|||||||
ServerHeader* = "server"
|
ServerHeader* = "server"
|
||||||
LocationHeader* = "location"
|
LocationHeader* = "location"
|
||||||
AuthorizationHeader* = "authorization"
|
AuthorizationHeader* = "authorization"
|
||||||
|
ContentDispositionHeader* = "content-disposition"
|
||||||
|
|
||||||
UrlEncodedContentType* = MediaType.init("application/x-www-form-urlencoded")
|
UrlEncodedContentType* = MediaType.init("application/x-www-form-urlencoded")
|
||||||
MultipartContentType* = MediaType.init("multipart/form-data")
|
MultipartContentType* = MediaType.init("multipart/form-data")
|
||||||
|
|
||||||
type
|
type
|
||||||
|
HttpMessage* = object
|
||||||
|
code*: HttpCode
|
||||||
|
contentType*: MediaType
|
||||||
|
message*: string
|
||||||
|
|
||||||
HttpResult*[T] = Result[T, string]
|
HttpResult*[T] = Result[T, string]
|
||||||
HttpResultCode*[T] = Result[T, HttpCode]
|
HttpResultCode*[T] = Result[T, HttpCode]
|
||||||
|
HttpResultMessage*[T] = Result[T, HttpMessage]
|
||||||
|
|
||||||
HttpDefect* = object of Defect
|
|
||||||
HttpError* = object of AsyncError
|
HttpError* = object of AsyncError
|
||||||
HttpResponseError* = object of HttpError
|
|
||||||
code*: HttpCode
|
|
||||||
HttpCriticalError* = object of HttpResponseError
|
|
||||||
HttpRecoverableError* = object of HttpResponseError
|
|
||||||
HttpDisconnectError* = object of HttpError
|
|
||||||
HttpConnectionError* = object of HttpError
|
|
||||||
HttpInterruptError* = object of HttpError
|
HttpInterruptError* = object of HttpError
|
||||||
HttpReadError* = object of HttpError
|
|
||||||
HttpWriteError* = object of HttpError
|
HttpTransportError* = object of HttpError
|
||||||
HttpProtocolError* = object of HttpError
|
HttpAddressError* = object of HttpTransportError
|
||||||
HttpRedirectError* = object of HttpError
|
HttpRedirectError* = object of HttpTransportError
|
||||||
HttpAddressError* = object of HttpError
|
HttpConnectionError* = object of HttpTransportError
|
||||||
HttpUseClosedError* = object of HttpError
|
HttpReadError* = object of HttpTransportError
|
||||||
HttpReadLimitError* = object of HttpReadError
|
HttpReadLimitError* = object of HttpReadError
|
||||||
|
HttpDisconnectError* = object of HttpReadError
|
||||||
|
HttpWriteError* = object of HttpTransportError
|
||||||
|
|
||||||
|
HttpProtocolError* = object of HttpError
|
||||||
|
code*: HttpCode
|
||||||
|
|
||||||
|
HttpCriticalError* = object of HttpProtocolError # deprecated
|
||||||
|
HttpRecoverableError* = object of HttpProtocolError # deprecated
|
||||||
|
|
||||||
|
HttpRequestError* = object of HttpProtocolError
|
||||||
|
HttpRequestHeadersError* = object of HttpRequestError
|
||||||
|
HttpRequestBodyError* = object of HttpRequestError
|
||||||
|
HttpRequestHeadersTooLargeError* = object of HttpRequestHeadersError
|
||||||
|
HttpRequestBodyTooLargeError* = object of HttpRequestBodyError
|
||||||
|
HttpResponseError* = object of HttpProtocolError
|
||||||
|
|
||||||
|
HttpInvalidUsageError* = object of HttpError
|
||||||
|
HttpUseClosedError* = object of HttpInvalidUsageError
|
||||||
|
|
||||||
KeyValueTuple* = tuple
|
KeyValueTuple* = tuple
|
||||||
key: string
|
key: string
|
||||||
@ -127,6 +145,11 @@ func toString*(error: HttpAddressErrorType): string =
|
|||||||
of HttpAddressErrorType.NoAddressResolved:
|
of HttpAddressErrorType.NoAddressResolved:
|
||||||
"No address has been resolved"
|
"No address has been resolved"
|
||||||
|
|
||||||
|
proc raiseHttpRequestBodyTooLargeError*() {.
|
||||||
|
noinline, noreturn, raises: [HttpRequestBodyTooLargeError].} =
|
||||||
|
raise (ref HttpRequestBodyTooLargeError)(
|
||||||
|
code: Http413, msg: MaximumBodySizeError)
|
||||||
|
|
||||||
proc raiseHttpCriticalError*(msg: string, code = Http400) {.
|
proc raiseHttpCriticalError*(msg: string, code = Http400) {.
|
||||||
noinline, noreturn, raises: [HttpCriticalError].} =
|
noinline, noreturn, raises: [HttpCriticalError].} =
|
||||||
raise (ref HttpCriticalError)(code: code, msg: msg)
|
raise (ref HttpCriticalError)(code: code, msg: msg)
|
||||||
@ -135,9 +158,6 @@ proc raiseHttpDisconnectError*() {.
|
|||||||
noinline, noreturn, raises: [HttpDisconnectError].} =
|
noinline, noreturn, raises: [HttpDisconnectError].} =
|
||||||
raise (ref HttpDisconnectError)(msg: "Remote peer disconnected")
|
raise (ref HttpDisconnectError)(msg: "Remote peer disconnected")
|
||||||
|
|
||||||
proc raiseHttpDefect*(msg: string) {.noinline, noreturn.} =
|
|
||||||
raise (ref HttpDefect)(msg: msg)
|
|
||||||
|
|
||||||
proc raiseHttpConnectionError*(msg: string) {.
|
proc raiseHttpConnectionError*(msg: string) {.
|
||||||
noinline, noreturn, raises: [HttpConnectionError].} =
|
noinline, noreturn, raises: [HttpConnectionError].} =
|
||||||
raise (ref HttpConnectionError)(msg: msg)
|
raise (ref HttpConnectionError)(msg: msg)
|
||||||
@ -152,7 +172,15 @@ proc raiseHttpReadError*(msg: string) {.
|
|||||||
|
|
||||||
proc raiseHttpProtocolError*(msg: string) {.
|
proc raiseHttpProtocolError*(msg: string) {.
|
||||||
noinline, noreturn, raises: [HttpProtocolError].} =
|
noinline, noreturn, raises: [HttpProtocolError].} =
|
||||||
raise (ref HttpProtocolError)(msg: msg)
|
raise (ref HttpProtocolError)(code: Http400, msg: msg)
|
||||||
|
|
||||||
|
proc raiseHttpProtocolError*(code: HttpCode, msg: string) {.
|
||||||
|
noinline, noreturn, raises: [HttpProtocolError].} =
|
||||||
|
raise (ref HttpProtocolError)(code: code, msg: msg)
|
||||||
|
|
||||||
|
proc raiseHttpProtocolError*(msg: HttpMessage) {.
|
||||||
|
noinline, noreturn, raises: [HttpProtocolError].} =
|
||||||
|
raise (ref HttpProtocolError)(code: msg.code, msg: msg.message)
|
||||||
|
|
||||||
proc raiseHttpWriteError*(msg: string) {.
|
proc raiseHttpWriteError*(msg: string) {.
|
||||||
noinline, noreturn, raises: [HttpWriteError].} =
|
noinline, noreturn, raises: [HttpWriteError].} =
|
||||||
@ -178,6 +206,23 @@ template newHttpWriteError*(message: string): ref HttpWriteError =
|
|||||||
template newHttpUseClosedError*(): ref HttpUseClosedError =
|
template newHttpUseClosedError*(): ref HttpUseClosedError =
|
||||||
newException(HttpUseClosedError, "Connection was already closed")
|
newException(HttpUseClosedError, "Connection was already closed")
|
||||||
|
|
||||||
|
func init*(t: typedesc[HttpMessage], code: HttpCode, message: string,
|
||||||
|
contentType: MediaType): HttpMessage =
|
||||||
|
HttpMessage(code: code, message: message, contentType: contentType)
|
||||||
|
|
||||||
|
func init*(t: typedesc[HttpMessage], code: HttpCode, message: string,
|
||||||
|
contentType: string): HttpMessage =
|
||||||
|
HttpMessage(code: code, message: message,
|
||||||
|
contentType: MediaType.init(contentType))
|
||||||
|
|
||||||
|
func init*(t: typedesc[HttpMessage], code: HttpCode,
|
||||||
|
message: string): HttpMessage =
|
||||||
|
HttpMessage(code: code, message: message,
|
||||||
|
contentType: MediaType.init("text/plain"))
|
||||||
|
|
||||||
|
func init*(t: typedesc[HttpMessage], code: HttpCode): HttpMessage =
|
||||||
|
HttpMessage(code: code)
|
||||||
|
|
||||||
iterator queryParams*(query: string,
|
iterator queryParams*(query: string,
|
||||||
flags: set[QueryParamsFlag] = {}): KeyValueTuple =
|
flags: set[QueryParamsFlag] = {}): KeyValueTuple =
|
||||||
## Iterate over url-encoded query string.
|
## Iterate over url-encoded query string.
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -18,7 +18,8 @@ import "."/[httptable, httpcommon, httpbodyrw]
|
|||||||
export asyncloop, httptable, httpcommon, httpbodyrw, asyncstream, httputils
|
export asyncloop, httptable, httpcommon, httpbodyrw, asyncstream, httputils
|
||||||
|
|
||||||
const
|
const
|
||||||
UnableToReadMultipartBody = "Unable to read multipart message body"
|
UnableToReadMultipartBody = "Unable to read multipart message body, reason: "
|
||||||
|
UnableToSendMultipartMessage = "Unable to send multipart message, reason: "
|
||||||
|
|
||||||
type
|
type
|
||||||
MultiPartSource* {.pure.} = enum
|
MultiPartSource* {.pure.} = enum
|
||||||
@ -69,7 +70,7 @@ type
|
|||||||
name*: string
|
name*: string
|
||||||
filename*: string
|
filename*: string
|
||||||
|
|
||||||
MultipartError* = object of HttpCriticalError
|
MultipartError* = object of HttpProtocolError
|
||||||
MultipartEOMError* = object of MultipartError
|
MultipartEOMError* = object of MultipartError
|
||||||
|
|
||||||
BChar* = byte | char
|
BChar* = byte | char
|
||||||
@ -105,7 +106,7 @@ func setPartNames(part: var MultiPart): HttpResult[void] =
|
|||||||
return err("Content-Disposition header value is incorrect")
|
return err("Content-Disposition header value is incorrect")
|
||||||
let dtype = disp.dispositionType(header.toOpenArrayByte(0, len(header) - 1))
|
let dtype = disp.dispositionType(header.toOpenArrayByte(0, len(header) - 1))
|
||||||
if dtype.toLowerAscii() != "form-data":
|
if dtype.toLowerAscii() != "form-data":
|
||||||
return err("Content-Disposition type is incorrect")
|
return err("Content-Disposition header type is incorrect")
|
||||||
for k, v in disp.fields(header.toOpenArrayByte(0, len(header) - 1)):
|
for k, v in disp.fields(header.toOpenArrayByte(0, len(header) - 1)):
|
||||||
case k.toLowerAscii()
|
case k.toLowerAscii()
|
||||||
of "name":
|
of "name":
|
||||||
@ -171,8 +172,17 @@ proc new*[B: BChar](mpt: typedesc[MultiPartReaderRef],
|
|||||||
stream: stream, offset: 0, boundary: fboundary,
|
stream: stream, offset: 0, boundary: fboundary,
|
||||||
buffer: newSeq[byte](partHeadersMaxSize))
|
buffer: newSeq[byte](partHeadersMaxSize))
|
||||||
|
|
||||||
|
template handleAsyncStreamReaderError(targ, excarg: untyped) =
|
||||||
|
if targ.hasOverflow():
|
||||||
|
raiseHttpRequestBodyTooLargeError()
|
||||||
|
raiseHttpReadError(UnableToReadMultipartBody & $excarg.msg)
|
||||||
|
|
||||||
|
template handleAsyncStreamWriterError(targ, excarg: untyped) =
|
||||||
|
targ.state = MultiPartWriterState.MessageFailure
|
||||||
|
raiseHttpWriteError(UnableToSendMultipartMessage & $excarg.msg)
|
||||||
|
|
||||||
proc readPart*(mpr: MultiPartReaderRef): Future[MultiPart] {.
|
proc readPart*(mpr: MultiPartReaderRef): Future[MultiPart] {.
|
||||||
async: (raises: [CancelledError, HttpCriticalError]).} =
|
async: (raises: [CancelledError, HttpReadError, HttpProtocolError]).} =
|
||||||
doAssert(mpr.kind == MultiPartSource.Stream)
|
doAssert(mpr.kind == MultiPartSource.Stream)
|
||||||
if mpr.firstTime:
|
if mpr.firstTime:
|
||||||
try:
|
try:
|
||||||
@ -181,14 +191,11 @@ proc readPart*(mpr: MultiPartReaderRef): Future[MultiPart] {.
|
|||||||
mpr.firstTime = false
|
mpr.firstTime = false
|
||||||
if not(startsWith(mpr.buffer.toOpenArray(0, len(mpr.boundary) - 3),
|
if not(startsWith(mpr.buffer.toOpenArray(0, len(mpr.boundary) - 3),
|
||||||
mpr.boundary.toOpenArray(2, len(mpr.boundary) - 1))):
|
mpr.boundary.toOpenArray(2, len(mpr.boundary) - 1))):
|
||||||
raiseHttpCriticalError("Unexpected boundary encountered")
|
raiseHttpProtocolError(Http400, "Unexpected boundary encountered")
|
||||||
except CancelledError as exc:
|
except CancelledError as exc:
|
||||||
raise exc
|
raise exc
|
||||||
except AsyncStreamError:
|
except AsyncStreamError as exc:
|
||||||
if mpr.stream.hasOverflow():
|
handleAsyncStreamReaderError(mpr.stream, exc)
|
||||||
raiseHttpCriticalError(MaximumBodySizeError, Http413)
|
|
||||||
else:
|
|
||||||
raiseHttpCriticalError(UnableToReadMultipartBody)
|
|
||||||
|
|
||||||
# Reading part's headers
|
# Reading part's headers
|
||||||
try:
|
try:
|
||||||
@ -202,9 +209,9 @@ proc readPart*(mpr: MultiPartReaderRef): Future[MultiPart] {.
|
|||||||
raise newException(MultipartEOMError,
|
raise newException(MultipartEOMError,
|
||||||
"End of multipart message")
|
"End of multipart message")
|
||||||
else:
|
else:
|
||||||
raiseHttpCriticalError("Incorrect multipart header found")
|
raiseHttpProtocolError(Http400, "Incorrect multipart header found")
|
||||||
if mpr.buffer[0] != 0x0D'u8 or mpr.buffer[1] != 0x0A'u8:
|
if mpr.buffer[0] != 0x0D'u8 or mpr.buffer[1] != 0x0A'u8:
|
||||||
raiseHttpCriticalError("Incorrect multipart boundary found")
|
raiseHttpProtocolError(Http400, "Incorrect multipart boundary found")
|
||||||
|
|
||||||
# If two bytes are CRLF we are at the part beginning.
|
# If two bytes are CRLF we are at the part beginning.
|
||||||
# Reading part's headers
|
# Reading part's headers
|
||||||
@ -212,7 +219,7 @@ proc readPart*(mpr: MultiPartReaderRef): Future[MultiPart] {.
|
|||||||
HeadersMark)
|
HeadersMark)
|
||||||
var headersList = parseHeaders(mpr.buffer.toOpenArray(0, res - 1), false)
|
var headersList = parseHeaders(mpr.buffer.toOpenArray(0, res - 1), false)
|
||||||
if headersList.failed():
|
if headersList.failed():
|
||||||
raiseHttpCriticalError("Incorrect multipart's headers found")
|
raiseHttpProtocolError(Http400, "Incorrect multipart's headers found")
|
||||||
inc(mpr.counter)
|
inc(mpr.counter)
|
||||||
|
|
||||||
var part = MultiPart(
|
var part = MultiPart(
|
||||||
@ -228,45 +235,35 @@ proc readPart*(mpr: MultiPartReaderRef): Future[MultiPart] {.
|
|||||||
|
|
||||||
let sres = part.setPartNames()
|
let sres = part.setPartNames()
|
||||||
if sres.isErr():
|
if sres.isErr():
|
||||||
raiseHttpCriticalError($sres.error)
|
raiseHttpProtocolError(Http400, $sres.error)
|
||||||
return part
|
return part
|
||||||
|
|
||||||
except CancelledError as exc:
|
except CancelledError as exc:
|
||||||
raise exc
|
raise exc
|
||||||
except AsyncStreamError:
|
except AsyncStreamError as exc:
|
||||||
if mpr.stream.hasOverflow():
|
handleAsyncStreamReaderError(mpr.stream, exc)
|
||||||
raiseHttpCriticalError(MaximumBodySizeError, Http413)
|
|
||||||
else:
|
|
||||||
raiseHttpCriticalError(UnableToReadMultipartBody)
|
|
||||||
|
|
||||||
proc getBody*(mp: MultiPart): Future[seq[byte]] {.
|
proc getBody*(mp: MultiPart): Future[seq[byte]] {.
|
||||||
async: (raises: [CancelledError, HttpCriticalError]).} =
|
async: (raises: [CancelledError, HttpReadError, HttpProtocolError]).} =
|
||||||
## Get multipart's ``mp`` value as sequence of bytes.
|
## Get multipart's ``mp`` value as sequence of bytes.
|
||||||
case mp.kind
|
case mp.kind
|
||||||
of MultiPartSource.Stream:
|
of MultiPartSource.Stream:
|
||||||
try:
|
try:
|
||||||
let res = await mp.stream.read()
|
await mp.stream.read()
|
||||||
return res
|
except AsyncStreamError as exc:
|
||||||
except AsyncStreamError:
|
handleAsyncStreamReaderError(mp.breader, exc)
|
||||||
if mp.breader.hasOverflow():
|
|
||||||
raiseHttpCriticalError(MaximumBodySizeError, Http413)
|
|
||||||
else:
|
|
||||||
raiseHttpCriticalError(UnableToReadMultipartBody)
|
|
||||||
of MultiPartSource.Buffer:
|
of MultiPartSource.Buffer:
|
||||||
return mp.buffer
|
mp.buffer
|
||||||
|
|
||||||
proc consumeBody*(mp: MultiPart) {.
|
proc consumeBody*(mp: MultiPart) {.
|
||||||
async: (raises: [CancelledError, HttpCriticalError]).} =
|
async: (raises: [CancelledError, HttpReadError, HttpProtocolError]).} =
|
||||||
## Discard multipart's ``mp`` value.
|
## Discard multipart's ``mp`` value.
|
||||||
case mp.kind
|
case mp.kind
|
||||||
of MultiPartSource.Stream:
|
of MultiPartSource.Stream:
|
||||||
try:
|
try:
|
||||||
discard await mp.stream.consume()
|
discard await mp.stream.consume()
|
||||||
except AsyncStreamError:
|
except AsyncStreamError as exc:
|
||||||
if mp.breader.hasOverflow():
|
handleAsyncStreamReaderError(mp.breader, exc)
|
||||||
raiseHttpCriticalError(MaximumBodySizeError, Http413)
|
|
||||||
else:
|
|
||||||
raiseHttpCriticalError(UnableToReadMultipartBody)
|
|
||||||
of MultiPartSource.Buffer:
|
of MultiPartSource.Buffer:
|
||||||
discard
|
discard
|
||||||
|
|
||||||
@ -533,7 +530,7 @@ proc new*[B: BChar](mpt: typedesc[MultiPartWriterRef],
|
|||||||
|
|
||||||
proc prepareHeaders(partMark: openArray[byte], name: string, filename: string,
|
proc prepareHeaders(partMark: openArray[byte], name: string, filename: string,
|
||||||
headers: HttpTable): string =
|
headers: HttpTable): string =
|
||||||
const ContentDisposition = "Content-Disposition"
|
const ContentDispositionHeader = "Content-Disposition"
|
||||||
let qname =
|
let qname =
|
||||||
block:
|
block:
|
||||||
let res = quoteCheck(name)
|
let res = quoteCheck(name)
|
||||||
@ -546,10 +543,10 @@ proc prepareHeaders(partMark: openArray[byte], name: string, filename: string,
|
|||||||
res.get()
|
res.get()
|
||||||
var buffer = newString(len(partMark))
|
var buffer = newString(len(partMark))
|
||||||
copyMem(addr buffer[0], unsafeAddr partMark[0], len(partMark))
|
copyMem(addr buffer[0], unsafeAddr partMark[0], len(partMark))
|
||||||
buffer.add(ContentDisposition)
|
buffer.add(ContentDispositionHeader)
|
||||||
buffer.add(": ")
|
buffer.add(": ")
|
||||||
if ContentDisposition in headers:
|
if ContentDispositionHeader in headers:
|
||||||
buffer.add(headers.getString(ContentDisposition))
|
buffer.add(headers.getString(ContentDispositionHeader))
|
||||||
buffer.add("\r\n")
|
buffer.add("\r\n")
|
||||||
else:
|
else:
|
||||||
buffer.add("form-data; name=\"")
|
buffer.add("form-data; name=\"")
|
||||||
@ -562,7 +559,7 @@ proc prepareHeaders(partMark: openArray[byte], name: string, filename: string,
|
|||||||
buffer.add("\r\n")
|
buffer.add("\r\n")
|
||||||
|
|
||||||
for k, v in headers.stringItems():
|
for k, v in headers.stringItems():
|
||||||
if k != toLowerAscii(ContentDisposition):
|
if k != ContentDispositionHeader:
|
||||||
if len(v) > 0:
|
if len(v) > 0:
|
||||||
buffer.add(k)
|
buffer.add(k)
|
||||||
buffer.add(": ")
|
buffer.add(": ")
|
||||||
@ -572,7 +569,7 @@ proc prepareHeaders(partMark: openArray[byte], name: string, filename: string,
|
|||||||
buffer
|
buffer
|
||||||
|
|
||||||
proc begin*(mpw: MultiPartWriterRef) {.
|
proc begin*(mpw: MultiPartWriterRef) {.
|
||||||
async: (raises: [CancelledError, HttpCriticalError]).} =
|
async: (raises: [CancelledError, HttpWriteError]).} =
|
||||||
## Starts multipart message form and write approprate markers to output
|
## Starts multipart message form and write approprate markers to output
|
||||||
## stream.
|
## stream.
|
||||||
doAssert(mpw.kind == MultiPartSource.Stream)
|
doAssert(mpw.kind == MultiPartSource.Stream)
|
||||||
@ -580,10 +577,9 @@ proc begin*(mpw: MultiPartWriterRef) {.
|
|||||||
# write "--"
|
# write "--"
|
||||||
try:
|
try:
|
||||||
await mpw.stream.write(mpw.beginMark)
|
await mpw.stream.write(mpw.beginMark)
|
||||||
except AsyncStreamError:
|
mpw.state = MultiPartWriterState.MessageStarted
|
||||||
mpw.state = MultiPartWriterState.MessageFailure
|
except AsyncStreamError as exc:
|
||||||
raiseHttpCriticalError("Unable to start multipart message")
|
handleAsyncStreamWriterError(mpw, exc)
|
||||||
mpw.state = MultiPartWriterState.MessageStarted
|
|
||||||
|
|
||||||
proc begin*(mpw: var MultiPartWriter) =
|
proc begin*(mpw: var MultiPartWriter) =
|
||||||
## Starts multipart message form and write approprate markers to output
|
## Starts multipart message form and write approprate markers to output
|
||||||
@ -596,7 +592,7 @@ proc begin*(mpw: var MultiPartWriter) =
|
|||||||
|
|
||||||
proc beginPart*(mpw: MultiPartWriterRef, name: string,
|
proc beginPart*(mpw: MultiPartWriterRef, name: string,
|
||||||
filename: string, headers: HttpTable) {.
|
filename: string, headers: HttpTable) {.
|
||||||
async: (raises: [CancelledError, HttpCriticalError]).} =
|
async: (raises: [CancelledError, HttpWriteError]).} =
|
||||||
## Starts part of multipart message and write appropriate ``headers`` to the
|
## Starts part of multipart message and write appropriate ``headers`` to the
|
||||||
## output stream.
|
## output stream.
|
||||||
##
|
##
|
||||||
@ -611,9 +607,8 @@ proc beginPart*(mpw: MultiPartWriterRef, name: string,
|
|||||||
try:
|
try:
|
||||||
await mpw.stream.write(buffer)
|
await mpw.stream.write(buffer)
|
||||||
mpw.state = MultiPartWriterState.PartStarted
|
mpw.state = MultiPartWriterState.PartStarted
|
||||||
except AsyncStreamError:
|
except AsyncStreamError as exc:
|
||||||
mpw.state = MultiPartWriterState.MessageFailure
|
handleAsyncStreamWriterError(mpw, exc)
|
||||||
raiseHttpCriticalError("Unable to start multipart part")
|
|
||||||
|
|
||||||
proc beginPart*(mpw: var MultiPartWriter, name: string,
|
proc beginPart*(mpw: var MultiPartWriter, name: string,
|
||||||
filename: string, headers: HttpTable) =
|
filename: string, headers: HttpTable) =
|
||||||
@ -632,7 +627,7 @@ proc beginPart*(mpw: var MultiPartWriter, name: string,
|
|||||||
mpw.state = MultiPartWriterState.PartStarted
|
mpw.state = MultiPartWriterState.PartStarted
|
||||||
|
|
||||||
proc write*(mpw: MultiPartWriterRef, pbytes: pointer, nbytes: int) {.
|
proc write*(mpw: MultiPartWriterRef, pbytes: pointer, nbytes: int) {.
|
||||||
async: (raises: [CancelledError, HttpCriticalError]).} =
|
async: (raises: [CancelledError, HttpWriteError]).} =
|
||||||
## Write part's data ``data`` to the output stream.
|
## Write part's data ``data`` to the output stream.
|
||||||
doAssert(mpw.kind == MultiPartSource.Stream)
|
doAssert(mpw.kind == MultiPartSource.Stream)
|
||||||
doAssert(mpw.state == MultiPartWriterState.PartStarted)
|
doAssert(mpw.state == MultiPartWriterState.PartStarted)
|
||||||
@ -640,12 +635,10 @@ proc write*(mpw: MultiPartWriterRef, pbytes: pointer, nbytes: int) {.
|
|||||||
# write <chunk> of data
|
# write <chunk> of data
|
||||||
await mpw.stream.write(pbytes, nbytes)
|
await mpw.stream.write(pbytes, nbytes)
|
||||||
except AsyncStreamError as exc:
|
except AsyncStreamError as exc:
|
||||||
mpw.state = MultiPartWriterState.MessageFailure
|
handleAsyncStreamWriterError(mpw, exc)
|
||||||
raiseHttpCriticalError(
|
|
||||||
"Unable to write multipart data, reason: " & $exc.msg)
|
|
||||||
|
|
||||||
proc write*(mpw: MultiPartWriterRef, data: seq[byte]) {.
|
proc write*(mpw: MultiPartWriterRef, data: seq[byte]) {.
|
||||||
async: (raises: [CancelledError, HttpCriticalError]).} =
|
async: (raises: [CancelledError, HttpWriteError]).} =
|
||||||
## Write part's data ``data`` to the output stream.
|
## Write part's data ``data`` to the output stream.
|
||||||
doAssert(mpw.kind == MultiPartSource.Stream)
|
doAssert(mpw.kind == MultiPartSource.Stream)
|
||||||
doAssert(mpw.state == MultiPartWriterState.PartStarted)
|
doAssert(mpw.state == MultiPartWriterState.PartStarted)
|
||||||
@ -653,12 +646,10 @@ proc write*(mpw: MultiPartWriterRef, data: seq[byte]) {.
|
|||||||
# write <chunk> of data
|
# write <chunk> of data
|
||||||
await mpw.stream.write(data)
|
await mpw.stream.write(data)
|
||||||
except AsyncStreamError as exc:
|
except AsyncStreamError as exc:
|
||||||
mpw.state = MultiPartWriterState.MessageFailure
|
handleAsyncStreamWriterError(mpw, exc)
|
||||||
raiseHttpCriticalError(
|
|
||||||
"Unable to write multipart data, reason: " & $exc.msg)
|
|
||||||
|
|
||||||
proc write*(mpw: MultiPartWriterRef, data: string) {.
|
proc write*(mpw: MultiPartWriterRef, data: string) {.
|
||||||
async: (raises: [CancelledError, HttpCriticalError]).} =
|
async: (raises: [CancelledError, HttpWriteError]).} =
|
||||||
## Write part's data ``data`` to the output stream.
|
## Write part's data ``data`` to the output stream.
|
||||||
doAssert(mpw.kind == MultiPartSource.Stream)
|
doAssert(mpw.kind == MultiPartSource.Stream)
|
||||||
doAssert(mpw.state == MultiPartWriterState.PartStarted)
|
doAssert(mpw.state == MultiPartWriterState.PartStarted)
|
||||||
@ -666,9 +657,7 @@ proc write*(mpw: MultiPartWriterRef, data: string) {.
|
|||||||
# write <chunk> of data
|
# write <chunk> of data
|
||||||
await mpw.stream.write(data)
|
await mpw.stream.write(data)
|
||||||
except AsyncStreamError as exc:
|
except AsyncStreamError as exc:
|
||||||
mpw.state = MultiPartWriterState.MessageFailure
|
handleAsyncStreamWriterError(mpw, exc)
|
||||||
raiseHttpCriticalError(
|
|
||||||
"Unable to write multipart data, reason: " & $exc.msg)
|
|
||||||
|
|
||||||
proc write*(mpw: var MultiPartWriter, pbytes: pointer, nbytes: int) =
|
proc write*(mpw: var MultiPartWriter, pbytes: pointer, nbytes: int) =
|
||||||
## Write part's data ``data`` to the output stream.
|
## Write part's data ``data`` to the output stream.
|
||||||
@ -692,7 +681,7 @@ proc write*(mpw: var MultiPartWriter, data: openArray[char]) =
|
|||||||
mpw.buffer.add(data.toOpenArrayByte(0, len(data) - 1))
|
mpw.buffer.add(data.toOpenArrayByte(0, len(data) - 1))
|
||||||
|
|
||||||
proc finishPart*(mpw: MultiPartWriterRef) {.
|
proc finishPart*(mpw: MultiPartWriterRef) {.
|
||||||
async: (raises: [CancelledError, HttpCriticalError]).} =
|
async: (raises: [CancelledError, HttpWriteError]).} =
|
||||||
## Finish multipart's message part and send proper markers to output stream.
|
## Finish multipart's message part and send proper markers to output stream.
|
||||||
doAssert(mpw.state == MultiPartWriterState.PartStarted)
|
doAssert(mpw.state == MultiPartWriterState.PartStarted)
|
||||||
try:
|
try:
|
||||||
@ -700,9 +689,7 @@ proc finishPart*(mpw: MultiPartWriterRef) {.
|
|||||||
await mpw.stream.write(mpw.finishPartMark)
|
await mpw.stream.write(mpw.finishPartMark)
|
||||||
mpw.state = MultiPartWriterState.PartFinished
|
mpw.state = MultiPartWriterState.PartFinished
|
||||||
except AsyncStreamError as exc:
|
except AsyncStreamError as exc:
|
||||||
mpw.state = MultiPartWriterState.MessageFailure
|
handleAsyncStreamWriterError(mpw, exc)
|
||||||
raiseHttpCriticalError(
|
|
||||||
"Unable to finish multipart message part, reason: " & $exc.msg)
|
|
||||||
|
|
||||||
proc finishPart*(mpw: var MultiPartWriter) =
|
proc finishPart*(mpw: var MultiPartWriter) =
|
||||||
## Finish multipart's message part and send proper markers to output stream.
|
## Finish multipart's message part and send proper markers to output stream.
|
||||||
@ -713,7 +700,7 @@ proc finishPart*(mpw: var MultiPartWriter) =
|
|||||||
mpw.state = MultiPartWriterState.PartFinished
|
mpw.state = MultiPartWriterState.PartFinished
|
||||||
|
|
||||||
proc finish*(mpw: MultiPartWriterRef) {.
|
proc finish*(mpw: MultiPartWriterRef) {.
|
||||||
async: (raises: [CancelledError, HttpCriticalError]).} =
|
async: (raises: [CancelledError, HttpWriteError]).} =
|
||||||
## Finish multipart's message form and send finishing markers to the output
|
## Finish multipart's message form and send finishing markers to the output
|
||||||
## stream.
|
## stream.
|
||||||
doAssert(mpw.kind == MultiPartSource.Stream)
|
doAssert(mpw.kind == MultiPartSource.Stream)
|
||||||
@ -723,9 +710,7 @@ proc finish*(mpw: MultiPartWriterRef) {.
|
|||||||
await mpw.stream.write(mpw.finishMark)
|
await mpw.stream.write(mpw.finishMark)
|
||||||
mpw.state = MultiPartWriterState.MessageFinished
|
mpw.state = MultiPartWriterState.MessageFinished
|
||||||
except AsyncStreamError as exc:
|
except AsyncStreamError as exc:
|
||||||
mpw.state = MultiPartWriterState.MessageFailure
|
handleAsyncStreamWriterError(mpw, exc)
|
||||||
raiseHttpCriticalError(
|
|
||||||
"Unable to finish multipart message, reason: " & $exc.msg)
|
|
||||||
|
|
||||||
proc finish*(mpw: var MultiPartWriter): seq[byte] =
|
proc finish*(mpw: var MultiPartWriter): seq[byte] =
|
||||||
## Finish multipart's message form and send finishing markers to the output
|
## Finish multipart's message form and send finishing markers to the output
|
||||||
|
|||||||
@ -164,22 +164,21 @@ proc new*(htype: typedesc[SecureHttpServerRef],
|
|||||||
maxRequestBodySize: int = 1_048_576,
|
maxRequestBodySize: int = 1_048_576,
|
||||||
dualstack = DualStackType.Auto
|
dualstack = DualStackType.Auto
|
||||||
): HttpResult[SecureHttpServerRef] {.
|
): HttpResult[SecureHttpServerRef] {.
|
||||||
deprecated: "raises missing from process callback".} =
|
deprecated: "Callback could raise only CancelledError, annotate with " &
|
||||||
proc processCallback2(req: RequestFence): Future[HttpResponseRef] {.
|
"{.async: (raises: [CancelledError]).}".} =
|
||||||
async: (raises: [CancelledError, HttpResponseError]).} =
|
|
||||||
try:
|
proc wrap(req: RequestFence): Future[HttpResponseRef] {.
|
||||||
await processCallback(req)
|
async: (raises: [CancelledError]).} =
|
||||||
except CancelledError as exc:
|
try:
|
||||||
raise exc
|
await processCallback(req)
|
||||||
except HttpResponseError as exc:
|
except CancelledError as exc:
|
||||||
raise exc
|
raise exc
|
||||||
except CatchableError as exc:
|
except CatchableError as exc:
|
||||||
# Emulate 3.x behavior
|
defaultResponse(exc)
|
||||||
raise (ref HttpCriticalError)(msg: exc.msg, code: Http503)
|
|
||||||
|
|
||||||
SecureHttpServerRef.new(
|
SecureHttpServerRef.new(
|
||||||
address = address,
|
address = address,
|
||||||
processCallback = processCallback2,
|
processCallback = wrap,
|
||||||
tlsPrivateKey = tlsPrivateKey,
|
tlsPrivateKey = tlsPrivateKey,
|
||||||
tlsCertificate = tlsCertificate,
|
tlsCertificate = tlsCertificate,
|
||||||
serverFlags = serverFlags,
|
serverFlags = serverFlags,
|
||||||
@ -194,4 +193,4 @@ proc new*(htype: typedesc[SecureHttpServerRef],
|
|||||||
maxHeadersSize = maxHeadersSize,
|
maxHeadersSize = maxHeadersSize,
|
||||||
maxRequestBodySize = maxRequestBodySize,
|
maxRequestBodySize = maxRequestBodySize,
|
||||||
dualstack = dualstack
|
dualstack = dualstack
|
||||||
)
|
)
|
||||||
|
|||||||
@ -85,7 +85,8 @@ suite "HTTP client testing suite":
|
|||||||
res
|
res
|
||||||
|
|
||||||
proc createServer(address: TransportAddress,
|
proc createServer(address: TransportAddress,
|
||||||
process: HttpProcessCallback2, secure: bool): HttpServerRef =
|
process: HttpProcessCallback2,
|
||||||
|
secure: bool): HttpServerRef =
|
||||||
let
|
let
|
||||||
socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
|
socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
|
||||||
serverFlags = {HttpServerFlags.Http11Pipeline}
|
serverFlags = {HttpServerFlags.Http11Pipeline}
|
||||||
@ -128,18 +129,24 @@ suite "HTTP client testing suite":
|
|||||||
(MethodPatch, "/test/patch")
|
(MethodPatch, "/test/patch")
|
||||||
]
|
]
|
||||||
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
||||||
async: (raises: [CancelledError, HttpResponseError]).} =
|
async: (raises: [CancelledError]).} =
|
||||||
if r.isOk():
|
if r.isOk():
|
||||||
let request = r.get()
|
let request = r.get()
|
||||||
case request.uri.path
|
case request.uri.path
|
||||||
of "/test/get", "/test/post", "/test/head", "/test/put",
|
of "/test/get", "/test/post", "/test/head", "/test/put",
|
||||||
"/test/delete", "/test/trace", "/test/options", "/test/connect",
|
"/test/delete", "/test/trace", "/test/options", "/test/connect",
|
||||||
"/test/patch", "/test/error":
|
"/test/patch", "/test/error":
|
||||||
return await request.respond(Http200, request.uri.path)
|
try:
|
||||||
|
await request.respond(Http200, request.uri.path)
|
||||||
|
except HttpWriteError as exc:
|
||||||
|
defaultResponse(exc)
|
||||||
else:
|
else:
|
||||||
return await request.respond(Http404, "Page not found")
|
try:
|
||||||
|
await request.respond(Http404, "Page not found")
|
||||||
|
except HttpWriteError as exc:
|
||||||
|
defaultResponse(exc)
|
||||||
else:
|
else:
|
||||||
return defaultResponse()
|
defaultResponse()
|
||||||
|
|
||||||
var server = createServer(initTAddress("127.0.0.1:0"), process, secure)
|
var server = createServer(initTAddress("127.0.0.1:0"), process, secure)
|
||||||
server.start()
|
server.start()
|
||||||
@ -195,7 +202,7 @@ suite "HTTP client testing suite":
|
|||||||
"LONGCHUNKRESPONSE")
|
"LONGCHUNKRESPONSE")
|
||||||
]
|
]
|
||||||
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
||||||
async: (raises: [CancelledError, HttpResponseError]).} =
|
async: (raises: [CancelledError]).} =
|
||||||
if r.isOk():
|
if r.isOk():
|
||||||
let request = r.get()
|
let request = r.get()
|
||||||
case request.uri.path
|
case request.uri.path
|
||||||
@ -203,46 +210,58 @@ suite "HTTP client testing suite":
|
|||||||
var response = request.getResponse()
|
var response = request.getResponse()
|
||||||
var data = createBigMessage(ResponseTests[0][4], ResponseTests[0][2])
|
var data = createBigMessage(ResponseTests[0][4], ResponseTests[0][2])
|
||||||
response.status = Http200
|
response.status = Http200
|
||||||
await response.sendBody(data)
|
try:
|
||||||
return response
|
await response.sendBody(data)
|
||||||
|
except HttpWriteError as exc:
|
||||||
|
return defaultResponse(exc)
|
||||||
|
response
|
||||||
of "/test/long_size_response":
|
of "/test/long_size_response":
|
||||||
var response = request.getResponse()
|
var response = request.getResponse()
|
||||||
var data = createBigMessage(ResponseTests[1][4], ResponseTests[1][2])
|
var data = createBigMessage(ResponseTests[1][4], ResponseTests[1][2])
|
||||||
response.status = Http200
|
response.status = Http200
|
||||||
await response.sendBody(data)
|
try:
|
||||||
return response
|
await response.sendBody(data)
|
||||||
|
except HttpWriteError as exc:
|
||||||
|
return defaultResponse(exc)
|
||||||
|
response
|
||||||
of "/test/short_chunked_response":
|
of "/test/short_chunked_response":
|
||||||
var response = request.getResponse()
|
var response = request.getResponse()
|
||||||
var data = createBigMessage(ResponseTests[2][4], ResponseTests[2][2])
|
var data = createBigMessage(ResponseTests[2][4], ResponseTests[2][2])
|
||||||
response.status = Http200
|
response.status = Http200
|
||||||
await response.prepare()
|
try:
|
||||||
var offset = 0
|
await response.prepare()
|
||||||
while true:
|
var offset = 0
|
||||||
if len(data) == offset:
|
while true:
|
||||||
break
|
if len(data) == offset:
|
||||||
let toWrite = min(1024, len(data) - offset)
|
break
|
||||||
await response.sendChunk(addr data[offset], toWrite)
|
let toWrite = min(1024, len(data) - offset)
|
||||||
offset = offset + toWrite
|
await response.sendChunk(addr data[offset], toWrite)
|
||||||
await response.finish()
|
offset = offset + toWrite
|
||||||
return response
|
await response.finish()
|
||||||
|
except HttpWriteError as exc:
|
||||||
|
return defaultResponse(exc)
|
||||||
|
response
|
||||||
of "/test/long_chunked_response":
|
of "/test/long_chunked_response":
|
||||||
var response = request.getResponse()
|
var response = request.getResponse()
|
||||||
var data = createBigMessage(ResponseTests[3][4], ResponseTests[3][2])
|
var data = createBigMessage(ResponseTests[3][4], ResponseTests[3][2])
|
||||||
response.status = Http200
|
response.status = Http200
|
||||||
await response.prepare()
|
try:
|
||||||
var offset = 0
|
await response.prepare()
|
||||||
while true:
|
var offset = 0
|
||||||
if len(data) == offset:
|
while true:
|
||||||
break
|
if len(data) == offset:
|
||||||
let toWrite = min(1024, len(data) - offset)
|
break
|
||||||
await response.sendChunk(addr data[offset], toWrite)
|
let toWrite = min(1024, len(data) - offset)
|
||||||
offset = offset + toWrite
|
await response.sendChunk(addr data[offset], toWrite)
|
||||||
await response.finish()
|
offset = offset + toWrite
|
||||||
return response
|
await response.finish()
|
||||||
|
except HttpWriteError as exc:
|
||||||
|
return defaultResponse(exc)
|
||||||
|
response
|
||||||
else:
|
else:
|
||||||
return await request.respond(Http404, "Page not found")
|
defaultResponse()
|
||||||
else:
|
else:
|
||||||
return defaultResponse()
|
defaultResponse()
|
||||||
|
|
||||||
var server = createServer(initTAddress("127.0.0.1:0"), process, secure)
|
var server = createServer(initTAddress("127.0.0.1:0"), process, secure)
|
||||||
server.start()
|
server.start()
|
||||||
@ -311,21 +330,26 @@ suite "HTTP client testing suite":
|
|||||||
(MethodPost, "/test/big_request", 262400)
|
(MethodPost, "/test/big_request", 262400)
|
||||||
]
|
]
|
||||||
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
||||||
async: (raises: [CancelledError, HttpResponseError]).} =
|
async: (raises: [CancelledError]).} =
|
||||||
if r.isOk():
|
if r.isOk():
|
||||||
let request = r.get()
|
let request = r.get()
|
||||||
case request.uri.path
|
case request.uri.path
|
||||||
of "/test/big_request":
|
of "/test/big_request":
|
||||||
if request.hasBody():
|
try:
|
||||||
let body = await request.getBody()
|
if request.hasBody():
|
||||||
let digest = $secureHash(string.fromBytes(body))
|
let body = await request.getBody()
|
||||||
return await request.respond(Http200, digest)
|
let digest = $secureHash(string.fromBytes(body))
|
||||||
else:
|
await request.respond(Http200, digest)
|
||||||
return await request.respond(Http400, "Missing content body")
|
else:
|
||||||
|
await request.respond(Http400, "Missing content body")
|
||||||
|
except HttpProtocolError as exc:
|
||||||
|
defaultResponse(exc)
|
||||||
|
except HttpTransportError as exc:
|
||||||
|
defaultResponse(exc)
|
||||||
else:
|
else:
|
||||||
return await request.respond(Http404, "Page not found")
|
defaultResponse()
|
||||||
else:
|
else:
|
||||||
return defaultResponse()
|
defaultResponse()
|
||||||
|
|
||||||
var server = createServer(initTAddress("127.0.0.1:0"), process, secure)
|
var server = createServer(initTAddress("127.0.0.1:0"), process, secure)
|
||||||
server.start()
|
server.start()
|
||||||
@ -381,21 +405,27 @@ suite "HTTP client testing suite":
|
|||||||
(MethodPost, "/test/big_chunk_request", 262400)
|
(MethodPost, "/test/big_chunk_request", 262400)
|
||||||
]
|
]
|
||||||
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
||||||
async: (raises: [CancelledError, HttpResponseError]).} =
|
async: (raises: [CancelledError]).} =
|
||||||
if r.isOk():
|
if r.isOk():
|
||||||
let request = r.get()
|
let request = r.get()
|
||||||
case request.uri.path
|
case request.uri.path
|
||||||
of "/test/big_chunk_request":
|
of "/test/big_chunk_request":
|
||||||
if request.hasBody():
|
try:
|
||||||
let body = await request.getBody()
|
if request.hasBody():
|
||||||
let digest = $secureHash(string.fromBytes(body))
|
let
|
||||||
return await request.respond(Http200, digest)
|
body = await request.getBody()
|
||||||
else:
|
digest = $secureHash(string.fromBytes(body))
|
||||||
return await request.respond(Http400, "Missing content body")
|
await request.respond(Http200, digest)
|
||||||
|
else:
|
||||||
|
await request.respond(Http400, "Missing content body")
|
||||||
|
except HttpProtocolError as exc:
|
||||||
|
defaultResponse(exc)
|
||||||
|
except HttpTransportError as exc:
|
||||||
|
defaultResponse(exc)
|
||||||
else:
|
else:
|
||||||
return await request.respond(Http404, "Page not found")
|
defaultResponse()
|
||||||
else:
|
else:
|
||||||
return defaultResponse()
|
defaultResponse()
|
||||||
|
|
||||||
var server = createServer(initTAddress("127.0.0.1:0"), process, secure)
|
var server = createServer(initTAddress("127.0.0.1:0"), process, secure)
|
||||||
server.start()
|
server.start()
|
||||||
@ -455,23 +485,28 @@ suite "HTTP client testing suite":
|
|||||||
]
|
]
|
||||||
|
|
||||||
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
||||||
async: (raises: [CancelledError, HttpResponseError]).} =
|
async: (raises: [CancelledError]).} =
|
||||||
if r.isOk():
|
if r.isOk():
|
||||||
let request = r.get()
|
let request = r.get()
|
||||||
case request.uri.path
|
case request.uri.path
|
||||||
of "/test/post/urlencoded_size", "/test/post/urlencoded_chunked":
|
of "/test/post/urlencoded_size", "/test/post/urlencoded_chunked":
|
||||||
if request.hasBody():
|
try:
|
||||||
var postTable = await request.post()
|
if request.hasBody():
|
||||||
let body = postTable.getString("field1") & ":" &
|
var postTable = await request.post()
|
||||||
postTable.getString("field2") & ":" &
|
let body = postTable.getString("field1") & ":" &
|
||||||
postTable.getString("field3")
|
postTable.getString("field2") & ":" &
|
||||||
return await request.respond(Http200, body)
|
postTable.getString("field3")
|
||||||
else:
|
await request.respond(Http200, body)
|
||||||
return await request.respond(Http400, "Missing content body")
|
else:
|
||||||
|
await request.respond(Http400, "Missing content body")
|
||||||
|
except HttpTransportError as exc:
|
||||||
|
defaultResponse(exc)
|
||||||
|
except HttpProtocolError as exc:
|
||||||
|
defaultResponse(exc)
|
||||||
else:
|
else:
|
||||||
return await request.respond(Http404, "Page not found")
|
defaultResponse()
|
||||||
else:
|
else:
|
||||||
return defaultResponse()
|
defaultResponse()
|
||||||
|
|
||||||
var server = createServer(initTAddress("127.0.0.1:0"), process, secure)
|
var server = createServer(initTAddress("127.0.0.1:0"), process, secure)
|
||||||
server.start()
|
server.start()
|
||||||
@ -554,23 +589,28 @@ suite "HTTP client testing suite":
|
|||||||
]
|
]
|
||||||
|
|
||||||
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
||||||
async: (raises: [CancelledError, HttpResponseError]).} =
|
async: (raises: [CancelledError]).} =
|
||||||
if r.isOk():
|
if r.isOk():
|
||||||
let request = r.get()
|
let request = r.get()
|
||||||
case request.uri.path
|
case request.uri.path
|
||||||
of "/test/post/multipart_size", "/test/post/multipart_chunked":
|
of "/test/post/multipart_size", "/test/post/multipart_chunked":
|
||||||
if request.hasBody():
|
try:
|
||||||
var postTable = await request.post()
|
if request.hasBody():
|
||||||
let body = postTable.getString("field1") & ":" &
|
var postTable = await request.post()
|
||||||
postTable.getString("field2") & ":" &
|
let body = postTable.getString("field1") & ":" &
|
||||||
postTable.getString("field3")
|
postTable.getString("field2") & ":" &
|
||||||
return await request.respond(Http200, body)
|
postTable.getString("field3")
|
||||||
else:
|
await request.respond(Http200, body)
|
||||||
return await request.respond(Http400, "Missing content body")
|
else:
|
||||||
|
await request.respond(Http400, "Missing content body")
|
||||||
|
except HttpProtocolError as exc:
|
||||||
|
defaultResponse(exc)
|
||||||
|
except HttpTransportError as exc:
|
||||||
|
defaultResponse(exc)
|
||||||
else:
|
else:
|
||||||
return await request.respond(Http404, "Page not found")
|
defaultResponse()
|
||||||
else:
|
else:
|
||||||
return defaultResponse()
|
defaultResponse()
|
||||||
|
|
||||||
var server = createServer(initTAddress("127.0.0.1:0"), process, secure)
|
var server = createServer(initTAddress("127.0.0.1:0"), process, secure)
|
||||||
server.start()
|
server.start()
|
||||||
@ -649,26 +689,29 @@ suite "HTTP client testing suite":
|
|||||||
var lastAddress: Uri
|
var lastAddress: Uri
|
||||||
|
|
||||||
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
||||||
async: (raises: [CancelledError, HttpResponseError]).} =
|
async: (raises: [CancelledError]).} =
|
||||||
if r.isOk():
|
if r.isOk():
|
||||||
let request = r.get()
|
let request = r.get()
|
||||||
case request.uri.path
|
try:
|
||||||
of "/":
|
case request.uri.path
|
||||||
return await request.redirect(Http302, "/redirect/1")
|
of "/":
|
||||||
of "/redirect/1":
|
await request.redirect(Http302, "/redirect/1")
|
||||||
return await request.redirect(Http302, "/next/redirect/2")
|
of "/redirect/1":
|
||||||
of "/next/redirect/2":
|
await request.redirect(Http302, "/next/redirect/2")
|
||||||
return await request.redirect(Http302, "redirect/3")
|
of "/next/redirect/2":
|
||||||
of "/next/redirect/redirect/3":
|
await request.redirect(Http302, "redirect/3")
|
||||||
return await request.redirect(Http302, "next/redirect/4")
|
of "/next/redirect/redirect/3":
|
||||||
of "/next/redirect/redirect/next/redirect/4":
|
await request.redirect(Http302, "next/redirect/4")
|
||||||
return await request.redirect(Http302, lastAddress)
|
of "/next/redirect/redirect/next/redirect/4":
|
||||||
of "/final/5":
|
await request.redirect(Http302, lastAddress)
|
||||||
return await request.respond(Http200, "ok-5")
|
of "/final/5":
|
||||||
else:
|
await request.respond(Http200, "ok-5")
|
||||||
return await request.respond(Http404, "Page not found")
|
else:
|
||||||
|
await request.respond(Http404, "Page not found")
|
||||||
|
except HttpWriteError as exc:
|
||||||
|
defaultResponse(exc)
|
||||||
else:
|
else:
|
||||||
return defaultResponse()
|
defaultResponse()
|
||||||
|
|
||||||
var server = createServer(initTAddress("127.0.0.1:0"), process, secure)
|
var server = createServer(initTAddress("127.0.0.1:0"), process, secure)
|
||||||
server.start()
|
server.start()
|
||||||
@ -706,8 +749,8 @@ suite "HTTP client testing suite":
|
|||||||
|
|
||||||
proc testSendCancelLeaksTest(secure: bool): Future[bool] {.async.} =
|
proc testSendCancelLeaksTest(secure: bool): Future[bool] {.async.} =
|
||||||
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
||||||
async: (raises: [CancelledError, HttpResponseError]).} =
|
async: (raises: [CancelledError]).} =
|
||||||
return defaultResponse()
|
defaultResponse()
|
||||||
|
|
||||||
var server = createServer(initTAddress("127.0.0.1:0"), process, secure)
|
var server = createServer(initTAddress("127.0.0.1:0"), process, secure)
|
||||||
server.start()
|
server.start()
|
||||||
@ -756,8 +799,8 @@ suite "HTTP client testing suite":
|
|||||||
|
|
||||||
proc testOpenCancelLeaksTest(secure: bool): Future[bool] {.async.} =
|
proc testOpenCancelLeaksTest(secure: bool): Future[bool] {.async.} =
|
||||||
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
||||||
async: (raises: [CancelledError, HttpResponseError]).} =
|
async: (raises: [CancelledError]).} =
|
||||||
return defaultResponse()
|
defaultResponse()
|
||||||
|
|
||||||
var server = createServer(initTAddress("127.0.0.1:0"), process, secure)
|
var server = createServer(initTAddress("127.0.0.1:0"), process, secure)
|
||||||
server.start()
|
server.start()
|
||||||
@ -868,20 +911,23 @@ suite "HTTP client testing suite":
|
|||||||
(data2.status, data2.data.bytesToString(), count)]
|
(data2.status, data2.data.bytesToString(), count)]
|
||||||
|
|
||||||
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
||||||
async: (raises: [CancelledError, HttpResponseError]).} =
|
async: (raises: [CancelledError]).} =
|
||||||
if r.isOk():
|
if r.isOk():
|
||||||
let request = r.get()
|
let request = r.get()
|
||||||
case request.uri.path
|
try:
|
||||||
of "/keep":
|
case request.uri.path
|
||||||
let headers = HttpTable.init([("connection", "keep-alive")])
|
of "/keep":
|
||||||
return await request.respond(Http200, "ok", headers = headers)
|
let headers = HttpTable.init([("connection", "keep-alive")])
|
||||||
of "/drop":
|
await request.respond(Http200, "ok", headers = headers)
|
||||||
let headers = HttpTable.init([("connection", "close")])
|
of "/drop":
|
||||||
return await request.respond(Http200, "ok", headers = headers)
|
let headers = HttpTable.init([("connection", "close")])
|
||||||
else:
|
await request.respond(Http200, "ok", headers = headers)
|
||||||
return await request.respond(Http404, "Page not found")
|
else:
|
||||||
|
await request.respond(Http404, "Page not found")
|
||||||
|
except HttpWriteError as exc:
|
||||||
|
defaultResponse(exc)
|
||||||
else:
|
else:
|
||||||
return defaultResponse()
|
defaultResponse()
|
||||||
|
|
||||||
var server = createServer(initTAddress("127.0.0.1:0"), process, false)
|
var server = createServer(initTAddress("127.0.0.1:0"), process, false)
|
||||||
server.start()
|
server.start()
|
||||||
@ -1004,16 +1050,19 @@ suite "HTTP client testing suite":
|
|||||||
return (data.status, data.data.bytesToString(), 0)
|
return (data.status, data.data.bytesToString(), 0)
|
||||||
|
|
||||||
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
||||||
async: (raises: [CancelledError, HttpResponseError]).} =
|
async: (raises: [CancelledError]).} =
|
||||||
if r.isOk():
|
if r.isOk():
|
||||||
let request = r.get()
|
let request = r.get()
|
||||||
case request.uri.path
|
try:
|
||||||
of "/test":
|
case request.uri.path
|
||||||
return await request.respond(Http200, "ok")
|
of "/test":
|
||||||
else:
|
await request.respond(Http200, "ok")
|
||||||
return await request.respond(Http404, "Page not found")
|
else:
|
||||||
|
await request.respond(Http404, "Page not found")
|
||||||
|
except HttpWriteError as exc:
|
||||||
|
defaultResponse(exc)
|
||||||
else:
|
else:
|
||||||
return defaultResponse()
|
defaultResponse()
|
||||||
|
|
||||||
var server = createServer(initTAddress("127.0.0.1:0"), process, false)
|
var server = createServer(initTAddress("127.0.0.1:0"), process, false)
|
||||||
server.start()
|
server.start()
|
||||||
@ -1064,19 +1113,22 @@ suite "HTTP client testing suite":
|
|||||||
return (data.status, data.data.bytesToString(), 0)
|
return (data.status, data.data.bytesToString(), 0)
|
||||||
|
|
||||||
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
||||||
async: (raises: [CancelledError, HttpResponseError]).} =
|
async: (raises: [CancelledError]).} =
|
||||||
if r.isOk():
|
if r.isOk():
|
||||||
let request = r.get()
|
let request = r.get()
|
||||||
case request.uri.path
|
try:
|
||||||
of "/test":
|
case request.uri.path
|
||||||
return await request.respond(Http200, "ok")
|
of "/test":
|
||||||
of "/keep-test":
|
await request.respond(Http200, "ok")
|
||||||
let headers = HttpTable.init([("Connection", "keep-alive")])
|
of "/keep-test":
|
||||||
return await request.respond(Http200, "not-alive", headers)
|
let headers = HttpTable.init([("Connection", "keep-alive")])
|
||||||
else:
|
await request.respond(Http200, "not-alive", headers)
|
||||||
return await request.respond(Http404, "Page not found")
|
else:
|
||||||
|
await request.respond(Http404, "Page not found")
|
||||||
|
except HttpWriteError as exc:
|
||||||
|
defaultResponse(exc)
|
||||||
else:
|
else:
|
||||||
return defaultResponse()
|
defaultResponse()
|
||||||
|
|
||||||
var server = createServer(initTAddress("127.0.0.1:0"), process, false)
|
var server = createServer(initTAddress("127.0.0.1:0"), process, false)
|
||||||
server.start()
|
server.start()
|
||||||
@ -1180,58 +1232,61 @@ suite "HTTP client testing suite":
|
|||||||
true
|
true
|
||||||
|
|
||||||
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
||||||
async: (raises: [CancelledError, HttpResponseError]).} =
|
async: (raises: [CancelledError]).} =
|
||||||
if r.isOk():
|
if r.isOk():
|
||||||
let request = r.get()
|
let request = r.get()
|
||||||
if request.uri.path.startsWith("/test/single/"):
|
try:
|
||||||
let index =
|
if request.uri.path.startsWith("/test/single/"):
|
||||||
block:
|
let index =
|
||||||
var res = -1
|
block:
|
||||||
for index, value in SingleGoodTests.pairs():
|
var res = -1
|
||||||
if value[0] == request.uri.path:
|
for index, value in SingleGoodTests.pairs():
|
||||||
res = index
|
if value[0] == request.uri.path:
|
||||||
break
|
res = index
|
||||||
res
|
break
|
||||||
if index < 0:
|
res
|
||||||
return await request.respond(Http404, "Page not found")
|
if index < 0:
|
||||||
var response = request.getResponse()
|
return await request.respond(Http404, "Page not found")
|
||||||
response.status = Http200
|
var response = request.getResponse()
|
||||||
await response.sendBody(SingleGoodTests[index][1])
|
response.status = Http200
|
||||||
return response
|
await response.sendBody(SingleGoodTests[index][1])
|
||||||
elif request.uri.path.startsWith("/test/multiple/"):
|
response
|
||||||
let index =
|
elif request.uri.path.startsWith("/test/multiple/"):
|
||||||
block:
|
let index =
|
||||||
var res = -1
|
block:
|
||||||
for index, value in MultipleGoodTests.pairs():
|
var res = -1
|
||||||
if value[0] == request.uri.path:
|
for index, value in MultipleGoodTests.pairs():
|
||||||
res = index
|
if value[0] == request.uri.path:
|
||||||
break
|
res = index
|
||||||
res
|
break
|
||||||
if index < 0:
|
res
|
||||||
return await request.respond(Http404, "Page not found")
|
if index < 0:
|
||||||
var response = request.getResponse()
|
return await request.respond(Http404, "Page not found")
|
||||||
response.status = Http200
|
var response = request.getResponse()
|
||||||
await response.sendBody(MultipleGoodTests[index][1])
|
response.status = Http200
|
||||||
return response
|
await response.sendBody(MultipleGoodTests[index][1])
|
||||||
elif request.uri.path.startsWith("/test/overflow/"):
|
response
|
||||||
let index =
|
elif request.uri.path.startsWith("/test/overflow/"):
|
||||||
block:
|
let index =
|
||||||
var res = -1
|
block:
|
||||||
for index, value in OverflowTests.pairs():
|
var res = -1
|
||||||
if value[0] == request.uri.path:
|
for index, value in OverflowTests.pairs():
|
||||||
res = index
|
if value[0] == request.uri.path:
|
||||||
break
|
res = index
|
||||||
res
|
break
|
||||||
if index < 0:
|
res
|
||||||
return await request.respond(Http404, "Page not found")
|
if index < 0:
|
||||||
var response = request.getResponse()
|
return await request.respond(Http404, "Page not found")
|
||||||
response.status = Http200
|
var response = request.getResponse()
|
||||||
await response.sendBody(OverflowTests[index][1])
|
response.status = Http200
|
||||||
return response
|
await response.sendBody(OverflowTests[index][1])
|
||||||
else:
|
response
|
||||||
return await request.respond(Http404, "Page not found")
|
else:
|
||||||
|
defaultResponse()
|
||||||
|
except HttpWriteError as exc:
|
||||||
|
defaultResponse(exc)
|
||||||
else:
|
else:
|
||||||
return defaultResponse()
|
defaultResponse()
|
||||||
|
|
||||||
var server = createServer(initTAddress("127.0.0.1:0"), process, secure)
|
var server = createServer(initTAddress("127.0.0.1:0"), process, secure)
|
||||||
server.start()
|
server.start()
|
||||||
|
|||||||
@ -64,7 +64,7 @@ suite "HTTP server testing suite":
|
|||||||
proc testTooBigBodyChunked(operation: TooBigTest): Future[bool] {.async.} =
|
proc testTooBigBodyChunked(operation: TooBigTest): Future[bool] {.async.} =
|
||||||
var serverRes = false
|
var serverRes = false
|
||||||
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
||||||
async: (raises: [CancelledError, HttpResponseError]).} =
|
async: (raises: [CancelledError]).} =
|
||||||
if r.isOk():
|
if r.isOk():
|
||||||
let request = r.get()
|
let request = r.get()
|
||||||
try:
|
try:
|
||||||
@ -77,13 +77,15 @@ suite "HTTP server testing suite":
|
|||||||
let ptable {.used.} = await request.post()
|
let ptable {.used.} = await request.post()
|
||||||
of PostMultipartTest:
|
of PostMultipartTest:
|
||||||
let ptable {.used.} = await request.post()
|
let ptable {.used.} = await request.post()
|
||||||
except HttpCriticalError as exc:
|
defaultResponse()
|
||||||
|
except HttpTransportError as exc:
|
||||||
|
defaultResponse(exc)
|
||||||
|
except HttpProtocolError as exc:
|
||||||
if exc.code == Http413:
|
if exc.code == Http413:
|
||||||
serverRes = true
|
serverRes = true
|
||||||
# Reraising exception, because processor should properly handle it.
|
defaultResponse(exc)
|
||||||
raise exc
|
|
||||||
else:
|
else:
|
||||||
return defaultResponse()
|
defaultResponse()
|
||||||
|
|
||||||
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
|
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
|
||||||
let res = HttpServerRef.new(initTAddress("127.0.0.1:0"), process,
|
let res = HttpServerRef.new(initTAddress("127.0.0.1:0"), process,
|
||||||
@ -128,14 +130,17 @@ suite "HTTP server testing suite":
|
|||||||
proc testTimeout(): Future[bool] {.async.} =
|
proc testTimeout(): Future[bool] {.async.} =
|
||||||
var serverRes = false
|
var serverRes = false
|
||||||
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
||||||
async: (raises: [CancelledError, HttpResponseError]).} =
|
async: (raises: [CancelledError]).} =
|
||||||
if r.isOk():
|
if r.isOk():
|
||||||
let request = r.get()
|
let request = r.get()
|
||||||
return await request.respond(Http200, "TEST_OK", HttpTable.init())
|
try:
|
||||||
|
await request.respond(Http200, "TEST_OK", HttpTable.init())
|
||||||
|
except HttpWriteError as exc:
|
||||||
|
defaultResponse(exc)
|
||||||
else:
|
else:
|
||||||
if r.error.kind == HttpServerError.TimeoutError:
|
if r.error.kind == HttpServerError.TimeoutError:
|
||||||
serverRes = true
|
serverRes = true
|
||||||
return defaultResponse()
|
defaultResponse()
|
||||||
|
|
||||||
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
|
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
|
||||||
let res = HttpServerRef.new(initTAddress("127.0.0.1:0"),
|
let res = HttpServerRef.new(initTAddress("127.0.0.1:0"),
|
||||||
@ -158,14 +163,17 @@ suite "HTTP server testing suite":
|
|||||||
proc testEmpty(): Future[bool] {.async.} =
|
proc testEmpty(): Future[bool] {.async.} =
|
||||||
var serverRes = false
|
var serverRes = false
|
||||||
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
||||||
async: (raises: [CancelledError, HttpResponseError]).} =
|
async: (raises: [CancelledError]).} =
|
||||||
if r.isOk():
|
if r.isOk():
|
||||||
let request = r.get()
|
let request = r.get()
|
||||||
return await request.respond(Http200, "TEST_OK", HttpTable.init())
|
try:
|
||||||
|
await request.respond(Http200, "TEST_OK", HttpTable.init())
|
||||||
|
except HttpWriteError as exc:
|
||||||
|
defaultResponse(exc)
|
||||||
else:
|
else:
|
||||||
if r.error.kind == HttpServerError.CriticalError:
|
if r.error.kind == HttpServerError.ProtocolError:
|
||||||
serverRes = true
|
serverRes = true
|
||||||
return defaultResponse()
|
defaultResponse()
|
||||||
|
|
||||||
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
|
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
|
||||||
let res = HttpServerRef.new(initTAddress("127.0.0.1:0"),
|
let res = HttpServerRef.new(initTAddress("127.0.0.1:0"),
|
||||||
@ -188,14 +196,17 @@ suite "HTTP server testing suite":
|
|||||||
proc testTooBig(): Future[bool] {.async.} =
|
proc testTooBig(): Future[bool] {.async.} =
|
||||||
var serverRes = false
|
var serverRes = false
|
||||||
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
||||||
async: (raises: [CancelledError, HttpResponseError]).} =
|
async: (raises: [CancelledError]).} =
|
||||||
if r.isOk():
|
if r.isOk():
|
||||||
let request = r.get()
|
let request = r.get()
|
||||||
return await request.respond(Http200, "TEST_OK", HttpTable.init())
|
try:
|
||||||
|
await request.respond(Http200, "TEST_OK", HttpTable.init())
|
||||||
|
except HttpWriteError as exc:
|
||||||
|
defaultResponse(exc)
|
||||||
else:
|
else:
|
||||||
if r.error.error == HttpServerError.CriticalError:
|
if r.error.error == HttpServerError.ProtocolError:
|
||||||
serverRes = true
|
serverRes = true
|
||||||
return defaultResponse()
|
defaultResponse()
|
||||||
|
|
||||||
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
|
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
|
||||||
let res = HttpServerRef.new(initTAddress("127.0.0.1:0"), process,
|
let res = HttpServerRef.new(initTAddress("127.0.0.1:0"), process,
|
||||||
@ -219,13 +230,11 @@ suite "HTTP server testing suite":
|
|||||||
proc testTooBigBody(): Future[bool] {.async.} =
|
proc testTooBigBody(): Future[bool] {.async.} =
|
||||||
var serverRes = false
|
var serverRes = false
|
||||||
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
||||||
async: (raises: [CancelledError, HttpResponseError]).} =
|
async: (raises: [CancelledError]).} =
|
||||||
if r.isOk():
|
if r.isErr():
|
||||||
discard
|
if r.error.error == HttpServerError.ProtocolError:
|
||||||
else:
|
|
||||||
if r.error.error == HttpServerError.CriticalError:
|
|
||||||
serverRes = true
|
serverRes = true
|
||||||
return defaultResponse()
|
defaultResponse()
|
||||||
|
|
||||||
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
|
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
|
||||||
let res = HttpServerRef.new(initTAddress("127.0.0.1:0"), process,
|
let res = HttpServerRef.new(initTAddress("127.0.0.1:0"), process,
|
||||||
@ -266,7 +275,7 @@ suite "HTTP server testing suite":
|
|||||||
proc testQuery(): Future[bool] {.async.} =
|
proc testQuery(): Future[bool] {.async.} =
|
||||||
var serverRes = false
|
var serverRes = false
|
||||||
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
||||||
async: (raises: [CancelledError, HttpResponseError]).} =
|
async: (raises: [CancelledError]).} =
|
||||||
if r.isOk():
|
if r.isOk():
|
||||||
let request = r.get()
|
let request = r.get()
|
||||||
var kres = newSeq[string]()
|
var kres = newSeq[string]()
|
||||||
@ -274,11 +283,14 @@ suite "HTTP server testing suite":
|
|||||||
kres.add(k & ":" & v)
|
kres.add(k & ":" & v)
|
||||||
sort(kres)
|
sort(kres)
|
||||||
serverRes = true
|
serverRes = true
|
||||||
return await request.respond(Http200, "TEST_OK:" & kres.join(":"),
|
try:
|
||||||
HttpTable.init())
|
await request.respond(Http200, "TEST_OK:" & kres.join(":"),
|
||||||
|
HttpTable.init())
|
||||||
|
except HttpWriteError as exc:
|
||||||
|
serverRes = false
|
||||||
|
defaultResponse(exc)
|
||||||
else:
|
else:
|
||||||
serverRes = false
|
defaultResponse()
|
||||||
return defaultResponse()
|
|
||||||
|
|
||||||
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
|
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
|
||||||
let res = HttpServerRef.new(initTAddress("127.0.0.1:0"), process,
|
let res = HttpServerRef.new(initTAddress("127.0.0.1:0"), process,
|
||||||
@ -296,10 +308,9 @@ suite "HTTP server testing suite":
|
|||||||
"GET /?a=%D0%9F&%D0%A4=%D0%91&b=%D0%A6&c=%D0%AE HTTP/1.0\r\n\r\n")
|
"GET /?a=%D0%9F&%D0%A4=%D0%91&b=%D0%A6&c=%D0%AE HTTP/1.0\r\n\r\n")
|
||||||
await server.stop()
|
await server.stop()
|
||||||
await server.closeWait()
|
await server.closeWait()
|
||||||
let r = serverRes and
|
serverRes and
|
||||||
(data1.find("TEST_OK:a:1:a:2:b:3:c:4") >= 0) and
|
(data1.find("TEST_OK:a:1:a:2:b:3:c:4") >= 0) and
|
||||||
(data2.find("TEST_OK:a:П:b:Ц:c:Ю:Ф:Б") >= 0)
|
(data2.find("TEST_OK:a:П:b:Ц:c:Ю:Ф:Б") >= 0)
|
||||||
return r
|
|
||||||
|
|
||||||
check waitFor(testQuery()) == true
|
check waitFor(testQuery()) == true
|
||||||
|
|
||||||
@ -307,7 +318,7 @@ suite "HTTP server testing suite":
|
|||||||
proc testHeaders(): Future[bool] {.async.} =
|
proc testHeaders(): Future[bool] {.async.} =
|
||||||
var serverRes = false
|
var serverRes = false
|
||||||
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
||||||
async: (raises: [CancelledError, HttpResponseError]).} =
|
async: (raises: [CancelledError]).} =
|
||||||
if r.isOk():
|
if r.isOk():
|
||||||
let request = r.get()
|
let request = r.get()
|
||||||
var kres = newSeq[string]()
|
var kres = newSeq[string]()
|
||||||
@ -315,11 +326,14 @@ suite "HTTP server testing suite":
|
|||||||
kres.add(k & ":" & v)
|
kres.add(k & ":" & v)
|
||||||
sort(kres)
|
sort(kres)
|
||||||
serverRes = true
|
serverRes = true
|
||||||
return await request.respond(Http200, "TEST_OK:" & kres.join(":"),
|
try:
|
||||||
HttpTable.init())
|
await request.respond(Http200, "TEST_OK:" & kres.join(":"),
|
||||||
|
HttpTable.init())
|
||||||
|
except HttpWriteError as exc:
|
||||||
|
serverRes = false
|
||||||
|
defaultResponse(exc)
|
||||||
else:
|
else:
|
||||||
serverRes = false
|
defaultResponse()
|
||||||
return defaultResponse()
|
|
||||||
|
|
||||||
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
|
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
|
||||||
let res = HttpServerRef.new(initTAddress("127.0.0.1:0"), process,
|
let res = HttpServerRef.new(initTAddress("127.0.0.1:0"), process,
|
||||||
@ -351,21 +365,30 @@ suite "HTTP server testing suite":
|
|||||||
proc testPostUrl(): Future[bool] {.async.} =
|
proc testPostUrl(): Future[bool] {.async.} =
|
||||||
var serverRes = false
|
var serverRes = false
|
||||||
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
||||||
async: (raises: [CancelledError, HttpResponseError]).} =
|
async: (raises: [CancelledError]).} =
|
||||||
if r.isOk():
|
if r.isOk():
|
||||||
var kres = newSeq[string]()
|
var kres = newSeq[string]()
|
||||||
let request = r.get()
|
let request = r.get()
|
||||||
if request.meth in PostMethods:
|
if request.meth in PostMethods:
|
||||||
let post = await request.post()
|
let post =
|
||||||
|
try:
|
||||||
|
await request.post()
|
||||||
|
except HttpProtocolError as exc:
|
||||||
|
return defaultResponse(exc)
|
||||||
|
except HttpTransportError as exc:
|
||||||
|
return defaultResponse(exc)
|
||||||
for k, v in post.stringItems():
|
for k, v in post.stringItems():
|
||||||
kres.add(k & ":" & v)
|
kres.add(k & ":" & v)
|
||||||
sort(kres)
|
sort(kres)
|
||||||
serverRes = true
|
serverRes = true
|
||||||
return await request.respond(Http200, "TEST_OK:" & kres.join(":"),
|
try:
|
||||||
HttpTable.init())
|
await request.respond(Http200, "TEST_OK:" & kres.join(":"),
|
||||||
|
HttpTable.init())
|
||||||
|
except HttpWriteError as exc:
|
||||||
|
serverRes = false
|
||||||
|
defaultResponse(exc)
|
||||||
else:
|
else:
|
||||||
serverRes = false
|
defaultResponse()
|
||||||
return defaultResponse()
|
|
||||||
|
|
||||||
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
|
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
|
||||||
let res = HttpServerRef.new(initTAddress("127.0.0.1:0"), process,
|
let res = HttpServerRef.new(initTAddress("127.0.0.1:0"), process,
|
||||||
@ -395,21 +418,30 @@ suite "HTTP server testing suite":
|
|||||||
proc testPostUrl2(): Future[bool] {.async.} =
|
proc testPostUrl2(): Future[bool] {.async.} =
|
||||||
var serverRes = false
|
var serverRes = false
|
||||||
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
||||||
async: (raises: [CancelledError, HttpResponseError]).} =
|
async: (raises: [CancelledError]).} =
|
||||||
if r.isOk():
|
if r.isOk():
|
||||||
var kres = newSeq[string]()
|
var kres = newSeq[string]()
|
||||||
let request = r.get()
|
let request = r.get()
|
||||||
if request.meth in PostMethods:
|
if request.meth in PostMethods:
|
||||||
let post = await request.post()
|
let post =
|
||||||
|
try:
|
||||||
|
await request.post()
|
||||||
|
except HttpProtocolError as exc:
|
||||||
|
return defaultResponse(exc)
|
||||||
|
except HttpTransportError as exc:
|
||||||
|
return defaultResponse(exc)
|
||||||
for k, v in post.stringItems():
|
for k, v in post.stringItems():
|
||||||
kres.add(k & ":" & v)
|
kres.add(k & ":" & v)
|
||||||
sort(kres)
|
sort(kres)
|
||||||
serverRes = true
|
serverRes = true
|
||||||
return await request.respond(Http200, "TEST_OK:" & kres.join(":"),
|
try:
|
||||||
HttpTable.init())
|
await request.respond(Http200, "TEST_OK:" & kres.join(":"),
|
||||||
|
HttpTable.init())
|
||||||
|
except HttpWriteError as exc:
|
||||||
|
serverRes = false
|
||||||
|
defaultResponse(exc)
|
||||||
else:
|
else:
|
||||||
serverRes = false
|
defaultResponse()
|
||||||
return defaultResponse()
|
|
||||||
|
|
||||||
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
|
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
|
||||||
let res = HttpServerRef.new(initTAddress("127.0.0.1:0"), process,
|
let res = HttpServerRef.new(initTAddress("127.0.0.1:0"), process,
|
||||||
@ -440,21 +472,30 @@ suite "HTTP server testing suite":
|
|||||||
proc testPostMultipart(): Future[bool] {.async.} =
|
proc testPostMultipart(): Future[bool] {.async.} =
|
||||||
var serverRes = false
|
var serverRes = false
|
||||||
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
||||||
async: (raises: [CancelledError, HttpResponseError]).} =
|
async: (raises: [CancelledError]).} =
|
||||||
if r.isOk():
|
if r.isOk():
|
||||||
var kres = newSeq[string]()
|
var kres = newSeq[string]()
|
||||||
let request = r.get()
|
let request = r.get()
|
||||||
if request.meth in PostMethods:
|
if request.meth in PostMethods:
|
||||||
let post = await request.post()
|
let post =
|
||||||
|
try:
|
||||||
|
await request.post()
|
||||||
|
except HttpProtocolError as exc:
|
||||||
|
return defaultResponse(exc)
|
||||||
|
except HttpTransportError as exc:
|
||||||
|
return defaultResponse(exc)
|
||||||
for k, v in post.stringItems():
|
for k, v in post.stringItems():
|
||||||
kres.add(k & ":" & v)
|
kres.add(k & ":" & v)
|
||||||
sort(kres)
|
sort(kres)
|
||||||
serverRes = true
|
serverRes = true
|
||||||
return await request.respond(Http200, "TEST_OK:" & kres.join(":"),
|
try:
|
||||||
HttpTable.init())
|
await request.respond(Http200, "TEST_OK:" & kres.join(":"),
|
||||||
|
HttpTable.init())
|
||||||
|
except HttpWriteError as exc:
|
||||||
|
serverRes = false
|
||||||
|
defaultResponse(exc)
|
||||||
else:
|
else:
|
||||||
serverRes = false
|
defaultResponse()
|
||||||
return defaultResponse()
|
|
||||||
|
|
||||||
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
|
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
|
||||||
let res = HttpServerRef.new(initTAddress("127.0.0.1:0"), process,
|
let res = HttpServerRef.new(initTAddress("127.0.0.1:0"), process,
|
||||||
@ -496,21 +537,31 @@ suite "HTTP server testing suite":
|
|||||||
proc testPostMultipart2(): Future[bool] {.async.} =
|
proc testPostMultipart2(): Future[bool] {.async.} =
|
||||||
var serverRes = false
|
var serverRes = false
|
||||||
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
||||||
async: (raises: [CancelledError, HttpResponseError]).} =
|
async: (raises: [CancelledError]).} =
|
||||||
if r.isOk():
|
if r.isOk():
|
||||||
var kres = newSeq[string]()
|
var kres = newSeq[string]()
|
||||||
let request = r.get()
|
let request = r.get()
|
||||||
if request.meth in PostMethods:
|
if request.meth in PostMethods:
|
||||||
let post = await request.post()
|
let post =
|
||||||
|
try:
|
||||||
|
await request.post()
|
||||||
|
except HttpProtocolError as exc:
|
||||||
|
return defaultResponse(exc)
|
||||||
|
except HttpTransportError as exc:
|
||||||
|
return defaultResponse(exc)
|
||||||
for k, v in post.stringItems():
|
for k, v in post.stringItems():
|
||||||
kres.add(k & ":" & v)
|
kres.add(k & ":" & v)
|
||||||
sort(kres)
|
sort(kres)
|
||||||
serverRes = true
|
serverRes = true
|
||||||
return await request.respond(Http200, "TEST_OK:" & kres.join(":"),
|
try:
|
||||||
HttpTable.init())
|
await request.respond(Http200, "TEST_OK:" & kres.join(":"),
|
||||||
|
HttpTable.init())
|
||||||
|
except HttpWriteError as exc:
|
||||||
|
serverRes = false
|
||||||
|
defaultResponse(exc)
|
||||||
else:
|
else:
|
||||||
serverRes = false
|
serverRes = false
|
||||||
return defaultResponse()
|
defaultResponse()
|
||||||
|
|
||||||
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
|
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
|
||||||
let res = HttpServerRef.new(initTAddress("127.0.0.1:0"), process,
|
let res = HttpServerRef.new(initTAddress("127.0.0.1:0"), process,
|
||||||
@ -566,16 +617,19 @@ suite "HTTP server testing suite":
|
|||||||
var count = 0
|
var count = 0
|
||||||
|
|
||||||
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
||||||
async: (raises: [CancelledError, HttpResponseError]).} =
|
async: (raises: [CancelledError]).} =
|
||||||
if r.isOk():
|
if r.isOk():
|
||||||
let request = r.get()
|
let request = r.get()
|
||||||
inc(count)
|
inc(count)
|
||||||
if count == ClientsCount:
|
if count == ClientsCount:
|
||||||
eventWait.fire()
|
eventWait.fire()
|
||||||
await eventContinue.wait()
|
await eventContinue.wait()
|
||||||
return await request.respond(Http404, "", HttpTable.init())
|
try:
|
||||||
|
await request.respond(Http404, "", HttpTable.init())
|
||||||
|
except HttpWriteError as exc:
|
||||||
|
defaultResponse(exc)
|
||||||
else:
|
else:
|
||||||
return defaultResponse()
|
defaultResponse()
|
||||||
|
|
||||||
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
|
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
|
||||||
let res = HttpServerRef.new(initTAddress("127.0.0.1:0"), process,
|
let res = HttpServerRef.new(initTAddress("127.0.0.1:0"), process,
|
||||||
@ -1230,23 +1284,26 @@ suite "HTTP server testing suite":
|
|||||||
proc testPostMultipart2(): Future[bool] {.async.} =
|
proc testPostMultipart2(): Future[bool] {.async.} =
|
||||||
var serverRes = false
|
var serverRes = false
|
||||||
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
||||||
async: (raises: [CancelledError, HttpResponseError]).} =
|
async: (raises: [CancelledError]).} =
|
||||||
if r.isOk():
|
if r.isOk():
|
||||||
let request = r.get()
|
let request = r.get()
|
||||||
let response = request.getResponse()
|
let response = request.getResponse()
|
||||||
await response.prepareSSE()
|
try:
|
||||||
await response.send("event: event1\r\ndata: data1\r\n\r\n")
|
await response.prepareSSE()
|
||||||
await response.send("event: event2\r\ndata: data2\r\n\r\n")
|
await response.send("event: event1\r\ndata: data1\r\n\r\n")
|
||||||
await response.sendEvent("event3", "data3")
|
await response.send("event: event2\r\ndata: data2\r\n\r\n")
|
||||||
await response.sendEvent("event4", "data4")
|
await response.sendEvent("event3", "data3")
|
||||||
await response.send("data: data5\r\n\r\n")
|
await response.sendEvent("event4", "data4")
|
||||||
await response.sendEvent("", "data6")
|
await response.send("data: data5\r\n\r\n")
|
||||||
await response.finish()
|
await response.sendEvent("", "data6")
|
||||||
serverRes = true
|
await response.finish()
|
||||||
return response
|
serverRes = true
|
||||||
|
response
|
||||||
|
except HttpWriteError as exc:
|
||||||
|
serverRes = false
|
||||||
|
defaultResponse(exc)
|
||||||
else:
|
else:
|
||||||
serverRes = false
|
defaultResponse()
|
||||||
return defaultResponse()
|
|
||||||
|
|
||||||
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
|
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
|
||||||
let res = HttpServerRef.new(initTAddress("127.0.0.1:0"), process,
|
let res = HttpServerRef.new(initTAddress("127.0.0.1:0"), process,
|
||||||
@ -1306,12 +1363,15 @@ suite "HTTP server testing suite":
|
|||||||
]
|
]
|
||||||
|
|
||||||
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
||||||
async: (raises: [CancelledError, HttpResponseError]).} =
|
async: (raises: [CancelledError]).} =
|
||||||
if r.isOk():
|
if r.isOk():
|
||||||
let request = r.get()
|
let request = r.get()
|
||||||
return await request.respond(Http200, "TEST_OK", HttpTable.init())
|
try:
|
||||||
|
await request.respond(Http200, "TEST_OK", HttpTable.init())
|
||||||
|
except HttpWriteError as exc:
|
||||||
|
defaultResponse(exc)
|
||||||
else:
|
else:
|
||||||
return defaultResponse()
|
defaultResponse()
|
||||||
|
|
||||||
for test in TestMessages:
|
for test in TestMessages:
|
||||||
let
|
let
|
||||||
@ -1360,12 +1420,15 @@ suite "HTTP server testing suite":
|
|||||||
TestRequest = "GET /httpdebug HTTP/1.1\r\nConnection: keep-alive\r\n\r\n"
|
TestRequest = "GET /httpdebug HTTP/1.1\r\nConnection: keep-alive\r\n\r\n"
|
||||||
|
|
||||||
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
||||||
async: (raises: [CancelledError, HttpResponseError]).} =
|
async: (raises: [CancelledError]).} =
|
||||||
if r.isOk():
|
if r.isOk():
|
||||||
let request = r.get()
|
let request = r.get()
|
||||||
return await request.respond(Http200, "TEST_OK", HttpTable.init())
|
try:
|
||||||
|
await request.respond(Http200, "TEST_OK", HttpTable.init())
|
||||||
|
except HttpWriteError as exc:
|
||||||
|
defaultResponse(exc)
|
||||||
else:
|
else:
|
||||||
return defaultResponse()
|
defaultResponse()
|
||||||
|
|
||||||
proc client(address: TransportAddress,
|
proc client(address: TransportAddress,
|
||||||
data: string): Future[StreamTransport] {.async.} =
|
data: string): Future[StreamTransport] {.async.} =
|
||||||
|
|||||||
@ -108,15 +108,18 @@ suite "Secure HTTP server testing suite":
|
|||||||
proc testHTTPS(address: TransportAddress): Future[bool] {.async.} =
|
proc testHTTPS(address: TransportAddress): Future[bool] {.async.} =
|
||||||
var serverRes = false
|
var serverRes = false
|
||||||
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
||||||
async: (raises: [CancelledError, HttpResponseError]).} =
|
async: (raises: [CancelledError]).} =
|
||||||
if r.isOk():
|
if r.isOk():
|
||||||
let request = r.get()
|
let request = r.get()
|
||||||
serverRes = true
|
serverRes = true
|
||||||
return await request.respond(Http200, "TEST_OK:" & $request.meth,
|
try:
|
||||||
HttpTable.init())
|
await request.respond(Http200, "TEST_OK:" & $request.meth,
|
||||||
|
HttpTable.init())
|
||||||
|
except HttpWriteError as exc:
|
||||||
|
serverRes = false
|
||||||
|
defaultResponse(exc)
|
||||||
else:
|
else:
|
||||||
serverRes = false
|
defaultResponse()
|
||||||
return defaultResponse()
|
|
||||||
|
|
||||||
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
|
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
|
||||||
let serverFlags = {Secure}
|
let serverFlags = {Secure}
|
||||||
@ -146,16 +149,18 @@ suite "Secure HTTP server testing suite":
|
|||||||
var serverRes = false
|
var serverRes = false
|
||||||
var testFut = newFuture[void]()
|
var testFut = newFuture[void]()
|
||||||
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
proc process(r: RequestFence): Future[HttpResponseRef] {.
|
||||||
async: (raises: [CancelledError, HttpResponseError]).} =
|
async: (raises: [CancelledError]).} =
|
||||||
if r.isOk():
|
if r.isOk():
|
||||||
let request = r.get()
|
let request = r.get()
|
||||||
serverRes = false
|
try:
|
||||||
return await request.respond(Http200, "TEST_OK:" & $request.meth,
|
await request.respond(Http200, "TEST_OK:" & $request.meth,
|
||||||
HttpTable.init())
|
HttpTable.init())
|
||||||
|
except HttpWriteError as exc:
|
||||||
|
defaultResponse(exc)
|
||||||
else:
|
else:
|
||||||
serverRes = true
|
serverRes = true
|
||||||
testFut.complete()
|
testFut.complete()
|
||||||
return defaultResponse()
|
defaultResponse()
|
||||||
|
|
||||||
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
|
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
|
||||||
let serverFlags = {Secure}
|
let serverFlags = {Secure}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user