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:
Eugene Kabanov 2023-12-09 06:50:35 +02:00 committed by GitHub
parent e38ceb5378
commit c41599a6d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 840 additions and 817 deletions

View File

@ -43,30 +43,48 @@ const
ServerHeader* = "server"
LocationHeader* = "location"
AuthorizationHeader* = "authorization"
ContentDispositionHeader* = "content-disposition"
UrlEncodedContentType* = MediaType.init("application/x-www-form-urlencoded")
MultipartContentType* = MediaType.init("multipart/form-data")
type
HttpMessage* = object
code*: HttpCode
contentType*: MediaType
message*: string
HttpResult*[T] = Result[T, string]
HttpResultCode*[T] = Result[T, HttpCode]
HttpResultMessage*[T] = Result[T, HttpMessage]
HttpDefect* = object of Defect
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
HttpReadError* = object of HttpError
HttpWriteError* = object of HttpError
HttpProtocolError* = object of HttpError
HttpRedirectError* = object of HttpError
HttpAddressError* = object of HttpError
HttpUseClosedError* = object of HttpError
HttpTransportError* = object of HttpError
HttpAddressError* = object of HttpTransportError
HttpRedirectError* = object of HttpTransportError
HttpConnectionError* = object of HttpTransportError
HttpReadError* = object of HttpTransportError
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
key: string
@ -127,6 +145,11 @@ func toString*(error: HttpAddressErrorType): string =
of HttpAddressErrorType.NoAddressResolved:
"No address has been resolved"
proc raiseHttpRequestBodyTooLargeError*() {.
noinline, noreturn, raises: [HttpRequestBodyTooLargeError].} =
raise (ref HttpRequestBodyTooLargeError)(
code: Http413, msg: MaximumBodySizeError)
proc raiseHttpCriticalError*(msg: string, code = Http400) {.
noinline, noreturn, raises: [HttpCriticalError].} =
raise (ref HttpCriticalError)(code: code, msg: msg)
@ -135,9 +158,6 @@ proc raiseHttpDisconnectError*() {.
noinline, noreturn, raises: [HttpDisconnectError].} =
raise (ref HttpDisconnectError)(msg: "Remote peer disconnected")
proc raiseHttpDefect*(msg: string) {.noinline, noreturn.} =
raise (ref HttpDefect)(msg: msg)
proc raiseHttpConnectionError*(msg: string) {.
noinline, noreturn, raises: [HttpConnectionError].} =
raise (ref HttpConnectionError)(msg: msg)
@ -152,7 +172,15 @@ proc raiseHttpReadError*(msg: string) {.
proc raiseHttpProtocolError*(msg: string) {.
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) {.
noinline, noreturn, raises: [HttpWriteError].} =
@ -178,6 +206,23 @@ template newHttpWriteError*(message: string): ref HttpWriteError =
template newHttpUseClosedError*(): ref HttpUseClosedError =
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,
flags: set[QueryParamsFlag] = {}): KeyValueTuple =
## Iterate over url-encoded query string.

File diff suppressed because it is too large Load Diff

View File

@ -18,7 +18,8 @@ import "."/[httptable, httpcommon, httpbodyrw]
export asyncloop, httptable, httpcommon, httpbodyrw, asyncstream, httputils
const
UnableToReadMultipartBody = "Unable to read multipart message body"
UnableToReadMultipartBody = "Unable to read multipart message body, reason: "
UnableToSendMultipartMessage = "Unable to send multipart message, reason: "
type
MultiPartSource* {.pure.} = enum
@ -69,7 +70,7 @@ type
name*: string
filename*: string
MultipartError* = object of HttpCriticalError
MultipartError* = object of HttpProtocolError
MultipartEOMError* = object of MultipartError
BChar* = byte | char
@ -105,7 +106,7 @@ func setPartNames(part: var MultiPart): HttpResult[void] =
return err("Content-Disposition header value is incorrect")
let dtype = disp.dispositionType(header.toOpenArrayByte(0, len(header) - 1))
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)):
case k.toLowerAscii()
of "name":
@ -171,8 +172,17 @@ proc new*[B: BChar](mpt: typedesc[MultiPartReaderRef],
stream: stream, offset: 0, boundary: fboundary,
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] {.
async: (raises: [CancelledError, HttpCriticalError]).} =
async: (raises: [CancelledError, HttpReadError, HttpProtocolError]).} =
doAssert(mpr.kind == MultiPartSource.Stream)
if mpr.firstTime:
try:
@ -181,14 +191,11 @@ proc readPart*(mpr: MultiPartReaderRef): Future[MultiPart] {.
mpr.firstTime = false
if not(startsWith(mpr.buffer.toOpenArray(0, len(mpr.boundary) - 3),
mpr.boundary.toOpenArray(2, len(mpr.boundary) - 1))):
raiseHttpCriticalError("Unexpected boundary encountered")
raiseHttpProtocolError(Http400, "Unexpected boundary encountered")
except CancelledError as exc:
raise exc
except AsyncStreamError:
if mpr.stream.hasOverflow():
raiseHttpCriticalError(MaximumBodySizeError, Http413)
else:
raiseHttpCriticalError(UnableToReadMultipartBody)
except AsyncStreamError as exc:
handleAsyncStreamReaderError(mpr.stream, exc)
# Reading part's headers
try:
@ -202,9 +209,9 @@ proc readPart*(mpr: MultiPartReaderRef): Future[MultiPart] {.
raise newException(MultipartEOMError,
"End of multipart message")
else:
raiseHttpCriticalError("Incorrect multipart header found")
raiseHttpProtocolError(Http400, "Incorrect multipart header found")
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.
# Reading part's headers
@ -212,7 +219,7 @@ proc readPart*(mpr: MultiPartReaderRef): Future[MultiPart] {.
HeadersMark)
var headersList = parseHeaders(mpr.buffer.toOpenArray(0, res - 1), false)
if headersList.failed():
raiseHttpCriticalError("Incorrect multipart's headers found")
raiseHttpProtocolError(Http400, "Incorrect multipart's headers found")
inc(mpr.counter)
var part = MultiPart(
@ -228,45 +235,35 @@ proc readPart*(mpr: MultiPartReaderRef): Future[MultiPart] {.
let sres = part.setPartNames()
if sres.isErr():
raiseHttpCriticalError($sres.error)
raiseHttpProtocolError(Http400, $sres.error)
return part
except CancelledError as exc:
raise exc
except AsyncStreamError:
if mpr.stream.hasOverflow():
raiseHttpCriticalError(MaximumBodySizeError, Http413)
else:
raiseHttpCriticalError(UnableToReadMultipartBody)
except AsyncStreamError as exc:
handleAsyncStreamReaderError(mpr.stream, exc)
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.
case mp.kind
of MultiPartSource.Stream:
try:
let res = await mp.stream.read()
return res
except AsyncStreamError:
if mp.breader.hasOverflow():
raiseHttpCriticalError(MaximumBodySizeError, Http413)
else:
raiseHttpCriticalError(UnableToReadMultipartBody)
await mp.stream.read()
except AsyncStreamError as exc:
handleAsyncStreamReaderError(mp.breader, exc)
of MultiPartSource.Buffer:
return mp.buffer
mp.buffer
proc consumeBody*(mp: MultiPart) {.
async: (raises: [CancelledError, HttpCriticalError]).} =
async: (raises: [CancelledError, HttpReadError, HttpProtocolError]).} =
## Discard multipart's ``mp`` value.
case mp.kind
of MultiPartSource.Stream:
try:
discard await mp.stream.consume()
except AsyncStreamError:
if mp.breader.hasOverflow():
raiseHttpCriticalError(MaximumBodySizeError, Http413)
else:
raiseHttpCriticalError(UnableToReadMultipartBody)
except AsyncStreamError as exc:
handleAsyncStreamReaderError(mp.breader, exc)
of MultiPartSource.Buffer:
discard
@ -533,7 +530,7 @@ proc new*[B: BChar](mpt: typedesc[MultiPartWriterRef],
proc prepareHeaders(partMark: openArray[byte], name: string, filename: string,
headers: HttpTable): string =
const ContentDisposition = "Content-Disposition"
const ContentDispositionHeader = "Content-Disposition"
let qname =
block:
let res = quoteCheck(name)
@ -546,10 +543,10 @@ proc prepareHeaders(partMark: openArray[byte], name: string, filename: string,
res.get()
var buffer = newString(len(partMark))
copyMem(addr buffer[0], unsafeAddr partMark[0], len(partMark))
buffer.add(ContentDisposition)
buffer.add(ContentDispositionHeader)
buffer.add(": ")
if ContentDisposition in headers:
buffer.add(headers.getString(ContentDisposition))
if ContentDispositionHeader in headers:
buffer.add(headers.getString(ContentDispositionHeader))
buffer.add("\r\n")
else:
buffer.add("form-data; name=\"")
@ -562,7 +559,7 @@ proc prepareHeaders(partMark: openArray[byte], name: string, filename: string,
buffer.add("\r\n")
for k, v in headers.stringItems():
if k != toLowerAscii(ContentDisposition):
if k != ContentDispositionHeader:
if len(v) > 0:
buffer.add(k)
buffer.add(": ")
@ -572,7 +569,7 @@ proc prepareHeaders(partMark: openArray[byte], name: string, filename: string,
buffer
proc begin*(mpw: MultiPartWriterRef) {.
async: (raises: [CancelledError, HttpCriticalError]).} =
async: (raises: [CancelledError, HttpWriteError]).} =
## Starts multipart message form and write approprate markers to output
## stream.
doAssert(mpw.kind == MultiPartSource.Stream)
@ -580,10 +577,9 @@ proc begin*(mpw: MultiPartWriterRef) {.
# write "--"
try:
await mpw.stream.write(mpw.beginMark)
except AsyncStreamError:
mpw.state = MultiPartWriterState.MessageFailure
raiseHttpCriticalError("Unable to start multipart message")
mpw.state = MultiPartWriterState.MessageStarted
mpw.state = MultiPartWriterState.MessageStarted
except AsyncStreamError as exc:
handleAsyncStreamWriterError(mpw, exc)
proc begin*(mpw: var MultiPartWriter) =
## 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,
filename: string, headers: HttpTable) {.
async: (raises: [CancelledError, HttpCriticalError]).} =
async: (raises: [CancelledError, HttpWriteError]).} =
## Starts part of multipart message and write appropriate ``headers`` to the
## output stream.
##
@ -611,9 +607,8 @@ proc beginPart*(mpw: MultiPartWriterRef, name: string,
try:
await mpw.stream.write(buffer)
mpw.state = MultiPartWriterState.PartStarted
except AsyncStreamError:
mpw.state = MultiPartWriterState.MessageFailure
raiseHttpCriticalError("Unable to start multipart part")
except AsyncStreamError as exc:
handleAsyncStreamWriterError(mpw, exc)
proc beginPart*(mpw: var MultiPartWriter, name: string,
filename: string, headers: HttpTable) =
@ -632,7 +627,7 @@ proc beginPart*(mpw: var MultiPartWriter, name: string,
mpw.state = MultiPartWriterState.PartStarted
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.
doAssert(mpw.kind == MultiPartSource.Stream)
doAssert(mpw.state == MultiPartWriterState.PartStarted)
@ -640,12 +635,10 @@ proc write*(mpw: MultiPartWriterRef, pbytes: pointer, nbytes: int) {.
# write <chunk> of data
await mpw.stream.write(pbytes, nbytes)
except AsyncStreamError as exc:
mpw.state = MultiPartWriterState.MessageFailure
raiseHttpCriticalError(
"Unable to write multipart data, reason: " & $exc.msg)
handleAsyncStreamWriterError(mpw, exc)
proc write*(mpw: MultiPartWriterRef, data: seq[byte]) {.
async: (raises: [CancelledError, HttpCriticalError]).} =
async: (raises: [CancelledError, HttpWriteError]).} =
## Write part's data ``data`` to the output stream.
doAssert(mpw.kind == MultiPartSource.Stream)
doAssert(mpw.state == MultiPartWriterState.PartStarted)
@ -653,12 +646,10 @@ proc write*(mpw: MultiPartWriterRef, data: seq[byte]) {.
# write <chunk> of data
await mpw.stream.write(data)
except AsyncStreamError as exc:
mpw.state = MultiPartWriterState.MessageFailure
raiseHttpCriticalError(
"Unable to write multipart data, reason: " & $exc.msg)
handleAsyncStreamWriterError(mpw, exc)
proc write*(mpw: MultiPartWriterRef, data: string) {.
async: (raises: [CancelledError, HttpCriticalError]).} =
async: (raises: [CancelledError, HttpWriteError]).} =
## Write part's data ``data`` to the output stream.
doAssert(mpw.kind == MultiPartSource.Stream)
doAssert(mpw.state == MultiPartWriterState.PartStarted)
@ -666,9 +657,7 @@ proc write*(mpw: MultiPartWriterRef, data: string) {.
# write <chunk> of data
await mpw.stream.write(data)
except AsyncStreamError as exc:
mpw.state = MultiPartWriterState.MessageFailure
raiseHttpCriticalError(
"Unable to write multipart data, reason: " & $exc.msg)
handleAsyncStreamWriterError(mpw, exc)
proc write*(mpw: var MultiPartWriter, pbytes: pointer, nbytes: int) =
## 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))
proc finishPart*(mpw: MultiPartWriterRef) {.
async: (raises: [CancelledError, HttpCriticalError]).} =
async: (raises: [CancelledError, HttpWriteError]).} =
## Finish multipart's message part and send proper markers to output stream.
doAssert(mpw.state == MultiPartWriterState.PartStarted)
try:
@ -700,9 +689,7 @@ proc finishPart*(mpw: MultiPartWriterRef) {.
await mpw.stream.write(mpw.finishPartMark)
mpw.state = MultiPartWriterState.PartFinished
except AsyncStreamError as exc:
mpw.state = MultiPartWriterState.MessageFailure
raiseHttpCriticalError(
"Unable to finish multipart message part, reason: " & $exc.msg)
handleAsyncStreamWriterError(mpw, exc)
proc finishPart*(mpw: var MultiPartWriter) =
## 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
proc finish*(mpw: MultiPartWriterRef) {.
async: (raises: [CancelledError, HttpCriticalError]).} =
async: (raises: [CancelledError, HttpWriteError]).} =
## Finish multipart's message form and send finishing markers to the output
## stream.
doAssert(mpw.kind == MultiPartSource.Stream)
@ -723,9 +710,7 @@ proc finish*(mpw: MultiPartWriterRef) {.
await mpw.stream.write(mpw.finishMark)
mpw.state = MultiPartWriterState.MessageFinished
except AsyncStreamError as exc:
mpw.state = MultiPartWriterState.MessageFailure
raiseHttpCriticalError(
"Unable to finish multipart message, reason: " & $exc.msg)
handleAsyncStreamWriterError(mpw, exc)
proc finish*(mpw: var MultiPartWriter): seq[byte] =
## Finish multipart's message form and send finishing markers to the output

View File

@ -164,22 +164,21 @@ proc new*(htype: typedesc[SecureHttpServerRef],
maxRequestBodySize: int = 1_048_576,
dualstack = DualStackType.Auto
): HttpResult[SecureHttpServerRef] {.
deprecated: "raises missing from process callback".} =
proc processCallback2(req: RequestFence): Future[HttpResponseRef] {.
async: (raises: [CancelledError, HttpResponseError]).} =
try:
await processCallback(req)
except CancelledError as exc:
raise exc
except HttpResponseError as exc:
raise exc
except CatchableError as exc:
# Emulate 3.x behavior
raise (ref HttpCriticalError)(msg: exc.msg, code: Http503)
deprecated: "Callback could raise only CancelledError, annotate with " &
"{.async: (raises: [CancelledError]).}".} =
proc wrap(req: RequestFence): Future[HttpResponseRef] {.
async: (raises: [CancelledError]).} =
try:
await processCallback(req)
except CancelledError as exc:
raise exc
except CatchableError as exc:
defaultResponse(exc)
SecureHttpServerRef.new(
address = address,
processCallback = processCallback2,
processCallback = wrap,
tlsPrivateKey = tlsPrivateKey,
tlsCertificate = tlsCertificate,
serverFlags = serverFlags,
@ -194,4 +193,4 @@ proc new*(htype: typedesc[SecureHttpServerRef],
maxHeadersSize = maxHeadersSize,
maxRequestBodySize = maxRequestBodySize,
dualstack = dualstack
)
)

View File

@ -85,7 +85,8 @@ suite "HTTP client testing suite":
res
proc createServer(address: TransportAddress,
process: HttpProcessCallback2, secure: bool): HttpServerRef =
process: HttpProcessCallback2,
secure: bool): HttpServerRef =
let
socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
serverFlags = {HttpServerFlags.Http11Pipeline}
@ -128,18 +129,24 @@ suite "HTTP client testing suite":
(MethodPatch, "/test/patch")
]
proc process(r: RequestFence): Future[HttpResponseRef] {.
async: (raises: [CancelledError, HttpResponseError]).} =
async: (raises: [CancelledError]).} =
if r.isOk():
let request = r.get()
case request.uri.path
of "/test/get", "/test/post", "/test/head", "/test/put",
"/test/delete", "/test/trace", "/test/options", "/test/connect",
"/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:
return await request.respond(Http404, "Page not found")
try:
await request.respond(Http404, "Page not found")
except HttpWriteError as exc:
defaultResponse(exc)
else:
return defaultResponse()
defaultResponse()
var server = createServer(initTAddress("127.0.0.1:0"), process, secure)
server.start()
@ -195,7 +202,7 @@ suite "HTTP client testing suite":
"LONGCHUNKRESPONSE")
]
proc process(r: RequestFence): Future[HttpResponseRef] {.
async: (raises: [CancelledError, HttpResponseError]).} =
async: (raises: [CancelledError]).} =
if r.isOk():
let request = r.get()
case request.uri.path
@ -203,46 +210,58 @@ suite "HTTP client testing suite":
var response = request.getResponse()
var data = createBigMessage(ResponseTests[0][4], ResponseTests[0][2])
response.status = Http200
await response.sendBody(data)
return response
try:
await response.sendBody(data)
except HttpWriteError as exc:
return defaultResponse(exc)
response
of "/test/long_size_response":
var response = request.getResponse()
var data = createBigMessage(ResponseTests[1][4], ResponseTests[1][2])
response.status = Http200
await response.sendBody(data)
return response
try:
await response.sendBody(data)
except HttpWriteError as exc:
return defaultResponse(exc)
response
of "/test/short_chunked_response":
var response = request.getResponse()
var data = createBigMessage(ResponseTests[2][4], ResponseTests[2][2])
response.status = Http200
await response.prepare()
var offset = 0
while true:
if len(data) == offset:
break
let toWrite = min(1024, len(data) - offset)
await response.sendChunk(addr data[offset], toWrite)
offset = offset + toWrite
await response.finish()
return response
try:
await response.prepare()
var offset = 0
while true:
if len(data) == offset:
break
let toWrite = min(1024, len(data) - offset)
await response.sendChunk(addr data[offset], toWrite)
offset = offset + toWrite
await response.finish()
except HttpWriteError as exc:
return defaultResponse(exc)
response
of "/test/long_chunked_response":
var response = request.getResponse()
var data = createBigMessage(ResponseTests[3][4], ResponseTests[3][2])
response.status = Http200
await response.prepare()
var offset = 0
while true:
if len(data) == offset:
break
let toWrite = min(1024, len(data) - offset)
await response.sendChunk(addr data[offset], toWrite)
offset = offset + toWrite
await response.finish()
return response
try:
await response.prepare()
var offset = 0
while true:
if len(data) == offset:
break
let toWrite = min(1024, len(data) - offset)
await response.sendChunk(addr data[offset], toWrite)
offset = offset + toWrite
await response.finish()
except HttpWriteError as exc:
return defaultResponse(exc)
response
else:
return await request.respond(Http404, "Page not found")
defaultResponse()
else:
return defaultResponse()
defaultResponse()
var server = createServer(initTAddress("127.0.0.1:0"), process, secure)
server.start()
@ -311,21 +330,26 @@ suite "HTTP client testing suite":
(MethodPost, "/test/big_request", 262400)
]
proc process(r: RequestFence): Future[HttpResponseRef] {.
async: (raises: [CancelledError, HttpResponseError]).} =
async: (raises: [CancelledError]).} =
if r.isOk():
let request = r.get()
case request.uri.path
of "/test/big_request":
if request.hasBody():
let body = await request.getBody()
let digest = $secureHash(string.fromBytes(body))
return await request.respond(Http200, digest)
else:
return await request.respond(Http400, "Missing content body")
try:
if request.hasBody():
let body = await request.getBody()
let digest = $secureHash(string.fromBytes(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:
return await request.respond(Http404, "Page not found")
defaultResponse()
else:
return defaultResponse()
defaultResponse()
var server = createServer(initTAddress("127.0.0.1:0"), process, secure)
server.start()
@ -381,21 +405,27 @@ suite "HTTP client testing suite":
(MethodPost, "/test/big_chunk_request", 262400)
]
proc process(r: RequestFence): Future[HttpResponseRef] {.
async: (raises: [CancelledError, HttpResponseError]).} =
async: (raises: [CancelledError]).} =
if r.isOk():
let request = r.get()
case request.uri.path
of "/test/big_chunk_request":
if request.hasBody():
let body = await request.getBody()
let digest = $secureHash(string.fromBytes(body))
return await request.respond(Http200, digest)
else:
return await request.respond(Http400, "Missing content body")
try:
if request.hasBody():
let
body = await request.getBody()
digest = $secureHash(string.fromBytes(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:
return await request.respond(Http404, "Page not found")
defaultResponse()
else:
return defaultResponse()
defaultResponse()
var server = createServer(initTAddress("127.0.0.1:0"), process, secure)
server.start()
@ -455,23 +485,28 @@ suite "HTTP client testing suite":
]
proc process(r: RequestFence): Future[HttpResponseRef] {.
async: (raises: [CancelledError, HttpResponseError]).} =
async: (raises: [CancelledError]).} =
if r.isOk():
let request = r.get()
case request.uri.path
of "/test/post/urlencoded_size", "/test/post/urlencoded_chunked":
if request.hasBody():
var postTable = await request.post()
let body = postTable.getString("field1") & ":" &
postTable.getString("field2") & ":" &
postTable.getString("field3")
return await request.respond(Http200, body)
else:
return await request.respond(Http400, "Missing content body")
try:
if request.hasBody():
var postTable = await request.post()
let body = postTable.getString("field1") & ":" &
postTable.getString("field2") & ":" &
postTable.getString("field3")
await request.respond(Http200, body)
else:
await request.respond(Http400, "Missing content body")
except HttpTransportError as exc:
defaultResponse(exc)
except HttpProtocolError as exc:
defaultResponse(exc)
else:
return await request.respond(Http404, "Page not found")
defaultResponse()
else:
return defaultResponse()
defaultResponse()
var server = createServer(initTAddress("127.0.0.1:0"), process, secure)
server.start()
@ -554,23 +589,28 @@ suite "HTTP client testing suite":
]
proc process(r: RequestFence): Future[HttpResponseRef] {.
async: (raises: [CancelledError, HttpResponseError]).} =
async: (raises: [CancelledError]).} =
if r.isOk():
let request = r.get()
case request.uri.path
of "/test/post/multipart_size", "/test/post/multipart_chunked":
if request.hasBody():
var postTable = await request.post()
let body = postTable.getString("field1") & ":" &
postTable.getString("field2") & ":" &
postTable.getString("field3")
return await request.respond(Http200, body)
else:
return await request.respond(Http400, "Missing content body")
try:
if request.hasBody():
var postTable = await request.post()
let body = postTable.getString("field1") & ":" &
postTable.getString("field2") & ":" &
postTable.getString("field3")
await request.respond(Http200, body)
else:
await request.respond(Http400, "Missing content body")
except HttpProtocolError as exc:
defaultResponse(exc)
except HttpTransportError as exc:
defaultResponse(exc)
else:
return await request.respond(Http404, "Page not found")
defaultResponse()
else:
return defaultResponse()
defaultResponse()
var server = createServer(initTAddress("127.0.0.1:0"), process, secure)
server.start()
@ -649,26 +689,29 @@ suite "HTTP client testing suite":
var lastAddress: Uri
proc process(r: RequestFence): Future[HttpResponseRef] {.
async: (raises: [CancelledError, HttpResponseError]).} =
async: (raises: [CancelledError]).} =
if r.isOk():
let request = r.get()
case request.uri.path
of "/":
return await request.redirect(Http302, "/redirect/1")
of "/redirect/1":
return await request.redirect(Http302, "/next/redirect/2")
of "/next/redirect/2":
return await request.redirect(Http302, "redirect/3")
of "/next/redirect/redirect/3":
return await request.redirect(Http302, "next/redirect/4")
of "/next/redirect/redirect/next/redirect/4":
return await request.redirect(Http302, lastAddress)
of "/final/5":
return await request.respond(Http200, "ok-5")
else:
return await request.respond(Http404, "Page not found")
try:
case request.uri.path
of "/":
await request.redirect(Http302, "/redirect/1")
of "/redirect/1":
await request.redirect(Http302, "/next/redirect/2")
of "/next/redirect/2":
await request.redirect(Http302, "redirect/3")
of "/next/redirect/redirect/3":
await request.redirect(Http302, "next/redirect/4")
of "/next/redirect/redirect/next/redirect/4":
await request.redirect(Http302, lastAddress)
of "/final/5":
await request.respond(Http200, "ok-5")
else:
await request.respond(Http404, "Page not found")
except HttpWriteError as exc:
defaultResponse(exc)
else:
return defaultResponse()
defaultResponse()
var server = createServer(initTAddress("127.0.0.1:0"), process, secure)
server.start()
@ -706,8 +749,8 @@ suite "HTTP client testing suite":
proc testSendCancelLeaksTest(secure: bool): Future[bool] {.async.} =
proc process(r: RequestFence): Future[HttpResponseRef] {.
async: (raises: [CancelledError, HttpResponseError]).} =
return defaultResponse()
async: (raises: [CancelledError]).} =
defaultResponse()
var server = createServer(initTAddress("127.0.0.1:0"), process, secure)
server.start()
@ -756,8 +799,8 @@ suite "HTTP client testing suite":
proc testOpenCancelLeaksTest(secure: bool): Future[bool] {.async.} =
proc process(r: RequestFence): Future[HttpResponseRef] {.
async: (raises: [CancelledError, HttpResponseError]).} =
return defaultResponse()
async: (raises: [CancelledError]).} =
defaultResponse()
var server = createServer(initTAddress("127.0.0.1:0"), process, secure)
server.start()
@ -868,20 +911,23 @@ suite "HTTP client testing suite":
(data2.status, data2.data.bytesToString(), count)]
proc process(r: RequestFence): Future[HttpResponseRef] {.
async: (raises: [CancelledError, HttpResponseError]).} =
async: (raises: [CancelledError]).} =
if r.isOk():
let request = r.get()
case request.uri.path
of "/keep":
let headers = HttpTable.init([("connection", "keep-alive")])
return await request.respond(Http200, "ok", headers = headers)
of "/drop":
let headers = HttpTable.init([("connection", "close")])
return await request.respond(Http200, "ok", headers = headers)
else:
return await request.respond(Http404, "Page not found")
try:
case request.uri.path
of "/keep":
let headers = HttpTable.init([("connection", "keep-alive")])
await request.respond(Http200, "ok", headers = headers)
of "/drop":
let headers = HttpTable.init([("connection", "close")])
await request.respond(Http200, "ok", headers = headers)
else:
await request.respond(Http404, "Page not found")
except HttpWriteError as exc:
defaultResponse(exc)
else:
return defaultResponse()
defaultResponse()
var server = createServer(initTAddress("127.0.0.1:0"), process, false)
server.start()
@ -1004,16 +1050,19 @@ suite "HTTP client testing suite":
return (data.status, data.data.bytesToString(), 0)
proc process(r: RequestFence): Future[HttpResponseRef] {.
async: (raises: [CancelledError, HttpResponseError]).} =
async: (raises: [CancelledError]).} =
if r.isOk():
let request = r.get()
case request.uri.path
of "/test":
return await request.respond(Http200, "ok")
else:
return await request.respond(Http404, "Page not found")
try:
case request.uri.path
of "/test":
await request.respond(Http200, "ok")
else:
await request.respond(Http404, "Page not found")
except HttpWriteError as exc:
defaultResponse(exc)
else:
return defaultResponse()
defaultResponse()
var server = createServer(initTAddress("127.0.0.1:0"), process, false)
server.start()
@ -1064,19 +1113,22 @@ suite "HTTP client testing suite":
return (data.status, data.data.bytesToString(), 0)
proc process(r: RequestFence): Future[HttpResponseRef] {.
async: (raises: [CancelledError, HttpResponseError]).} =
async: (raises: [CancelledError]).} =
if r.isOk():
let request = r.get()
case request.uri.path
of "/test":
return await request.respond(Http200, "ok")
of "/keep-test":
let headers = HttpTable.init([("Connection", "keep-alive")])
return await request.respond(Http200, "not-alive", headers)
else:
return await request.respond(Http404, "Page not found")
try:
case request.uri.path
of "/test":
await request.respond(Http200, "ok")
of "/keep-test":
let headers = HttpTable.init([("Connection", "keep-alive")])
await request.respond(Http200, "not-alive", headers)
else:
await request.respond(Http404, "Page not found")
except HttpWriteError as exc:
defaultResponse(exc)
else:
return defaultResponse()
defaultResponse()
var server = createServer(initTAddress("127.0.0.1:0"), process, false)
server.start()
@ -1180,58 +1232,61 @@ suite "HTTP client testing suite":
true
proc process(r: RequestFence): Future[HttpResponseRef] {.
async: (raises: [CancelledError, HttpResponseError]).} =
async: (raises: [CancelledError]).} =
if r.isOk():
let request = r.get()
if request.uri.path.startsWith("/test/single/"):
let index =
block:
var res = -1
for index, value in SingleGoodTests.pairs():
if value[0] == request.uri.path:
res = index
break
res
if index < 0:
return await request.respond(Http404, "Page not found")
var response = request.getResponse()
response.status = Http200
await response.sendBody(SingleGoodTests[index][1])
return response
elif request.uri.path.startsWith("/test/multiple/"):
let index =
block:
var res = -1
for index, value in MultipleGoodTests.pairs():
if value[0] == request.uri.path:
res = index
break
res
if index < 0:
return await request.respond(Http404, "Page not found")
var response = request.getResponse()
response.status = Http200
await response.sendBody(MultipleGoodTests[index][1])
return response
elif request.uri.path.startsWith("/test/overflow/"):
let index =
block:
var res = -1
for index, value in OverflowTests.pairs():
if value[0] == request.uri.path:
res = index
break
res
if index < 0:
return await request.respond(Http404, "Page not found")
var response = request.getResponse()
response.status = Http200
await response.sendBody(OverflowTests[index][1])
return response
else:
return await request.respond(Http404, "Page not found")
try:
if request.uri.path.startsWith("/test/single/"):
let index =
block:
var res = -1
for index, value in SingleGoodTests.pairs():
if value[0] == request.uri.path:
res = index
break
res
if index < 0:
return await request.respond(Http404, "Page not found")
var response = request.getResponse()
response.status = Http200
await response.sendBody(SingleGoodTests[index][1])
response
elif request.uri.path.startsWith("/test/multiple/"):
let index =
block:
var res = -1
for index, value in MultipleGoodTests.pairs():
if value[0] == request.uri.path:
res = index
break
res
if index < 0:
return await request.respond(Http404, "Page not found")
var response = request.getResponse()
response.status = Http200
await response.sendBody(MultipleGoodTests[index][1])
response
elif request.uri.path.startsWith("/test/overflow/"):
let index =
block:
var res = -1
for index, value in OverflowTests.pairs():
if value[0] == request.uri.path:
res = index
break
res
if index < 0:
return await request.respond(Http404, "Page not found")
var response = request.getResponse()
response.status = Http200
await response.sendBody(OverflowTests[index][1])
response
else:
defaultResponse()
except HttpWriteError as exc:
defaultResponse(exc)
else:
return defaultResponse()
defaultResponse()
var server = createServer(initTAddress("127.0.0.1:0"), process, secure)
server.start()

View File

@ -64,7 +64,7 @@ suite "HTTP server testing suite":
proc testTooBigBodyChunked(operation: TooBigTest): Future[bool] {.async.} =
var serverRes = false
proc process(r: RequestFence): Future[HttpResponseRef] {.
async: (raises: [CancelledError, HttpResponseError]).} =
async: (raises: [CancelledError]).} =
if r.isOk():
let request = r.get()
try:
@ -77,13 +77,15 @@ suite "HTTP server testing suite":
let ptable {.used.} = await request.post()
of PostMultipartTest:
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:
serverRes = true
# Reraising exception, because processor should properly handle it.
raise exc
defaultResponse(exc)
else:
return defaultResponse()
defaultResponse()
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
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.} =
var serverRes = false
proc process(r: RequestFence): Future[HttpResponseRef] {.
async: (raises: [CancelledError, HttpResponseError]).} =
async: (raises: [CancelledError]).} =
if r.isOk():
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:
if r.error.kind == HttpServerError.TimeoutError:
serverRes = true
return defaultResponse()
defaultResponse()
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
let res = HttpServerRef.new(initTAddress("127.0.0.1:0"),
@ -158,14 +163,17 @@ suite "HTTP server testing suite":
proc testEmpty(): Future[bool] {.async.} =
var serverRes = false
proc process(r: RequestFence): Future[HttpResponseRef] {.
async: (raises: [CancelledError, HttpResponseError]).} =
async: (raises: [CancelledError]).} =
if r.isOk():
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:
if r.error.kind == HttpServerError.CriticalError:
if r.error.kind == HttpServerError.ProtocolError:
serverRes = true
return defaultResponse()
defaultResponse()
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
let res = HttpServerRef.new(initTAddress("127.0.0.1:0"),
@ -188,14 +196,17 @@ suite "HTTP server testing suite":
proc testTooBig(): Future[bool] {.async.} =
var serverRes = false
proc process(r: RequestFence): Future[HttpResponseRef] {.
async: (raises: [CancelledError, HttpResponseError]).} =
async: (raises: [CancelledError]).} =
if r.isOk():
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:
if r.error.error == HttpServerError.CriticalError:
if r.error.error == HttpServerError.ProtocolError:
serverRes = true
return defaultResponse()
defaultResponse()
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
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.} =
var serverRes = false
proc process(r: RequestFence): Future[HttpResponseRef] {.
async: (raises: [CancelledError, HttpResponseError]).} =
if r.isOk():
discard
else:
if r.error.error == HttpServerError.CriticalError:
async: (raises: [CancelledError]).} =
if r.isErr():
if r.error.error == HttpServerError.ProtocolError:
serverRes = true
return defaultResponse()
defaultResponse()
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
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.} =
var serverRes = false
proc process(r: RequestFence): Future[HttpResponseRef] {.
async: (raises: [CancelledError, HttpResponseError]).} =
async: (raises: [CancelledError]).} =
if r.isOk():
let request = r.get()
var kres = newSeq[string]()
@ -274,11 +283,14 @@ suite "HTTP server testing suite":
kres.add(k & ":" & v)
sort(kres)
serverRes = true
return await request.respond(Http200, "TEST_OK:" & kres.join(":"),
HttpTable.init())
try:
await request.respond(Http200, "TEST_OK:" & kres.join(":"),
HttpTable.init())
except HttpWriteError as exc:
serverRes = false
defaultResponse(exc)
else:
serverRes = false
return defaultResponse()
defaultResponse()
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
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")
await server.stop()
await server.closeWait()
let r = serverRes and
(data1.find("TEST_OK:a:1:a:2:b:3:c:4") >= 0) and
(data2.find("TEST_OK:a:П:b:Ц:c:Ю:Ф:Б") >= 0)
return r
serverRes and
(data1.find("TEST_OK:a:1:a:2:b:3:c:4") >= 0) and
(data2.find("TEST_OK:a:П:b:Ц:c:Ю:Ф:Б") >= 0)
check waitFor(testQuery()) == true
@ -307,7 +318,7 @@ suite "HTTP server testing suite":
proc testHeaders(): Future[bool] {.async.} =
var serverRes = false
proc process(r: RequestFence): Future[HttpResponseRef] {.
async: (raises: [CancelledError, HttpResponseError]).} =
async: (raises: [CancelledError]).} =
if r.isOk():
let request = r.get()
var kres = newSeq[string]()
@ -315,11 +326,14 @@ suite "HTTP server testing suite":
kres.add(k & ":" & v)
sort(kres)
serverRes = true
return await request.respond(Http200, "TEST_OK:" & kres.join(":"),
HttpTable.init())
try:
await request.respond(Http200, "TEST_OK:" & kres.join(":"),
HttpTable.init())
except HttpWriteError as exc:
serverRes = false
defaultResponse(exc)
else:
serverRes = false
return defaultResponse()
defaultResponse()
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
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.} =
var serverRes = false
proc process(r: RequestFence): Future[HttpResponseRef] {.
async: (raises: [CancelledError, HttpResponseError]).} =
async: (raises: [CancelledError]).} =
if r.isOk():
var kres = newSeq[string]()
let request = r.get()
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():
kres.add(k & ":" & v)
sort(kres)
serverRes = true
return await request.respond(Http200, "TEST_OK:" & kres.join(":"),
HttpTable.init())
serverRes = true
try:
await request.respond(Http200, "TEST_OK:" & kres.join(":"),
HttpTable.init())
except HttpWriteError as exc:
serverRes = false
defaultResponse(exc)
else:
serverRes = false
return defaultResponse()
defaultResponse()
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
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.} =
var serverRes = false
proc process(r: RequestFence): Future[HttpResponseRef] {.
async: (raises: [CancelledError, HttpResponseError]).} =
async: (raises: [CancelledError]).} =
if r.isOk():
var kres = newSeq[string]()
let request = r.get()
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():
kres.add(k & ":" & v)
sort(kres)
serverRes = true
return await request.respond(Http200, "TEST_OK:" & kres.join(":"),
HttpTable.init())
serverRes = true
try:
await request.respond(Http200, "TEST_OK:" & kres.join(":"),
HttpTable.init())
except HttpWriteError as exc:
serverRes = false
defaultResponse(exc)
else:
serverRes = false
return defaultResponse()
defaultResponse()
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
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.} =
var serverRes = false
proc process(r: RequestFence): Future[HttpResponseRef] {.
async: (raises: [CancelledError, HttpResponseError]).} =
async: (raises: [CancelledError]).} =
if r.isOk():
var kres = newSeq[string]()
let request = r.get()
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():
kres.add(k & ":" & v)
sort(kres)
serverRes = true
return await request.respond(Http200, "TEST_OK:" & kres.join(":"),
HttpTable.init())
serverRes = true
try:
await request.respond(Http200, "TEST_OK:" & kres.join(":"),
HttpTable.init())
except HttpWriteError as exc:
serverRes = false
defaultResponse(exc)
else:
serverRes = false
return defaultResponse()
defaultResponse()
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
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.} =
var serverRes = false
proc process(r: RequestFence): Future[HttpResponseRef] {.
async: (raises: [CancelledError, HttpResponseError]).} =
async: (raises: [CancelledError]).} =
if r.isOk():
var kres = newSeq[string]()
let request = r.get()
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():
kres.add(k & ":" & v)
sort(kres)
serverRes = true
return await request.respond(Http200, "TEST_OK:" & kres.join(":"),
HttpTable.init())
try:
await request.respond(Http200, "TEST_OK:" & kres.join(":"),
HttpTable.init())
except HttpWriteError as exc:
serverRes = false
defaultResponse(exc)
else:
serverRes = false
return defaultResponse()
defaultResponse()
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
let res = HttpServerRef.new(initTAddress("127.0.0.1:0"), process,
@ -566,16 +617,19 @@ suite "HTTP server testing suite":
var count = 0
proc process(r: RequestFence): Future[HttpResponseRef] {.
async: (raises: [CancelledError, HttpResponseError]).} =
async: (raises: [CancelledError]).} =
if r.isOk():
let request = r.get()
inc(count)
if count == ClientsCount:
eventWait.fire()
await eventContinue.wait()
return await request.respond(Http404, "", HttpTable.init())
try:
await request.respond(Http404, "", HttpTable.init())
except HttpWriteError as exc:
defaultResponse(exc)
else:
return defaultResponse()
defaultResponse()
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
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.} =
var serverRes = false
proc process(r: RequestFence): Future[HttpResponseRef] {.
async: (raises: [CancelledError, HttpResponseError]).} =
async: (raises: [CancelledError]).} =
if r.isOk():
let request = r.get()
let response = request.getResponse()
await response.prepareSSE()
await response.send("event: event1\r\ndata: data1\r\n\r\n")
await response.send("event: event2\r\ndata: data2\r\n\r\n")
await response.sendEvent("event3", "data3")
await response.sendEvent("event4", "data4")
await response.send("data: data5\r\n\r\n")
await response.sendEvent("", "data6")
await response.finish()
serverRes = true
return response
try:
await response.prepareSSE()
await response.send("event: event1\r\ndata: data1\r\n\r\n")
await response.send("event: event2\r\ndata: data2\r\n\r\n")
await response.sendEvent("event3", "data3")
await response.sendEvent("event4", "data4")
await response.send("data: data5\r\n\r\n")
await response.sendEvent("", "data6")
await response.finish()
serverRes = true
response
except HttpWriteError as exc:
serverRes = false
defaultResponse(exc)
else:
serverRes = false
return defaultResponse()
defaultResponse()
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
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] {.
async: (raises: [CancelledError, HttpResponseError]).} =
async: (raises: [CancelledError]).} =
if r.isOk():
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:
return defaultResponse()
defaultResponse()
for test in TestMessages:
let
@ -1360,12 +1420,15 @@ suite "HTTP server testing suite":
TestRequest = "GET /httpdebug HTTP/1.1\r\nConnection: keep-alive\r\n\r\n"
proc process(r: RequestFence): Future[HttpResponseRef] {.
async: (raises: [CancelledError, HttpResponseError]).} =
async: (raises: [CancelledError]).} =
if r.isOk():
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:
return defaultResponse()
defaultResponse()
proc client(address: TransportAddress,
data: string): Future[StreamTransport] {.async.} =

View File

@ -108,15 +108,18 @@ suite "Secure HTTP server testing suite":
proc testHTTPS(address: TransportAddress): Future[bool] {.async.} =
var serverRes = false
proc process(r: RequestFence): Future[HttpResponseRef] {.
async: (raises: [CancelledError, HttpResponseError]).} =
async: (raises: [CancelledError]).} =
if r.isOk():
let request = r.get()
serverRes = true
return await request.respond(Http200, "TEST_OK:" & $request.meth,
HttpTable.init())
try:
await request.respond(Http200, "TEST_OK:" & $request.meth,
HttpTable.init())
except HttpWriteError as exc:
serverRes = false
defaultResponse(exc)
else:
serverRes = false
return defaultResponse()
defaultResponse()
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
let serverFlags = {Secure}
@ -146,16 +149,18 @@ suite "Secure HTTP server testing suite":
var serverRes = false
var testFut = newFuture[void]()
proc process(r: RequestFence): Future[HttpResponseRef] {.
async: (raises: [CancelledError, HttpResponseError]).} =
async: (raises: [CancelledError]).} =
if r.isOk():
let request = r.get()
serverRes = false
return await request.respond(Http200, "TEST_OK:" & $request.meth,
HttpTable.init())
try:
await request.respond(Http200, "TEST_OK:" & $request.meth,
HttpTable.init())
except HttpWriteError as exc:
defaultResponse(exc)
else:
serverRes = true
testFut.complete()
return defaultResponse()
defaultResponse()
let socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
let serverFlags = {Secure}