2019-05-07 20:11:40 +00:00
|
|
|
# Chronos Test Suite
|
|
|
|
# (c) Copyright 2019-Present
|
|
|
|
# Status Research & Development GmbH
|
|
|
|
#
|
|
|
|
# Licensed under either of
|
|
|
|
# Apache License, version 2.0, (LICENSE-APACHEv2)
|
|
|
|
# MIT license (LICENSE-MIT)
|
exception tracking (#166)
* exception tracking
This PR adds minimal exception tracking to chronos, moving the goalpost
one step further.
In particular, it becomes invalid to raise exceptions from `callSoon`
callbacks: this is critical for writing correct error handling because
there's no reasonable way that a user of chronos can possibly _reason_
about exceptions coming out of there: the event loop will be in an
indeterminite state when the loop is executing an _random_ callback.
As expected, there are several issues in the error handling of chronos:
in particular, it will end up in an inconsistent internal state whenever
the selector loop operations fail, because the internal state update
functions are not written in an exception-safe way. This PR turns this
into a Defect, which probably is not the optimal way of handling things
- expect more work to be done here.
Some API have no way of reporting back errors to callers - for example,
when something fails in the accept loop, there's not much it can do, and
no way to report it back to the user of the API - this has been fixed
with the new accept flow - the old one should be deprecated.
Finally, there is information loss in the API: in composite operations
like `poll` and `waitFor` there's no way to differentiate internal
errors from user-level errors originating from callbacks.
* store `CatchableError` in future
* annotate proc's with correct raises information
* `selectors2` to avoid non-CatchableError IOSelectorsException
* `$` should never raise
* remove unnecessary gcsafe annotations
* fix exceptions leaking out of timer waits
* fix some imports
* functions must signal raising the union of all exceptions across all
platforms to enable cross-platform code
* switch to unittest2
* add `selectors2` which supercedes the std library version and fixes
several exception handling issues in there
* fixes
* docs, platform-independent eh specifiers for some functions
* add feature flag for strict exception mode
also bump version to 3.0.0 - _most_ existing code should be compatible
with this version of exception handling but some things might need
fixing - callbacks, existing raises specifications etc.
* fix AsyncCheck for non-void T
2021-03-24 09:08:33 +00:00
|
|
|
import unittest2
|
2023-02-21 18:38:53 +00:00
|
|
|
import bearssl/[x509]
|
2023-11-13 11:14:21 +00:00
|
|
|
import stew/byteutils
|
2023-07-14 10:35:08 +00:00
|
|
|
import ".."/chronos/unittest2/asynctests
|
|
|
|
import ".."/chronos/streams/[tlsstream, chunkstream, boundstream]
|
2021-02-10 09:04:45 +00:00
|
|
|
|
2023-03-31 05:35:04 +00:00
|
|
|
{.used.}
|
2019-10-24 13:01:57 +00:00
|
|
|
|
2020-10-12 23:12:52 +00:00
|
|
|
# To create self-signed certificate and key you can use openssl
|
|
|
|
# openssl req -new -x509 -sha256 -newkey rsa:2048 -nodes \
|
|
|
|
# -keyout example-com.key.pem -days 3650 -out example-com.cert.pem
|
|
|
|
|
2019-10-16 06:01:52 +00:00
|
|
|
const SelfSignedRsaKey = """
|
|
|
|
-----BEGIN PRIVATE KEY-----
|
2020-10-12 23:12:52 +00:00
|
|
|
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCn7tXGLKMIMzOG
|
|
|
|
tVzUixax1/ftlSLcpEAkZMORuiCCnYjtIJhGZdzRFZC8fBlfAJZpLIAOfX2L2f1J
|
|
|
|
ZuwpwDkOIvNqKMBrl5Mvkl5azPT0rtnjuwrcqN5NFtbmZPKFYvbjex2aXGqjl5MW
|
|
|
|
nQIs/ZA++DVEXmaN9oDxcZsvRMDKfrGQf9iLeoVL47Gx9KpqNqD/JLIn4LpieumV
|
|
|
|
yYidm6ukTOqHRvrWm36y6VvKW4TE97THacULmkeahtTf8zDJbbh4EO+gifgwgJ2W
|
|
|
|
BUS0+5hMcWu8111mXmanlOVlcoW8fH8RmPjL1eK1Z3j3SVHEf7oWZtIVW5gGA0jQ
|
|
|
|
nfA4K51RAgMBAAECggEANZ7/R13tWKrwouy6DWuz/WlWUtgx333atUQvZhKmWs5u
|
|
|
|
cDjeJmxUC7b1FhoSB9GqNT7uTLIpKkSaqZthgRtNnIPwcU890Zz+dEwqMJgNByvl
|
|
|
|
it+oYjjRco/+YmaNQaYN6yjelPE5Y678WlYb4b29Fz4t0/zIhj/VgEKkKH2tiXpS
|
|
|
|
TIicoM7pSOscEUfaW3yp5bS5QwNU6/AaF1wws0feBACd19ZkcdPvr52jopbhxlXw
|
|
|
|
h3XTV/vXIJd5zWGp0h/Jbd4xcD4MVo2GjfkeORKY6SjDaNzt8OGtePcKnnbUVu8b
|
|
|
|
2XlDxukhDQXqJ3g0sHz47mhvo4JeIM+FgymRm+3QmQKBgQDTawrEA3Zy9WvucaC7
|
|
|
|
Zah02oE9nuvpF12lZ7WJh7+tZ/1ss+Fm7YspEKaUiEk7nn1CAVFtem4X4YCXTBiC
|
|
|
|
Oqq/o+ipv1yTur0ae6m4pwLm5wcMWBh3H5zjfQTfrClNN8yjWv8u3/sq8KesHPnT
|
|
|
|
R92/sMAptAChPgTzQphWbxFiYwKBgQDLWFaBqXfZYVnTyUvKX8GorS6jGWc6Eh4l
|
|
|
|
lAFA+2EBWDICrUxsDPoZjEXrWCixdqLhyehaI3KEFIx2bcPv6X2c7yx3IG5lA/Gx
|
|
|
|
TZiKlY74c6jOTstkdLW9RJbg1VUHUVZMf/Owt802YmEfUI5S5v7jFmKW6VG+io+K
|
|
|
|
+5KYeHD1uwKBgQDMf53KPA82422jFwYCPjLT1QduM2q97HwIomhWv5gIg63+l4BP
|
|
|
|
rzYMYq6+vZUYthUy41OAMgyLzPQ1ZMXQMi83b7R9fTxvKRIBq9xfYCzObGnE5vHD
|
|
|
|
SDDZWvR75muM5Yxr9nkfPkgVIPMO6Hg+hiVYZf96V0LEtNjU9HWmJYkLQQKBgQCQ
|
|
|
|
ULGUdGHKtXy7AjH3/t3CiKaAupa4cANVSCVbqQy/l4hmvfdu+AbH+vXkgTzgNgKD
|
|
|
|
nHh7AI1Vj//gTSayLlQn/Nbh9PJkXtg5rYiFUn+VdQBo6yMOuIYDPZqXFtCx0Nge
|
|
|
|
kvCwisHpxwiG4PUhgS+Em259DDonsM8PJFx2OYRx4QKBgEQpGhg71Oi9MhPJshN7
|
|
|
|
dYTowaMS5eLTk2264ARaY+hAIV7fgvUa+5bgTVaWL+Cfs33hi4sMRqlEwsmfds2T
|
|
|
|
cnQiJ4cU20Euldfwa5FLnk6LaWdOyzYt/ICBJnKFRwfCUbS4Bu5rtMEM+3t0wxnJ
|
|
|
|
IgaD04WhoL9EX0Qo3DC1+0kG
|
2019-10-16 06:01:52 +00:00
|
|
|
-----END PRIVATE KEY-----
|
|
|
|
"""
|
|
|
|
|
2020-10-12 23:12:52 +00:00
|
|
|
# This SSL certificate will expire 13 October 2030.
|
2019-10-16 06:01:52 +00:00
|
|
|
const SelfSignedRsaCert = """
|
|
|
|
-----BEGIN CERTIFICATE-----
|
2020-10-12 23:12:52 +00:00
|
|
|
MIIDnzCCAoegAwIBAgIUUdcusjDd3XQi3FPM8urdFG3qI+8wDQYJKoZIhvcNAQEL
|
|
|
|
BQAwXzELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
|
|
|
|
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEYMBYGA1UEAwwPMTI3LjAuMC4xOjQz
|
|
|
|
ODA4MB4XDTIwMTAxMjIxNDUwMVoXDTMwMTAxMDIxNDUwMVowXzELMAkGA1UEBhMC
|
|
|
|
QVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdp
|
|
|
|
dHMgUHR5IEx0ZDEYMBYGA1UEAwwPMTI3LjAuMC4xOjQzODA4MIIBIjANBgkqhkiG
|
|
|
|
9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp+7VxiyjCDMzhrVc1IsWsdf37ZUi3KRAJGTD
|
|
|
|
kboggp2I7SCYRmXc0RWQvHwZXwCWaSyADn19i9n9SWbsKcA5DiLzaijAa5eTL5Je
|
|
|
|
Wsz09K7Z47sK3KjeTRbW5mTyhWL243sdmlxqo5eTFp0CLP2QPvg1RF5mjfaA8XGb
|
|
|
|
L0TAyn6xkH/Yi3qFS+OxsfSqajag/ySyJ+C6YnrplcmInZurpEzqh0b61pt+sulb
|
|
|
|
yluExPe0x2nFC5pHmobU3/MwyW24eBDvoIn4MICdlgVEtPuYTHFrvNddZl5mp5Tl
|
|
|
|
ZXKFvHx/EZj4y9XitWd490lRxH+6FmbSFVuYBgNI0J3wOCudUQIDAQABo1MwUTAd
|
|
|
|
BgNVHQ4EFgQUBKha84woY5WkFxKw7qx1cONg1H8wHwYDVR0jBBgwFoAUBKha84wo
|
|
|
|
Y5WkFxKw7qx1cONg1H8wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC
|
|
|
|
AQEAHZMYt9Ry+Xj3vTbzpGFQzYQVTJlfJWSN6eWNOivRFQE5io9kOBEe5noa8aLo
|
|
|
|
dLkw6ztxRP2QRJmlhGCO9/HwS17ckrkgZp3EC2LFnzxcBmoZu+owfxOT1KqpO52O
|
|
|
|
IKOl8eVohi1pEicE4dtTJVcpI7VCMovnXUhzx1Ci4Vibns4a6H+BQa19a1JSpifN
|
|
|
|
tO8U5jkjJ8Jprs/VPFhJj2O3di53oDHaYSE5eOrm2ZO14KFHSk9cGcOGmcYkUv8B
|
|
|
|
nV5vnGadH5Lvfxb/BCpuONabeRdOxMt9u9yQ89vNpxFtRdZDCpGKZBCfmUP+5m3m
|
|
|
|
N8r5CwGcIX/XPC3lKazzbZ8baA==
|
2019-10-16 06:01:52 +00:00
|
|
|
-----END CERTIFICATE-----
|
|
|
|
"""
|
|
|
|
|
2023-10-17 12:19:20 +00:00
|
|
|
let SelfSignedTrustAnchors {.importc: "SelfSignedTAs".}: array[1, X509TrustAnchor]
|
|
|
|
{.compile: "testasyncstream.c".}
|
2023-02-21 18:38:53 +00:00
|
|
|
|
2021-04-24 17:32:21 +00:00
|
|
|
proc createBigMessage(message: string, size: int): seq[byte] =
|
|
|
|
var res = newSeq[byte](size)
|
|
|
|
for i in 0 ..< len(res):
|
|
|
|
res[i] = byte(ord(message[i mod len(message)]))
|
|
|
|
res
|
|
|
|
|
2019-05-07 20:11:40 +00:00
|
|
|
suite "AsyncStream test suite":
|
|
|
|
test "AsyncStream(StreamTransport) readExactly() test":
|
2023-06-26 13:28:33 +00:00
|
|
|
proc testReadExactly(): Future[bool] {.async.} =
|
2019-05-07 20:11:40 +00:00
|
|
|
proc serveClient(server: StreamServer,
|
|
|
|
transp: StreamTransport) {.async.} =
|
|
|
|
var wstream = newAsyncStreamWriter(transp)
|
|
|
|
await wstream.write("000000000011111111112222222222")
|
|
|
|
await wstream.finish()
|
|
|
|
await wstream.closeWait()
|
|
|
|
await transp.closeWait()
|
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
|
|
|
|
var buffer = newSeq[byte](10)
|
2023-06-26 13:28:33 +00:00
|
|
|
var server = createStreamServer(initTAddress("127.0.0.1:0"),
|
|
|
|
serveClient, {ReuseAddr})
|
2019-05-07 20:11:40 +00:00
|
|
|
server.start()
|
2023-06-26 13:28:33 +00:00
|
|
|
var transp = await connect(server.localAddress())
|
2019-05-07 20:11:40 +00:00
|
|
|
var rstream = newAsyncStreamReader(transp)
|
|
|
|
await rstream.readExactly(addr buffer[0], 10)
|
2023-11-13 11:14:21 +00:00
|
|
|
check string.fromBytes(buffer) == "0000000000"
|
2019-05-07 20:11:40 +00:00
|
|
|
await rstream.readExactly(addr buffer[0], 10)
|
2023-11-13 11:14:21 +00:00
|
|
|
check string.fromBytes(buffer) == "1111111111"
|
2019-05-07 20:11:40 +00:00
|
|
|
await rstream.readExactly(addr buffer[0], 10)
|
2023-11-13 11:14:21 +00:00
|
|
|
check string.fromBytes(buffer) == "2222222222"
|
2019-05-07 20:11:40 +00:00
|
|
|
await rstream.closeWait()
|
|
|
|
await transp.closeWait()
|
|
|
|
await server.join()
|
|
|
|
result = true
|
2023-06-26 13:28:33 +00:00
|
|
|
check waitFor(testReadExactly()) == true
|
|
|
|
|
2019-05-07 20:11:40 +00:00
|
|
|
test "AsyncStream(StreamTransport) readUntil() test":
|
2023-06-26 13:28:33 +00:00
|
|
|
proc testReadUntil(): Future[bool] {.async.} =
|
2019-05-07 20:11:40 +00:00
|
|
|
proc serveClient(server: StreamServer,
|
|
|
|
transp: StreamTransport) {.async.} =
|
|
|
|
var wstream = newAsyncStreamWriter(transp)
|
|
|
|
await wstream.write("0000000000NNz1111111111NNz2222222222NNz")
|
|
|
|
await wstream.finish()
|
|
|
|
await wstream.closeWait()
|
|
|
|
await transp.closeWait()
|
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
|
|
|
|
var buffer = newSeq[byte](13)
|
|
|
|
var sep = @[byte('N'), byte('N'), byte('z')]
|
2023-06-26 13:28:33 +00:00
|
|
|
var server = createStreamServer(initTAddress("127.0.0.1:0"),
|
|
|
|
serveClient, {ReuseAddr})
|
2019-05-07 20:11:40 +00:00
|
|
|
server.start()
|
2023-06-26 13:28:33 +00:00
|
|
|
var transp = await connect(server.localAddress())
|
2019-05-07 20:11:40 +00:00
|
|
|
var rstream = newAsyncStreamReader(transp)
|
|
|
|
var r1 = await rstream.readUntil(addr buffer[0], len(buffer), sep)
|
|
|
|
check:
|
|
|
|
r1 == 13
|
2023-11-13 11:14:21 +00:00
|
|
|
string.fromBytes(buffer) == "0000000000NNz"
|
2019-05-07 20:11:40 +00:00
|
|
|
var r2 = await rstream.readUntil(addr buffer[0], len(buffer), sep)
|
|
|
|
check:
|
|
|
|
r2 == 13
|
2023-11-13 11:14:21 +00:00
|
|
|
string.fromBytes(buffer) == "1111111111NNz"
|
2019-05-07 20:11:40 +00:00
|
|
|
var r3 = await rstream.readUntil(addr buffer[0], len(buffer), sep)
|
|
|
|
check:
|
|
|
|
r3 == 13
|
2023-11-13 11:14:21 +00:00
|
|
|
string.fromBytes(buffer) == "2222222222NNz"
|
2019-05-07 20:11:40 +00:00
|
|
|
|
|
|
|
await rstream.closeWait()
|
|
|
|
await transp.closeWait()
|
|
|
|
await server.join()
|
|
|
|
result = true
|
2023-06-26 13:28:33 +00:00
|
|
|
check waitFor(testReadUntil()) == true
|
|
|
|
|
2019-05-07 20:11:40 +00:00
|
|
|
test "AsyncStream(StreamTransport) readLine() test":
|
2023-06-26 13:28:33 +00:00
|
|
|
proc testReadLine(): Future[bool] {.async.} =
|
2019-05-07 20:11:40 +00:00
|
|
|
proc serveClient(server: StreamServer,
|
|
|
|
transp: StreamTransport) {.async.} =
|
|
|
|
var wstream = newAsyncStreamWriter(transp)
|
|
|
|
await wstream.write("0000000000\r\n1111111111\r\n2222222222\r\n")
|
|
|
|
await wstream.finish()
|
|
|
|
await wstream.closeWait()
|
|
|
|
await transp.closeWait()
|
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
|
2023-06-26 13:28:33 +00:00
|
|
|
var server = createStreamServer(initTAddress("127.0.0.1:0"),
|
|
|
|
serveClient, {ReuseAddr})
|
2019-05-07 20:11:40 +00:00
|
|
|
server.start()
|
2023-06-26 13:28:33 +00:00
|
|
|
var transp = await connect(server.localAddress())
|
2019-05-07 20:11:40 +00:00
|
|
|
var rstream = newAsyncStreamReader(transp)
|
|
|
|
var r1 = await rstream.readLine()
|
|
|
|
check r1 == "0000000000"
|
|
|
|
var r2 = await rstream.readLine()
|
|
|
|
check r2 == "1111111111"
|
|
|
|
var r3 = await rstream.readLine()
|
|
|
|
check r3 == "2222222222"
|
|
|
|
await rstream.closeWait()
|
|
|
|
await transp.closeWait()
|
|
|
|
await server.join()
|
|
|
|
result = true
|
2023-06-26 13:28:33 +00:00
|
|
|
check waitFor(testReadLine()) == true
|
|
|
|
|
2019-05-07 20:11:40 +00:00
|
|
|
test "AsyncStream(StreamTransport) read() test":
|
2023-06-26 13:28:33 +00:00
|
|
|
proc testRead(): Future[bool] {.async.} =
|
2019-05-07 20:11:40 +00:00
|
|
|
proc serveClient(server: StreamServer,
|
|
|
|
transp: StreamTransport) {.async.} =
|
|
|
|
var wstream = newAsyncStreamWriter(transp)
|
|
|
|
await wstream.write("000000000011111111112222222222")
|
|
|
|
await wstream.finish()
|
|
|
|
await wstream.closeWait()
|
|
|
|
await transp.closeWait()
|
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
|
2023-06-26 13:28:33 +00:00
|
|
|
var server = createStreamServer(initTAddress("127.0.0.1:0"),
|
|
|
|
serveClient, {ReuseAddr})
|
2019-05-07 20:11:40 +00:00
|
|
|
server.start()
|
2023-06-26 13:28:33 +00:00
|
|
|
var transp = await connect(server.localAddress())
|
2019-05-07 20:11:40 +00:00
|
|
|
var rstream = newAsyncStreamReader(transp)
|
|
|
|
var buf1 = await rstream.read(10)
|
2023-11-13 11:14:21 +00:00
|
|
|
check string.fromBytes(buf1) == "0000000000"
|
2019-05-07 20:11:40 +00:00
|
|
|
var buf2 = await rstream.read()
|
2023-11-13 11:14:21 +00:00
|
|
|
check string.fromBytes(buf2) == "11111111112222222222"
|
2019-05-07 20:11:40 +00:00
|
|
|
await rstream.closeWait()
|
|
|
|
await transp.closeWait()
|
|
|
|
await server.join()
|
|
|
|
result = true
|
2023-06-26 13:28:33 +00:00
|
|
|
check waitFor(testRead()) == true
|
|
|
|
|
2019-05-07 20:11:40 +00:00
|
|
|
test "AsyncStream(StreamTransport) consume() test":
|
2023-06-26 13:28:33 +00:00
|
|
|
proc testConsume(): Future[bool] {.async.} =
|
2019-05-07 20:11:40 +00:00
|
|
|
proc serveClient(server: StreamServer,
|
|
|
|
transp: StreamTransport) {.async.} =
|
|
|
|
var wstream = newAsyncStreamWriter(transp)
|
|
|
|
await wstream.write("0000000000111111111122222222223333333333")
|
|
|
|
await wstream.finish()
|
|
|
|
await wstream.closeWait()
|
|
|
|
await transp.closeWait()
|
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
|
2023-06-26 13:28:33 +00:00
|
|
|
var server = createStreamServer(initTAddress("127.0.0.1:0"),
|
|
|
|
serveClient, {ReuseAddr})
|
2019-05-07 20:11:40 +00:00
|
|
|
server.start()
|
2023-06-26 13:28:33 +00:00
|
|
|
var transp = await connect(server.localAddress())
|
2019-05-07 20:11:40 +00:00
|
|
|
var rstream = newAsyncStreamReader(transp)
|
|
|
|
var res1 = await rstream.consume(10)
|
|
|
|
check:
|
|
|
|
res1 == 10
|
|
|
|
var buf1 = await rstream.read(10)
|
2023-11-13 11:14:21 +00:00
|
|
|
check string.fromBytes(buf1) == "1111111111"
|
2019-05-07 20:11:40 +00:00
|
|
|
var res2 = await rstream.consume(10)
|
|
|
|
check:
|
|
|
|
res2 == 10
|
|
|
|
var buf2 = await rstream.read(10)
|
2023-11-13 11:14:21 +00:00
|
|
|
check string.fromBytes(buf2) == "3333333333"
|
2019-05-07 20:11:40 +00:00
|
|
|
await rstream.closeWait()
|
|
|
|
await transp.closeWait()
|
|
|
|
await server.join()
|
|
|
|
result = true
|
2023-06-26 13:28:33 +00:00
|
|
|
check waitFor(testConsume()) == true
|
|
|
|
|
2019-05-07 20:11:40 +00:00
|
|
|
test "AsyncStream(StreamTransport) leaks test":
|
2023-07-14 10:35:08 +00:00
|
|
|
checkLeaks()
|
2019-05-07 20:11:40 +00:00
|
|
|
|
|
|
|
test "AsyncStream(AsyncStream) readExactly() test":
|
2023-06-26 13:28:33 +00:00
|
|
|
proc testReadExactly2(): Future[bool] {.async.} =
|
2019-05-07 20:11:40 +00:00
|
|
|
proc serveClient(server: StreamServer,
|
|
|
|
transp: StreamTransport) {.async.} =
|
|
|
|
var wstream = newAsyncStreamWriter(transp)
|
|
|
|
var wstream2 = newChunkedStreamWriter(wstream)
|
|
|
|
var s1 = "00000"
|
|
|
|
var s2 = "11111"
|
|
|
|
var s3 = "22222"
|
|
|
|
await wstream2.write("00000")
|
|
|
|
await wstream2.write(addr s1[0], len(s1))
|
|
|
|
await wstream2.write("11111")
|
2023-11-13 11:14:21 +00:00
|
|
|
await wstream2.write(s2.toBytes())
|
2019-05-07 20:11:40 +00:00
|
|
|
await wstream2.write("22222")
|
|
|
|
await wstream2.write(addr s3[0], len(s3))
|
|
|
|
|
|
|
|
await wstream2.finish()
|
|
|
|
await wstream.finish()
|
|
|
|
await wstream2.closeWait()
|
|
|
|
await wstream.closeWait()
|
|
|
|
await transp.closeWait()
|
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
|
|
|
|
var buffer = newSeq[byte](10)
|
2023-06-26 13:28:33 +00:00
|
|
|
var server = createStreamServer(initTAddress("127.0.0.1:0"),
|
|
|
|
serveClient, {ReuseAddr})
|
2019-05-07 20:11:40 +00:00
|
|
|
server.start()
|
2023-06-26 13:28:33 +00:00
|
|
|
var transp = await connect(server.localAddress())
|
2019-05-07 20:11:40 +00:00
|
|
|
var rstream = newAsyncStreamReader(transp)
|
|
|
|
var rstream2 = newChunkedStreamReader(rstream)
|
|
|
|
await rstream2.readExactly(addr buffer[0], 10)
|
2023-11-13 11:14:21 +00:00
|
|
|
check string.fromBytes(buffer) == "0000000000"
|
2019-05-07 20:11:40 +00:00
|
|
|
await rstream2.readExactly(addr buffer[0], 10)
|
2023-11-13 11:14:21 +00:00
|
|
|
check string.fromBytes(buffer) == "1111111111"
|
2019-05-07 20:11:40 +00:00
|
|
|
await rstream2.readExactly(addr buffer[0], 10)
|
2023-11-13 11:14:21 +00:00
|
|
|
check string.fromBytes(buffer) == "2222222222"
|
2019-05-08 09:44:00 +00:00
|
|
|
|
|
|
|
# We need to consume all the stream with finish markers, but there will
|
|
|
|
# be no actual data.
|
|
|
|
let left = await rstream2.consume()
|
|
|
|
check:
|
|
|
|
left == 0
|
|
|
|
rstream2.atEof() == true
|
|
|
|
|
2019-05-07 20:11:40 +00:00
|
|
|
await rstream2.closeWait()
|
|
|
|
await rstream.closeWait()
|
|
|
|
await transp.closeWait()
|
|
|
|
await server.join()
|
|
|
|
result = true
|
2023-06-26 13:28:33 +00:00
|
|
|
check waitFor(testReadExactly2()) == true
|
|
|
|
|
2019-05-07 20:11:40 +00:00
|
|
|
test "AsyncStream(AsyncStream) readUntil() test":
|
2023-06-26 13:28:33 +00:00
|
|
|
proc testReadUntil2(): Future[bool] {.async.} =
|
2019-05-07 20:11:40 +00:00
|
|
|
proc serveClient(server: StreamServer,
|
|
|
|
transp: StreamTransport) {.async.} =
|
|
|
|
var wstream = newAsyncStreamWriter(transp)
|
|
|
|
var wstream2 = newChunkedStreamWriter(wstream)
|
|
|
|
var s1 = "00000NNz"
|
|
|
|
var s2 = "11111NNz"
|
|
|
|
var s3 = "22222NNz"
|
|
|
|
await wstream2.write("00000")
|
|
|
|
await wstream2.write(addr s1[0], len(s1))
|
|
|
|
await wstream2.write("11111")
|
|
|
|
await wstream2.write(s2)
|
|
|
|
await wstream2.write("22222")
|
2023-11-13 11:14:21 +00:00
|
|
|
await wstream2.write(s3.toBytes())
|
2019-05-07 20:11:40 +00:00
|
|
|
await wstream2.finish()
|
|
|
|
await wstream.finish()
|
|
|
|
await wstream2.closeWait()
|
|
|
|
await wstream.closeWait()
|
|
|
|
await transp.closeWait()
|
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
|
|
|
|
var buffer = newSeq[byte](13)
|
|
|
|
var sep = @[byte('N'), byte('N'), byte('z')]
|
2023-06-26 13:28:33 +00:00
|
|
|
var server = createStreamServer(initTAddress("127.0.0.1:0"),
|
|
|
|
serveClient, {ReuseAddr})
|
2019-05-07 20:11:40 +00:00
|
|
|
server.start()
|
2023-06-26 13:28:33 +00:00
|
|
|
var transp = await connect(server.localAddress())
|
2019-05-07 20:11:40 +00:00
|
|
|
var rstream = newAsyncStreamReader(transp)
|
|
|
|
var rstream2 = newChunkedStreamReader(rstream)
|
|
|
|
|
|
|
|
var r1 = await rstream2.readUntil(addr buffer[0], len(buffer), sep)
|
|
|
|
check:
|
|
|
|
r1 == 13
|
2023-11-13 11:14:21 +00:00
|
|
|
string.fromBytes(buffer) == "0000000000NNz"
|
2019-05-07 20:11:40 +00:00
|
|
|
var r2 = await rstream2.readUntil(addr buffer[0], len(buffer), sep)
|
|
|
|
check:
|
|
|
|
r2 == 13
|
2023-11-13 11:14:21 +00:00
|
|
|
string.fromBytes(buffer) == "1111111111NNz"
|
2019-05-07 20:11:40 +00:00
|
|
|
var r3 = await rstream2.readUntil(addr buffer[0], len(buffer), sep)
|
|
|
|
check:
|
|
|
|
r3 == 13
|
2023-11-13 11:14:21 +00:00
|
|
|
string.fromBytes(buffer) == "2222222222NNz"
|
2019-05-08 09:44:00 +00:00
|
|
|
|
|
|
|
# We need to consume all the stream with finish markers, but there will
|
|
|
|
# be no actual data.
|
|
|
|
let left = await rstream2.consume()
|
|
|
|
check:
|
|
|
|
left == 0
|
|
|
|
rstream2.atEof() == true
|
|
|
|
|
2019-05-07 20:11:40 +00:00
|
|
|
await rstream2.closeWait()
|
|
|
|
await rstream.closeWait()
|
|
|
|
await transp.closeWait()
|
|
|
|
await server.join()
|
|
|
|
result = true
|
2023-06-26 13:28:33 +00:00
|
|
|
check waitFor(testReadUntil2()) == true
|
|
|
|
|
2019-05-07 20:11:40 +00:00
|
|
|
test "AsyncStream(AsyncStream) readLine() test":
|
2023-06-26 13:28:33 +00:00
|
|
|
proc testReadLine2(): Future[bool] {.async.} =
|
2019-05-07 20:11:40 +00:00
|
|
|
proc serveClient(server: StreamServer,
|
|
|
|
transp: StreamTransport) {.async.} =
|
|
|
|
var wstream = newAsyncStreamWriter(transp)
|
|
|
|
var wstream2 = newChunkedStreamWriter(wstream)
|
|
|
|
await wstream2.write("00000")
|
|
|
|
await wstream2.write("00000\r\n")
|
|
|
|
await wstream2.write("11111")
|
|
|
|
await wstream2.write("11111\r\n")
|
|
|
|
await wstream2.write("22222")
|
|
|
|
await wstream2.write("22222\r\n")
|
|
|
|
await wstream2.finish()
|
|
|
|
await wstream.finish()
|
|
|
|
await wstream2.closeWait()
|
|
|
|
await wstream.closeWait()
|
|
|
|
await transp.closeWait()
|
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
|
2023-06-26 13:28:33 +00:00
|
|
|
var server = createStreamServer(initTAddress("127.0.0.1:0"),
|
|
|
|
serveClient, {ReuseAddr})
|
2019-05-07 20:11:40 +00:00
|
|
|
server.start()
|
2023-06-26 13:28:33 +00:00
|
|
|
var transp = await connect(server.localAddress())
|
2019-05-07 20:11:40 +00:00
|
|
|
var rstream = newAsyncStreamReader(transp)
|
|
|
|
var rstream2 = newChunkedStreamReader(rstream)
|
|
|
|
var r1 = await rstream2.readLine()
|
|
|
|
check r1 == "0000000000"
|
|
|
|
var r2 = await rstream2.readLine()
|
|
|
|
check r2 == "1111111111"
|
|
|
|
var r3 = await rstream2.readLine()
|
|
|
|
check r3 == "2222222222"
|
2019-05-08 09:44:00 +00:00
|
|
|
|
|
|
|
# We need to consume all the stream with finish markers, but there will
|
|
|
|
# be no actual data.
|
|
|
|
let left = await rstream2.consume()
|
|
|
|
check:
|
|
|
|
left == 0
|
|
|
|
rstream2.atEof() == true
|
|
|
|
|
2019-05-07 20:11:40 +00:00
|
|
|
await rstream2.closeWait()
|
|
|
|
await rstream.closeWait()
|
|
|
|
await transp.closeWait()
|
|
|
|
await server.join()
|
|
|
|
result = true
|
2023-06-26 13:28:33 +00:00
|
|
|
check waitFor(testReadLine2()) == true
|
|
|
|
|
2019-05-07 20:11:40 +00:00
|
|
|
test "AsyncStream(AsyncStream) read() test":
|
2023-06-26 13:28:33 +00:00
|
|
|
proc testRead2(): Future[bool] {.async.} =
|
2019-05-07 20:11:40 +00:00
|
|
|
proc serveClient(server: StreamServer,
|
|
|
|
transp: StreamTransport) {.async.} =
|
|
|
|
var wstream = newAsyncStreamWriter(transp)
|
|
|
|
var wstream2 = newChunkedStreamWriter(wstream)
|
|
|
|
var s2 = "1111111111"
|
|
|
|
var s3 = "2222222222"
|
|
|
|
await wstream2.write("0000000000")
|
|
|
|
await wstream2.write(s2)
|
2023-11-13 11:14:21 +00:00
|
|
|
await wstream2.write(s3.toBytes())
|
2019-05-07 20:11:40 +00:00
|
|
|
await wstream2.finish()
|
|
|
|
await wstream.finish()
|
|
|
|
await wstream2.closeWait()
|
|
|
|
await wstream.closeWait()
|
|
|
|
await transp.closeWait()
|
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
|
2023-06-26 13:28:33 +00:00
|
|
|
var server = createStreamServer(initTAddress("127.0.0.1:0"),
|
|
|
|
serveClient, {ReuseAddr})
|
2019-05-07 20:11:40 +00:00
|
|
|
server.start()
|
2023-06-26 13:28:33 +00:00
|
|
|
var transp = await connect(server.localAddress())
|
2019-05-07 20:11:40 +00:00
|
|
|
var rstream = newAsyncStreamReader(transp)
|
|
|
|
var rstream2 = newChunkedStreamReader(rstream)
|
|
|
|
var buf1 = await rstream2.read(10)
|
2023-11-13 11:14:21 +00:00
|
|
|
check string.fromBytes(buf1) == "0000000000"
|
2019-05-07 20:11:40 +00:00
|
|
|
var buf2 = await rstream2.read()
|
2023-11-13 11:14:21 +00:00
|
|
|
check string.fromBytes(buf2) == "11111111112222222222"
|
2019-05-08 09:44:00 +00:00
|
|
|
|
|
|
|
# read() call will consume all the bytes and finish markers too, so
|
|
|
|
# we just check stream for EOF.
|
|
|
|
check rstream2.atEof() == true
|
|
|
|
|
2019-05-07 20:11:40 +00:00
|
|
|
await rstream2.closeWait()
|
|
|
|
await rstream.closeWait()
|
|
|
|
await transp.closeWait()
|
|
|
|
await server.join()
|
|
|
|
result = true
|
2023-06-26 13:28:33 +00:00
|
|
|
check waitFor(testRead2()) == true
|
|
|
|
|
2019-05-07 20:11:40 +00:00
|
|
|
test "AsyncStream(AsyncStream) consume() test":
|
2023-06-26 13:28:33 +00:00
|
|
|
proc testConsume2(): Future[bool] {.async.} =
|
2019-05-07 20:11:40 +00:00
|
|
|
proc serveClient(server: StreamServer,
|
|
|
|
transp: StreamTransport) {.async.} =
|
|
|
|
const
|
|
|
|
S4 = @[byte('3'), byte('3'), byte('3'), byte('3'), byte('3')]
|
|
|
|
var wstream = newAsyncStreamWriter(transp)
|
|
|
|
var wstream2 = newChunkedStreamWriter(wstream)
|
|
|
|
|
|
|
|
var s1 = "00000"
|
2023-11-13 11:14:21 +00:00
|
|
|
var s2 = "11111".toBytes()
|
2019-05-07 20:11:40 +00:00
|
|
|
var s3 = "22222"
|
|
|
|
|
|
|
|
await wstream2.write("00000")
|
|
|
|
await wstream2.write(s1)
|
|
|
|
await wstream2.write("11111")
|
|
|
|
await wstream2.write(s2)
|
|
|
|
await wstream2.write("22222")
|
|
|
|
await wstream2.write(addr s3[0], len(s3))
|
|
|
|
await wstream2.write("33333")
|
|
|
|
await wstream2.write(S4)
|
|
|
|
await wstream2.finish()
|
|
|
|
await wstream.finish()
|
|
|
|
await wstream2.closeWait()
|
|
|
|
await wstream.closeWait()
|
|
|
|
await transp.closeWait()
|
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
|
2023-06-26 13:28:33 +00:00
|
|
|
var server = createStreamServer(initTAddress("127.0.0.1:0"),
|
|
|
|
serveClient, {ReuseAddr})
|
2019-05-07 20:11:40 +00:00
|
|
|
server.start()
|
2023-06-26 13:28:33 +00:00
|
|
|
var transp = await connect(server.localAddress())
|
2019-05-07 20:11:40 +00:00
|
|
|
var rstream = newAsyncStreamReader(transp)
|
|
|
|
var rstream2 = newChunkedStreamReader(rstream)
|
|
|
|
|
|
|
|
var res1 = await rstream2.consume(10)
|
|
|
|
check:
|
|
|
|
res1 == 10
|
|
|
|
var buf1 = await rstream2.read(10)
|
2023-11-13 11:14:21 +00:00
|
|
|
check string.fromBytes(buf1) == "1111111111"
|
2019-05-07 20:11:40 +00:00
|
|
|
var res2 = await rstream2.consume(10)
|
|
|
|
check:
|
|
|
|
res2 == 10
|
|
|
|
var buf2 = await rstream2.read(10)
|
2023-11-13 11:14:21 +00:00
|
|
|
check string.fromBytes(buf2) == "3333333333"
|
2019-05-08 09:44:00 +00:00
|
|
|
|
|
|
|
# We need to consume all the stream with finish markers, but there will
|
|
|
|
# be no actual data.
|
|
|
|
let left = await rstream2.consume()
|
|
|
|
check:
|
|
|
|
left == 0
|
|
|
|
rstream2.atEof() == true
|
|
|
|
|
2019-05-07 20:11:40 +00:00
|
|
|
await rstream2.closeWait()
|
|
|
|
await rstream.closeWait()
|
|
|
|
await transp.closeWait()
|
|
|
|
await server.join()
|
|
|
|
result = true
|
2023-06-26 13:28:33 +00:00
|
|
|
check waitFor(testConsume2()) == true
|
|
|
|
|
2023-01-10 16:08:54 +00:00
|
|
|
test "AsyncStream(AsyncStream) write(eof) test":
|
2023-06-26 13:28:33 +00:00
|
|
|
proc testWriteEof(): Future[bool] {.async.} =
|
2023-01-10 16:08:54 +00:00
|
|
|
let
|
|
|
|
size = 10240
|
|
|
|
message = createBigMessage("ABCDEFGHIJKLMNOP", size)
|
|
|
|
|
|
|
|
proc processClient(server: StreamServer,
|
|
|
|
transp: StreamTransport) {.async.} =
|
|
|
|
var wstream = newAsyncStreamWriter(transp)
|
|
|
|
var wbstream = newBoundedStreamWriter(wstream, uint64(size))
|
|
|
|
try:
|
|
|
|
check wbstream.atEof() == false
|
|
|
|
await wbstream.write(message)
|
|
|
|
check wbstream.atEof() == false
|
|
|
|
await wbstream.finish()
|
|
|
|
check wbstream.atEof() == true
|
|
|
|
expect AsyncStreamWriteEOFError:
|
|
|
|
await wbstream.write(message)
|
|
|
|
expect AsyncStreamWriteEOFError:
|
|
|
|
await wbstream.write(message)
|
|
|
|
expect AsyncStreamWriteEOFError:
|
|
|
|
await wbstream.write(message)
|
|
|
|
check wbstream.atEof() == true
|
|
|
|
await wbstream.closeWait()
|
|
|
|
check wbstream.atEof() == true
|
|
|
|
finally:
|
|
|
|
await wstream.closeWait()
|
|
|
|
await transp.closeWait()
|
|
|
|
|
|
|
|
let flags = {ServerFlags.ReuseAddr, ServerFlags.TcpNoDelay}
|
2023-06-26 13:28:33 +00:00
|
|
|
var server = createStreamServer(initTAddress("127.0.0.1:0"),
|
|
|
|
processClient, flags = flags)
|
2023-01-10 16:08:54 +00:00
|
|
|
server.start()
|
|
|
|
var conn = await connect(server.localAddress())
|
|
|
|
try:
|
|
|
|
discard await conn.consume()
|
|
|
|
finally:
|
|
|
|
await conn.closeWait()
|
|
|
|
server.stop()
|
|
|
|
await server.closeWait()
|
|
|
|
return true
|
|
|
|
|
2023-06-26 13:28:33 +00:00
|
|
|
check waitFor(testWriteEof()) == true
|
|
|
|
|
2019-05-07 20:11:40 +00:00
|
|
|
test "AsyncStream(AsyncStream) leaks test":
|
2023-07-14 10:35:08 +00:00
|
|
|
checkLeaks()
|
2019-05-07 20:11:40 +00:00
|
|
|
|
|
|
|
suite "ChunkedStream test suite":
|
|
|
|
test "ChunkedStream test vectors":
|
|
|
|
const ChunkedVectors = [
|
|
|
|
["4\r\nWiki\r\n5\r\npedia\r\nE\r\n in\r\n\r\nchunks.\r\n0\r\n\r\n",
|
|
|
|
"Wikipedia in\r\n\r\nchunks."],
|
|
|
|
["4\r\nWiki\r\n5\r\npedia\r\nE\r\n in\r\n\r\nchunks.\r\n0\r\n\r\n0\r\n\r\n",
|
|
|
|
"Wikipedia in\r\n\r\nchunks."],
|
2021-02-10 08:43:05 +00:00
|
|
|
["3b\r\n--f98f0\r\nContent-Disposition: form-data; name=\"key1\"" &
|
|
|
|
"\r\n\r\nA\r\n\r\n" &
|
|
|
|
"3b\r\n--f98f0\r\nContent-Disposition: form-data; name=\"key2\"" &
|
|
|
|
"\r\n\r\nB\r\n\r\n" &
|
|
|
|
"3b\r\n--f98f0\r\nContent-Disposition: form-data; name=\"key3\"" &
|
|
|
|
"\r\n\r\nC\r\n\r\n" &
|
|
|
|
"b\r\n--f98f0--\r\n\r\n" &
|
|
|
|
"0\r\n\r\n",
|
|
|
|
"--f98f0\r\nContent-Disposition: form-data; name=\"key1\"" &
|
|
|
|
"\r\n\r\nA\r\n" &
|
|
|
|
"--f98f0\r\nContent-Disposition: form-data; name=\"key2\"" &
|
|
|
|
"\r\n\r\nB\r\n" &
|
|
|
|
"--f98f0\r\nContent-Disposition: form-data; name=\"key3\"" &
|
|
|
|
"\r\n\r\nC\r\n" &
|
|
|
|
"--f98f0--\r\n"
|
2021-02-18 12:08:21 +00:00
|
|
|
],
|
|
|
|
["4;position=1\r\nWiki\r\n5;position=2\r\npedia\r\nE;position=3\r\n" &
|
|
|
|
" in\r\n\r\nchunks.\r\n0;position=4\r\n\r\n",
|
|
|
|
"Wikipedia in\r\n\r\nchunks."],
|
2019-05-07 20:11:40 +00:00
|
|
|
]
|
2023-06-26 13:28:33 +00:00
|
|
|
proc checkVector(inputstr: string): Future[string] {.async.} =
|
2019-05-07 20:11:40 +00:00
|
|
|
proc serveClient(server: StreamServer,
|
|
|
|
transp: StreamTransport) {.async.} =
|
|
|
|
var wstream = newAsyncStreamWriter(transp)
|
|
|
|
var data = inputstr
|
|
|
|
await wstream.write(data)
|
|
|
|
await wstream.finish()
|
|
|
|
await wstream.closeWait()
|
|
|
|
await transp.closeWait()
|
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
|
2023-06-26 13:28:33 +00:00
|
|
|
var server = createStreamServer(initTAddress("127.0.0.1:0"),
|
|
|
|
serveClient, {ReuseAddr})
|
2019-05-07 20:11:40 +00:00
|
|
|
server.start()
|
2023-06-26 13:28:33 +00:00
|
|
|
var transp = await connect(server.localAddress())
|
2019-05-07 20:11:40 +00:00
|
|
|
var rstream = newAsyncStreamReader(transp)
|
|
|
|
var rstream2 = newChunkedStreamReader(rstream)
|
|
|
|
var res = await rstream2.read()
|
2023-11-13 11:14:21 +00:00
|
|
|
var ress = string.fromBytes(res)
|
2019-05-07 20:11:40 +00:00
|
|
|
await rstream2.closeWait()
|
|
|
|
await rstream.closeWait()
|
|
|
|
await transp.closeWait()
|
|
|
|
await server.join()
|
|
|
|
result = ress
|
|
|
|
|
2023-06-26 13:28:33 +00:00
|
|
|
proc testVectors(): Future[bool] {.async.} =
|
2019-05-07 20:11:40 +00:00
|
|
|
var res = true
|
|
|
|
for i in 0..<len(ChunkedVectors):
|
2023-06-26 13:28:33 +00:00
|
|
|
var r = await checkVector(ChunkedVectors[i][0])
|
2019-05-07 20:11:40 +00:00
|
|
|
if r != ChunkedVectors[i][1]:
|
|
|
|
res = false
|
|
|
|
break
|
|
|
|
result = res
|
2023-06-26 13:28:33 +00:00
|
|
|
check waitFor(testVectors()) == true
|
|
|
|
|
2019-05-07 20:11:40 +00:00
|
|
|
test "ChunkedStream incorrect chunk test":
|
|
|
|
const BadVectors = [
|
2021-02-18 12:08:21 +00:00
|
|
|
["10000000;\r\n1"],
|
|
|
|
["10000000\r\n1"],
|
|
|
|
["FFFFFFFF;extension1=value1;extension2=value2\r\n1"],
|
|
|
|
["FFFFFFFF\r\n1"],
|
|
|
|
["100000000\r\n1"],
|
|
|
|
["10000000 \r\n1"],
|
|
|
|
["100000000 ;\r\n"],
|
|
|
|
["FFFFFFFF0\r\n1"],
|
|
|
|
["FFFFFFFF \r\n1"],
|
|
|
|
["FFFFFFFF ;\r\n1"],
|
2019-05-07 20:11:40 +00:00
|
|
|
["z\r\n1"]
|
|
|
|
]
|
2023-06-26 13:28:33 +00:00
|
|
|
proc checkVector(inputstr: string): Future[bool] {.async.} =
|
2019-05-07 20:11:40 +00:00
|
|
|
proc serveClient(server: StreamServer,
|
|
|
|
transp: StreamTransport) {.async.} =
|
|
|
|
var wstream = newAsyncStreamWriter(transp)
|
|
|
|
var data = inputstr
|
|
|
|
await wstream.write(data)
|
|
|
|
await wstream.finish()
|
|
|
|
await wstream.closeWait()
|
|
|
|
await transp.closeWait()
|
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
|
|
|
|
var res = false
|
2023-06-26 13:28:33 +00:00
|
|
|
var server = createStreamServer(initTAddress("127.0.0.1:0"),
|
|
|
|
serveClient, {ReuseAddr})
|
2019-05-07 20:11:40 +00:00
|
|
|
server.start()
|
2023-06-26 13:28:33 +00:00
|
|
|
var transp = await connect(server.localAddress())
|
2019-05-07 20:11:40 +00:00
|
|
|
var rstream = newAsyncStreamReader(transp)
|
|
|
|
var rstream2 = newChunkedStreamReader(rstream)
|
|
|
|
try:
|
|
|
|
var r = await rstream2.read()
|
2019-10-29 21:19:41 +00:00
|
|
|
doAssert(len(r) > 0)
|
2021-01-20 13:40:15 +00:00
|
|
|
except ChunkedStreamIncompleteError:
|
2021-02-18 12:08:21 +00:00
|
|
|
case inputstr
|
|
|
|
of "10000000;\r\n1":
|
|
|
|
res = true
|
|
|
|
of "10000000\r\n1":
|
|
|
|
res = true
|
|
|
|
of "FFFFFFFF;extension1=value1;extension2=value2\r\n1":
|
|
|
|
res = true
|
|
|
|
of "FFFFFFFF\r\n1":
|
2021-01-20 13:40:15 +00:00
|
|
|
res = true
|
2021-02-18 12:08:21 +00:00
|
|
|
else:
|
|
|
|
res = false
|
2021-01-20 13:40:15 +00:00
|
|
|
except ChunkedStreamProtocolError:
|
2021-02-18 12:08:21 +00:00
|
|
|
case inputstr
|
|
|
|
of "100000000\r\n1":
|
|
|
|
res = true
|
|
|
|
of "10000000 \r\n1":
|
|
|
|
res = true
|
|
|
|
of "100000000 ;\r\n":
|
2021-01-20 13:40:15 +00:00
|
|
|
res = true
|
2021-02-18 12:08:21 +00:00
|
|
|
of "z\r\n1":
|
|
|
|
res = true
|
|
|
|
of "FFFFFFFF0\r\n1":
|
|
|
|
res = true
|
|
|
|
of "FFFFFFFF \r\n1":
|
|
|
|
res = true
|
|
|
|
of "FFFFFFFF ;\r\n1":
|
|
|
|
res = true
|
|
|
|
else:
|
|
|
|
res = false
|
|
|
|
|
2019-05-07 20:11:40 +00:00
|
|
|
await rstream2.closeWait()
|
|
|
|
await rstream.closeWait()
|
|
|
|
await transp.closeWait()
|
|
|
|
await server.join()
|
|
|
|
result = res
|
|
|
|
|
2023-06-26 13:28:33 +00:00
|
|
|
proc testVectors2(): Future[bool] {.async.} =
|
2019-05-07 20:11:40 +00:00
|
|
|
var res = true
|
|
|
|
for i in 0..<len(BadVectors):
|
2023-06-26 13:28:33 +00:00
|
|
|
var r = await checkVector(BadVectors[i][0])
|
2019-05-07 20:11:40 +00:00
|
|
|
if not(r):
|
|
|
|
res = false
|
|
|
|
break
|
|
|
|
result = res
|
2023-06-26 13:28:33 +00:00
|
|
|
check waitFor(testVectors2()) == true
|
2019-10-08 15:46:27 +00:00
|
|
|
|
2021-02-18 14:39:36 +00:00
|
|
|
test "ChunkedStream hex decoding test":
|
|
|
|
for i in 0 ..< 256:
|
|
|
|
let ch = char(i)
|
|
|
|
case ch
|
|
|
|
of '0' .. '9':
|
|
|
|
check hexValue(byte(ch)) == ord(ch) - ord('0')
|
|
|
|
of 'a' .. 'f':
|
|
|
|
check hexValue(byte(ch)) == ord(ch) - ord('a') + 10
|
|
|
|
of 'A' .. 'F':
|
|
|
|
check hexValue(byte(ch)) == ord(ch) - ord('A') + 10
|
|
|
|
else:
|
|
|
|
check hexValue(byte(ch)) == -1
|
|
|
|
|
2021-04-22 12:32:28 +00:00
|
|
|
test "ChunkedStream too big chunk header test":
|
2023-06-26 13:28:33 +00:00
|
|
|
proc checkTooBigChunkHeader(inputstr: seq[byte]): Future[bool] {.async.} =
|
2021-04-22 12:32:28 +00:00
|
|
|
proc serveClient(server: StreamServer,
|
|
|
|
transp: StreamTransport) {.async.} =
|
|
|
|
var wstream = newAsyncStreamWriter(transp)
|
2021-04-24 17:32:21 +00:00
|
|
|
await wstream.write(inputstr)
|
2021-04-22 12:32:28 +00:00
|
|
|
await wstream.finish()
|
|
|
|
await wstream.closeWait()
|
|
|
|
await transp.closeWait()
|
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
|
2023-06-26 13:28:33 +00:00
|
|
|
var server = createStreamServer(initTAddress("127.0.0.1:0"),
|
|
|
|
serveClient, {ReuseAddr})
|
2021-04-22 12:32:28 +00:00
|
|
|
server.start()
|
2023-06-26 13:28:33 +00:00
|
|
|
var transp = await connect(server.localAddress())
|
2021-04-22 12:32:28 +00:00
|
|
|
var rstream = newAsyncStreamReader(transp)
|
|
|
|
var rstream2 = newChunkedStreamReader(rstream)
|
|
|
|
let res =
|
|
|
|
try:
|
2021-04-24 17:32:21 +00:00
|
|
|
var datares {.used.} = await rstream2.read()
|
2021-04-22 12:32:28 +00:00
|
|
|
false
|
|
|
|
except ChunkedStreamProtocolError:
|
|
|
|
true
|
|
|
|
except CatchableError:
|
|
|
|
false
|
|
|
|
await rstream2.closeWait()
|
|
|
|
await rstream.closeWait()
|
|
|
|
await transp.closeWait()
|
|
|
|
await server.join()
|
|
|
|
return res
|
|
|
|
|
|
|
|
var data1 = createBigMessage("REQUESTSTREAMMESSAGE", 65600)
|
|
|
|
var data2 = createBigMessage("REQUESTSTREAMMESSAGE", 262400)
|
2023-06-26 13:28:33 +00:00
|
|
|
check waitFor(checkTooBigChunkHeader(data1)) == true
|
|
|
|
check waitFor(checkTooBigChunkHeader(data2)) == true
|
2021-04-22 12:32:28 +00:00
|
|
|
|
|
|
|
test "ChunkedStream read/write test":
|
2023-06-26 13:28:33 +00:00
|
|
|
proc checkVector(inputstr: seq[byte],
|
2021-04-24 17:32:21 +00:00
|
|
|
chunkSize: int): Future[seq[byte]] {.async.} =
|
2021-04-22 12:32:28 +00:00
|
|
|
proc serveClient(server: StreamServer,
|
|
|
|
transp: StreamTransport) {.async.} =
|
|
|
|
var wstream = newAsyncStreamWriter(transp)
|
|
|
|
var wstream2 = newChunkedStreamWriter(wstream)
|
|
|
|
var data = inputstr
|
|
|
|
var offset = 0
|
|
|
|
while true:
|
|
|
|
if len(data) == offset:
|
|
|
|
break
|
2021-04-24 17:32:21 +00:00
|
|
|
let toWrite = min(chunkSize, len(data) - offset)
|
2021-04-22 12:32:28 +00:00
|
|
|
await wstream2.write(addr data[offset], toWrite)
|
|
|
|
offset = offset + toWrite
|
|
|
|
await wstream2.finish()
|
|
|
|
await wstream2.closeWait()
|
|
|
|
await wstream.closeWait()
|
|
|
|
await transp.closeWait()
|
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
|
2023-06-26 13:28:33 +00:00
|
|
|
var server = createStreamServer(initTAddress("127.0.0.1:0"),
|
|
|
|
serveClient, {ReuseAddr})
|
2021-04-22 12:32:28 +00:00
|
|
|
server.start()
|
2023-06-26 13:28:33 +00:00
|
|
|
var transp = await connect(server.localAddress())
|
2021-04-22 12:32:28 +00:00
|
|
|
var rstream = newAsyncStreamReader(transp)
|
|
|
|
var rstream2 = newChunkedStreamReader(rstream)
|
|
|
|
var res = await rstream2.read()
|
|
|
|
await rstream2.closeWait()
|
|
|
|
await rstream.closeWait()
|
|
|
|
await transp.closeWait()
|
|
|
|
await server.join()
|
2021-04-24 17:32:21 +00:00
|
|
|
return res
|
2021-04-22 12:32:28 +00:00
|
|
|
|
2023-06-26 13:28:33 +00:00
|
|
|
proc testBigData(datasize: int, chunksize: int): Future[bool] {.async.} =
|
2021-04-22 12:32:28 +00:00
|
|
|
var data = createBigMessage("REQUESTSTREAMMESSAGE", datasize)
|
2023-06-26 13:28:33 +00:00
|
|
|
var check = await checkVector(data, chunksize)
|
2021-04-22 12:32:28 +00:00
|
|
|
return (data == check)
|
|
|
|
|
2023-06-26 13:28:33 +00:00
|
|
|
check waitFor(testBigData(65600, 1024)) == true
|
|
|
|
check waitFor(testBigData(262400, 4096)) == true
|
|
|
|
check waitFor(testBigData(767309, 4457)) == true
|
2021-04-22 12:32:28 +00:00
|
|
|
|
2021-04-24 17:32:21 +00:00
|
|
|
test "ChunkedStream read small chunks test":
|
2023-06-26 13:28:33 +00:00
|
|
|
proc checkVector(inputstr: seq[byte],
|
2021-04-24 17:32:21 +00:00
|
|
|
writeChunkSize: int,
|
|
|
|
readChunkSize: int): Future[seq[byte]] {.async.} =
|
|
|
|
proc serveClient(server: StreamServer,
|
|
|
|
transp: StreamTransport) {.async.} =
|
|
|
|
var wstream = newAsyncStreamWriter(transp)
|
|
|
|
var wstream2 = newChunkedStreamWriter(wstream)
|
|
|
|
var data = inputstr
|
|
|
|
var offset = 0
|
|
|
|
while true:
|
|
|
|
if len(data) == offset:
|
|
|
|
break
|
|
|
|
let toWrite = min(writeChunkSize, len(data) - offset)
|
|
|
|
await wstream2.write(addr data[offset], toWrite)
|
|
|
|
offset = offset + toWrite
|
|
|
|
await wstream2.finish()
|
|
|
|
await wstream2.closeWait()
|
|
|
|
await wstream.closeWait()
|
|
|
|
await transp.closeWait()
|
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
|
2023-06-26 13:28:33 +00:00
|
|
|
var server = createStreamServer(initTAddress("127.0.0.1:0"),
|
|
|
|
serveClient, {ReuseAddr})
|
2021-04-24 17:32:21 +00:00
|
|
|
server.start()
|
2023-06-26 13:28:33 +00:00
|
|
|
var transp = await connect(server.localAddress())
|
2021-04-24 17:32:21 +00:00
|
|
|
var rstream = newAsyncStreamReader(transp)
|
|
|
|
var rstream2 = newChunkedStreamReader(rstream)
|
|
|
|
var res: seq[byte]
|
|
|
|
while not(rstream2.atEof()):
|
|
|
|
var chunk = await rstream2.read(readChunkSize)
|
|
|
|
res.add(chunk)
|
|
|
|
await rstream2.closeWait()
|
|
|
|
await rstream.closeWait()
|
|
|
|
await transp.closeWait()
|
|
|
|
await server.join()
|
|
|
|
return res
|
|
|
|
|
2023-06-26 13:28:33 +00:00
|
|
|
proc testSmallChunk(datasize: int,
|
2021-04-24 17:32:21 +00:00
|
|
|
writeChunkSize: int,
|
|
|
|
readChunkSize: int): Future[bool] {.async.} =
|
|
|
|
var data = createBigMessage("REQUESTSTREAMMESSAGE", datasize)
|
2023-06-26 13:28:33 +00:00
|
|
|
var check = await checkVector(data, writeChunkSize, readChunkSize)
|
2021-04-24 17:32:21 +00:00
|
|
|
return (data == check)
|
|
|
|
|
2023-06-26 13:28:33 +00:00
|
|
|
check waitFor(testSmallChunk(4457, 128, 1)) == true
|
|
|
|
check waitFor(testSmallChunk(65600, 1024, 17)) == true
|
|
|
|
check waitFor(testSmallChunk(262400, 4096, 61)) == true
|
|
|
|
check waitFor(testSmallChunk(767309, 4457, 173)) == true
|
2021-04-24 17:32:21 +00:00
|
|
|
|
2019-10-08 15:46:27 +00:00
|
|
|
test "ChunkedStream leaks test":
|
2023-07-14 10:35:08 +00:00
|
|
|
checkLeaks()
|
2019-10-08 15:46:27 +00:00
|
|
|
|
|
|
|
suite "TLSStream test suite":
|
|
|
|
const HttpHeadersMark = @[byte(0x0D), byte(0x0A), byte(0x0D), byte(0x0A)]
|
|
|
|
test "Simple HTTPS connection":
|
|
|
|
proc headerClient(address: TransportAddress,
|
|
|
|
name: string): Future[bool] {.async.} =
|
|
|
|
var mark = "HTTP/1.1 "
|
|
|
|
var buffer = newSeq[byte](8192)
|
|
|
|
var transp = await connect(address)
|
|
|
|
var reader = newAsyncStreamReader(transp)
|
|
|
|
var writer = newAsyncStreamWriter(transp)
|
2019-10-16 06:01:52 +00:00
|
|
|
var tlsstream = newTLSClientAsyncStream(reader, writer, name)
|
2019-10-08 15:46:27 +00:00
|
|
|
await tlsstream.writer.write("GET / HTTP/1.1\r\nHost: " & name &
|
|
|
|
"\r\nConnection: close\r\n\r\n")
|
|
|
|
var readFut = tlsstream.reader.readUntil(addr buffer[0], len(buffer),
|
|
|
|
HttpHeadersMark)
|
|
|
|
let res = await withTimeout(readFut, 5.seconds)
|
|
|
|
if res:
|
|
|
|
var length = readFut.read()
|
|
|
|
buffer.setLen(length)
|
|
|
|
if len(buffer) > len(mark):
|
|
|
|
if equalMem(addr buffer[0], addr mark[0], len(mark)):
|
|
|
|
result = true
|
|
|
|
|
|
|
|
await tlsstream.reader.closeWait()
|
|
|
|
await tlsstream.writer.closeWait()
|
|
|
|
await reader.closeWait()
|
|
|
|
await writer.closeWait()
|
|
|
|
await transp.closeWait()
|
|
|
|
|
|
|
|
let res = waitFor(headerClient(resolveTAddress("www.google.com:443")[0],
|
|
|
|
"www.google.com"))
|
|
|
|
check res == true
|
|
|
|
|
2023-06-26 13:28:33 +00:00
|
|
|
proc checkSSLServer(pemkey, pemcert: string): Future[bool] {.async.} =
|
2019-10-16 06:01:52 +00:00
|
|
|
var key: TLSPrivateKey
|
|
|
|
var cert: TLSCertificate
|
|
|
|
let testMessage = "TEST MESSAGE"
|
|
|
|
|
|
|
|
proc serveClient(server: StreamServer,
|
|
|
|
transp: StreamTransport) {.async.} =
|
|
|
|
var reader = newAsyncStreamReader(transp)
|
|
|
|
var writer = newAsyncStreamWriter(transp)
|
|
|
|
var sstream = newTLSServerAsyncStream(reader, writer, key, cert)
|
|
|
|
await handshake(sstream)
|
|
|
|
await sstream.writer.write(testMessage & "\r\n")
|
2021-01-21 03:42:44 +00:00
|
|
|
await sstream.writer.finish()
|
2019-10-16 06:01:52 +00:00
|
|
|
await sstream.writer.closeWait()
|
|
|
|
await sstream.reader.closeWait()
|
|
|
|
await reader.closeWait()
|
|
|
|
await writer.closeWait()
|
|
|
|
await transp.closeWait()
|
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
|
|
|
|
key = TLSPrivateKey.init(pemkey)
|
|
|
|
cert = TLSCertificate.init(pemcert)
|
|
|
|
|
2023-06-26 13:28:33 +00:00
|
|
|
var server = createStreamServer(initTAddress("127.0.0.1:0"),
|
|
|
|
serveClient, {ServerFlags.ReuseAddr})
|
2019-10-16 06:01:52 +00:00
|
|
|
server.start()
|
2023-06-26 13:28:33 +00:00
|
|
|
var conn = await connect(server.localAddress())
|
2019-10-16 06:01:52 +00:00
|
|
|
var creader = newAsyncStreamReader(conn)
|
|
|
|
var cwriter = newAsyncStreamWriter(conn)
|
|
|
|
# We are using self-signed certificate
|
2019-10-16 06:07:46 +00:00
|
|
|
let flags = {NoVerifyHost, NoVerifyServerName}
|
|
|
|
var cstream = newTLSClientAsyncStream(creader, cwriter, "", flags = flags)
|
2021-01-21 18:11:43 +00:00
|
|
|
let res = await cstream.reader.read()
|
2019-10-16 06:01:52 +00:00
|
|
|
await cstream.reader.closeWait()
|
|
|
|
await cstream.writer.closeWait()
|
|
|
|
await creader.closeWait()
|
|
|
|
await cwriter.closeWait()
|
|
|
|
await conn.closeWait()
|
|
|
|
await server.join()
|
2023-11-13 11:14:21 +00:00
|
|
|
return string.fromBytes(res) == (testMessage & "\r\n")
|
2019-10-16 06:01:52 +00:00
|
|
|
|
|
|
|
test "Simple server with RSA self-signed certificate":
|
2023-06-26 13:28:33 +00:00
|
|
|
let res = waitFor(checkSSLServer(SelfSignedRsaKey, SelfSignedRsaCert))
|
2019-10-16 06:01:52 +00:00
|
|
|
check res == true
|
2023-10-17 12:19:20 +00:00
|
|
|
|
2023-02-21 18:38:53 +00:00
|
|
|
test "Custom TrustAnchors test":
|
|
|
|
proc checkTrustAnchors(testMessage: string): Future[string] {.async.} =
|
|
|
|
var key = TLSPrivateKey.init(SelfSignedRsaKey)
|
|
|
|
var cert = TLSCertificate.init(SelfSignedRsaCert)
|
|
|
|
let trustAnchors = TrustAnchorStore.new(SelfSignedTrustAnchors)
|
|
|
|
|
|
|
|
proc serveClient(server: StreamServer,
|
|
|
|
transp: StreamTransport) {.async.} =
|
|
|
|
var reader = newAsyncStreamReader(transp)
|
|
|
|
var writer = newAsyncStreamWriter(transp)
|
|
|
|
var sstream = newTLSServerAsyncStream(reader, writer, key, cert)
|
|
|
|
await handshake(sstream)
|
|
|
|
await sstream.writer.write(testMessage & "\r\n")
|
|
|
|
await sstream.writer.finish()
|
|
|
|
await sstream.writer.closeWait()
|
|
|
|
await sstream.reader.closeWait()
|
|
|
|
await reader.closeWait()
|
|
|
|
await writer.closeWait()
|
|
|
|
await transp.closeWait()
|
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
|
2023-06-26 13:28:33 +00:00
|
|
|
var server = createStreamServer(initTAddress("127.0.0.1:0"),
|
|
|
|
serveClient, {ReuseAddr})
|
2023-02-21 18:38:53 +00:00
|
|
|
server.start()
|
2023-06-26 13:28:33 +00:00
|
|
|
var conn = await connect(server.localAddress())
|
2023-02-21 18:38:53 +00:00
|
|
|
var creader = newAsyncStreamReader(conn)
|
|
|
|
var cwriter = newAsyncStreamWriter(conn)
|
|
|
|
let flags = {NoVerifyServerName}
|
|
|
|
var cstream = newTLSClientAsyncStream(creader, cwriter, "", flags = flags,
|
|
|
|
trustAnchors = trustAnchors)
|
|
|
|
let res = await cstream.reader.read()
|
|
|
|
await cstream.reader.closeWait()
|
|
|
|
await cstream.writer.closeWait()
|
|
|
|
await creader.closeWait()
|
|
|
|
await cwriter.closeWait()
|
|
|
|
await conn.closeWait()
|
|
|
|
await server.join()
|
2023-11-13 11:14:21 +00:00
|
|
|
return string.fromBytes(res)
|
2023-02-21 18:38:53 +00:00
|
|
|
let res = waitFor checkTrustAnchors("Some message")
|
|
|
|
check res == "Some message\r\n"
|
2023-10-17 12:19:20 +00:00
|
|
|
|
2019-10-16 06:01:52 +00:00
|
|
|
test "TLSStream leaks test":
|
2023-07-14 10:35:08 +00:00
|
|
|
checkLeaks()
|
2021-01-20 13:40:15 +00:00
|
|
|
|
|
|
|
suite "BoundedStream test suite":
|
|
|
|
|
2021-02-18 12:08:21 +00:00
|
|
|
type
|
|
|
|
BoundarySizeTest = enum
|
|
|
|
SizeReadWrite, SizeOverflow, SizeIncomplete, SizeEmpty
|
|
|
|
BoundaryBytesTest = enum
|
|
|
|
BoundaryRead, BoundaryDouble, BoundarySize, BoundaryIncomplete,
|
|
|
|
BoundaryEmpty
|
|
|
|
|
2021-02-09 11:56:33 +00:00
|
|
|
for itemComp in [BoundCmp.Equal, BoundCmp.LessOrEqual]:
|
|
|
|
for itemSize in [100, 60000]:
|
|
|
|
|
2023-06-26 13:28:33 +00:00
|
|
|
proc boundaryTest(btest: BoundaryBytesTest,
|
2021-02-18 12:08:21 +00:00
|
|
|
size: int, boundary: seq[byte],
|
2021-02-09 11:56:33 +00:00
|
|
|
cmp: BoundCmp): Future[bool] {.async.} =
|
2021-04-24 17:32:21 +00:00
|
|
|
var message = createBigMessage("ABCDEFGHIJKLMNOP", size)
|
2021-02-09 11:56:33 +00:00
|
|
|
var clientRes = false
|
|
|
|
|
|
|
|
proc processClient(server: StreamServer,
|
|
|
|
transp: StreamTransport) {.async.} =
|
|
|
|
var wstream = newAsyncStreamWriter(transp)
|
2021-02-18 12:08:21 +00:00
|
|
|
case btest
|
|
|
|
of BoundaryRead:
|
2021-02-09 11:56:33 +00:00
|
|
|
await wstream.write(message)
|
|
|
|
await wstream.write(boundary)
|
|
|
|
await wstream.finish()
|
|
|
|
await wstream.closeWait()
|
|
|
|
clientRes = true
|
2021-02-18 12:08:21 +00:00
|
|
|
of BoundaryDouble:
|
2021-02-09 11:56:33 +00:00
|
|
|
await wstream.write(message)
|
|
|
|
await wstream.write(boundary)
|
|
|
|
await wstream.write(message)
|
|
|
|
await wstream.finish()
|
|
|
|
await wstream.closeWait()
|
|
|
|
clientRes = true
|
2021-02-18 12:08:21 +00:00
|
|
|
of BoundarySize:
|
2021-02-09 11:56:33 +00:00
|
|
|
var ncmessage = message
|
|
|
|
ncmessage.setLen(len(message) - 2)
|
|
|
|
await wstream.write(ncmessage)
|
|
|
|
await wstream.write(@[0x2D'u8, 0x2D'u8])
|
|
|
|
await wstream.finish()
|
|
|
|
await wstream.closeWait()
|
|
|
|
clientRes = true
|
2021-02-18 12:08:21 +00:00
|
|
|
of BoundaryIncomplete:
|
2021-02-09 11:56:33 +00:00
|
|
|
var ncmessage = message
|
|
|
|
ncmessage.setLen(len(message) - 2)
|
|
|
|
await wstream.write(ncmessage)
|
|
|
|
await wstream.finish()
|
|
|
|
await wstream.closeWait()
|
|
|
|
clientRes = true
|
2021-02-18 12:08:21 +00:00
|
|
|
of BoundaryEmpty:
|
2021-02-09 11:56:33 +00:00
|
|
|
await wstream.write(boundary)
|
|
|
|
await wstream.finish()
|
|
|
|
await wstream.closeWait()
|
|
|
|
clientRes = true
|
2021-01-24 21:40:52 +00:00
|
|
|
|
2021-02-09 11:56:33 +00:00
|
|
|
await transp.closeWait()
|
|
|
|
server.stop()
|
|
|
|
server.close()
|
2021-01-24 21:40:52 +00:00
|
|
|
|
2021-02-09 11:56:33 +00:00
|
|
|
var res = false
|
|
|
|
let flags = {ServerFlags.ReuseAddr, ServerFlags.TcpNoDelay}
|
2023-06-26 13:28:33 +00:00
|
|
|
var server = createStreamServer(initTAddress("127.0.0.1:0"),
|
|
|
|
processClient, flags = flags)
|
2021-02-09 11:56:33 +00:00
|
|
|
server.start()
|
2022-01-20 16:38:41 +00:00
|
|
|
var conn = await connect(server.localAddress())
|
2021-02-09 11:56:33 +00:00
|
|
|
var rstream = newAsyncStreamReader(conn)
|
2021-02-18 12:08:21 +00:00
|
|
|
case btest
|
|
|
|
of BoundaryRead:
|
2021-04-26 11:05:37 +00:00
|
|
|
var rbstream = newBoundedStreamReader(rstream, boundary)
|
2021-02-09 11:56:33 +00:00
|
|
|
let response = await rbstream.read()
|
|
|
|
if response == message:
|
|
|
|
res = true
|
|
|
|
await rbstream.closeWait()
|
2021-02-18 12:08:21 +00:00
|
|
|
of BoundaryDouble:
|
2021-04-26 11:05:37 +00:00
|
|
|
var rbstream = newBoundedStreamReader(rstream, boundary)
|
2021-02-09 11:56:33 +00:00
|
|
|
let response1 = await rbstream.read()
|
|
|
|
await rbstream.closeWait()
|
|
|
|
let response2 = await rstream.read()
|
|
|
|
if (response1 == message) and (response2 == message):
|
|
|
|
res = true
|
2021-02-18 12:08:21 +00:00
|
|
|
of BoundarySize:
|
2021-02-09 11:56:33 +00:00
|
|
|
var expectMessage = message
|
|
|
|
expectMessage[^2] = 0x2D'u8
|
|
|
|
expectMessage[^1] = 0x2D'u8
|
2021-04-26 11:05:37 +00:00
|
|
|
var rbstream = newBoundedStreamReader(rstream, uint64(size), boundary)
|
2021-02-09 11:56:33 +00:00
|
|
|
let response = await rbstream.read()
|
|
|
|
await rbstream.closeWait()
|
|
|
|
if (len(response) == size) and response == expectMessage:
|
|
|
|
res = true
|
2021-02-18 12:08:21 +00:00
|
|
|
of BoundaryIncomplete:
|
2021-04-26 11:05:37 +00:00
|
|
|
var rbstream = newBoundedStreamReader(rstream, boundary)
|
2021-01-20 13:40:15 +00:00
|
|
|
try:
|
2021-02-09 11:56:33 +00:00
|
|
|
let response {.used.} = await rbstream.read()
|
2021-01-20 13:40:15 +00:00
|
|
|
except BoundedStreamIncompleteError:
|
2021-02-09 11:56:33 +00:00
|
|
|
res = true
|
|
|
|
await rbstream.closeWait()
|
2021-02-18 12:08:21 +00:00
|
|
|
of BoundaryEmpty:
|
2021-04-26 11:05:37 +00:00
|
|
|
var rbstream = newBoundedStreamReader(rstream, boundary)
|
2021-02-09 11:56:33 +00:00
|
|
|
let response = await rbstream.read()
|
|
|
|
await rbstream.closeWait()
|
|
|
|
if len(response) == 0:
|
|
|
|
res = true
|
|
|
|
|
|
|
|
await rstream.closeWait()
|
|
|
|
await conn.closeWait()
|
|
|
|
await server.join()
|
|
|
|
return (res and clientRes)
|
|
|
|
|
2023-06-26 13:28:33 +00:00
|
|
|
proc boundedTest(stest: BoundarySizeTest,
|
2021-02-09 11:56:33 +00:00
|
|
|
size: int, cmp: BoundCmp): Future[bool] {.async.} =
|
|
|
|
var clientRes = false
|
|
|
|
var res = false
|
|
|
|
|
2021-04-24 17:32:21 +00:00
|
|
|
let messagePart = createBigMessage("ABCDEFGHIJKLMNOP",
|
|
|
|
int(itemSize) div 10)
|
2021-02-09 11:56:33 +00:00
|
|
|
var message: seq[byte]
|
|
|
|
for i in 0 ..< 10:
|
|
|
|
message.add(messagePart)
|
|
|
|
|
|
|
|
proc processClient(server: StreamServer,
|
|
|
|
transp: StreamTransport) {.async.} =
|
|
|
|
var wstream = newAsyncStreamWriter(transp)
|
2021-04-26 11:05:37 +00:00
|
|
|
var wbstream = newBoundedStreamWriter(wstream, uint64(size),
|
|
|
|
comparison = cmp)
|
2021-02-18 12:08:21 +00:00
|
|
|
case stest
|
|
|
|
of SizeReadWrite:
|
2021-02-09 11:56:33 +00:00
|
|
|
for i in 0 ..< 10:
|
|
|
|
await wbstream.write(messagePart)
|
|
|
|
await wbstream.finish()
|
|
|
|
await wbstream.closeWait()
|
2021-01-20 13:40:15 +00:00
|
|
|
clientRes = true
|
2021-02-18 12:08:21 +00:00
|
|
|
of SizeOverflow:
|
2021-02-09 11:56:33 +00:00
|
|
|
for i in 0 ..< 10:
|
|
|
|
await wbstream.write(messagePart)
|
|
|
|
try:
|
|
|
|
await wbstream.write(messagePart)
|
|
|
|
except BoundedStreamOverflowError:
|
|
|
|
clientRes = true
|
|
|
|
await wbstream.closeWait()
|
2021-02-18 12:08:21 +00:00
|
|
|
of SizeIncomplete:
|
2021-02-09 11:56:33 +00:00
|
|
|
for i in 0 ..< 9:
|
|
|
|
await wbstream.write(messagePart)
|
|
|
|
case cmp
|
|
|
|
of BoundCmp.Equal:
|
|
|
|
try:
|
|
|
|
await wbstream.finish()
|
|
|
|
except BoundedStreamIncompleteError:
|
|
|
|
clientRes = true
|
|
|
|
of BoundCmp.LessOrEqual:
|
|
|
|
try:
|
|
|
|
await wbstream.finish()
|
|
|
|
clientRes = true
|
|
|
|
except BoundedStreamIncompleteError:
|
|
|
|
discard
|
|
|
|
await wbstream.closeWait()
|
2021-02-18 12:08:21 +00:00
|
|
|
of SizeEmpty:
|
2021-02-09 11:56:33 +00:00
|
|
|
case cmp
|
|
|
|
of BoundCmp.Equal:
|
|
|
|
try:
|
|
|
|
await wbstream.finish()
|
|
|
|
except BoundedStreamIncompleteError:
|
|
|
|
clientRes = true
|
|
|
|
of BoundCmp.LessOrEqual:
|
|
|
|
try:
|
|
|
|
await wbstream.finish()
|
|
|
|
clientRes = true
|
|
|
|
except BoundedStreamIncompleteError:
|
|
|
|
discard
|
|
|
|
await wbstream.closeWait()
|
2021-01-20 13:40:15 +00:00
|
|
|
|
2021-02-09 11:56:33 +00:00
|
|
|
await wstream.closeWait()
|
|
|
|
await transp.closeWait()
|
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
|
|
|
|
let flags = {ServerFlags.ReuseAddr, ServerFlags.TcpNoDelay}
|
2023-06-26 13:28:33 +00:00
|
|
|
var server = createStreamServer(initTAddress("127.0.0.1:0"),
|
|
|
|
processClient, flags = flags)
|
2021-02-09 11:56:33 +00:00
|
|
|
server.start()
|
2022-01-20 16:38:41 +00:00
|
|
|
var conn = await connect(server.localAddress())
|
2021-02-09 11:56:33 +00:00
|
|
|
var rstream = newAsyncStreamReader(conn)
|
2021-04-26 11:05:37 +00:00
|
|
|
var rbstream = newBoundedStreamReader(rstream, uint64(size),
|
|
|
|
comparison = cmp)
|
2021-02-18 12:08:21 +00:00
|
|
|
case stest
|
|
|
|
of SizeReadWrite:
|
2021-02-09 11:56:33 +00:00
|
|
|
let response = await rbstream.read()
|
|
|
|
await rbstream.closeWait()
|
|
|
|
if response == message:
|
|
|
|
res = true
|
2021-02-18 12:08:21 +00:00
|
|
|
of SizeOverflow:
|
2021-02-09 11:56:33 +00:00
|
|
|
let response = await rbstream.read()
|
|
|
|
await rbstream.closeWait()
|
|
|
|
if response == message:
|
|
|
|
res = true
|
2021-02-18 12:08:21 +00:00
|
|
|
of SizeIncomplete:
|
2021-02-09 11:56:33 +00:00
|
|
|
case cmp
|
|
|
|
of BoundCmp.Equal:
|
|
|
|
try:
|
|
|
|
let response {.used.} = await rbstream.read()
|
|
|
|
except BoundedStreamIncompleteError:
|
|
|
|
res = true
|
|
|
|
of BoundCmp.LessOrEqual:
|
|
|
|
try:
|
|
|
|
let response = await rbstream.read()
|
|
|
|
if len(response) == 9 * len(messagePart):
|
|
|
|
res = true
|
|
|
|
except BoundedStreamIncompleteError:
|
|
|
|
res = false
|
|
|
|
await rbstream.closeWait()
|
2021-02-18 12:08:21 +00:00
|
|
|
of SizeEmpty:
|
2021-02-09 11:56:33 +00:00
|
|
|
case cmp
|
|
|
|
of BoundCmp.Equal:
|
|
|
|
try:
|
|
|
|
let response {.used.} = await rbstream.read()
|
|
|
|
except BoundedStreamIncompleteError:
|
|
|
|
res = true
|
|
|
|
of BoundCmp.LessOrEqual:
|
|
|
|
try:
|
|
|
|
let response = await rbstream.read()
|
|
|
|
if len(response) == 0:
|
|
|
|
res = true
|
|
|
|
except BoundedStreamIncompleteError:
|
|
|
|
res = false
|
|
|
|
await rbstream.closeWait()
|
|
|
|
|
|
|
|
await rstream.closeWait()
|
|
|
|
await conn.closeWait()
|
|
|
|
await server.join()
|
|
|
|
return (res and clientRes)
|
|
|
|
|
|
|
|
let suffix =
|
|
|
|
case itemComp
|
|
|
|
of BoundCmp.Equal:
|
|
|
|
"== " & $itemSize
|
|
|
|
of BoundCmp.LessOrEqual:
|
|
|
|
"<= " & $itemSize
|
|
|
|
|
|
|
|
test "BoundedStream(size) reading/writing test [" & suffix & "]":
|
2023-06-26 13:28:33 +00:00
|
|
|
check waitFor(boundedTest(SizeReadWrite, itemSize,
|
2021-02-18 12:08:21 +00:00
|
|
|
itemComp)) == true
|
2021-02-09 11:56:33 +00:00
|
|
|
test "BoundedStream(size) overflow test [" & suffix & "]":
|
2023-06-26 13:28:33 +00:00
|
|
|
check waitFor(boundedTest(SizeOverflow, itemSize,
|
2021-02-18 12:08:21 +00:00
|
|
|
itemComp)) == true
|
2021-02-09 11:56:33 +00:00
|
|
|
test "BoundedStream(size) incomplete test [" & suffix & "]":
|
2023-06-26 13:28:33 +00:00
|
|
|
check waitFor(boundedTest(SizeIncomplete, itemSize,
|
2021-02-18 12:08:21 +00:00
|
|
|
itemComp)) == true
|
2021-02-09 11:56:33 +00:00
|
|
|
test "BoundedStream(size) empty message test [" & suffix & "]":
|
2023-06-26 13:28:33 +00:00
|
|
|
check waitFor(boundedTest(SizeEmpty, itemSize,
|
2021-02-18 12:08:21 +00:00
|
|
|
itemComp)) == true
|
2021-02-09 11:56:33 +00:00
|
|
|
test "BoundedStream(boundary) reading test [" & suffix & "]":
|
2023-06-26 13:28:33 +00:00
|
|
|
check waitFor(boundaryTest(BoundaryRead, itemSize,
|
2021-02-09 11:56:33 +00:00
|
|
|
@[0x2D'u8, 0x2D'u8, 0x2D'u8], itemComp))
|
|
|
|
test "BoundedStream(boundary) double message test [" & suffix & "]":
|
2023-06-26 13:28:33 +00:00
|
|
|
check waitFor(boundaryTest(BoundaryDouble, itemSize,
|
2021-02-09 11:56:33 +00:00
|
|
|
@[0x2D'u8, 0x2D'u8, 0x2D'u8], itemComp))
|
|
|
|
test "BoundedStream(size+boundary) reading size-bound test [" &
|
|
|
|
suffix & "]":
|
2023-06-26 13:28:33 +00:00
|
|
|
check waitFor(boundaryTest(BoundarySize, itemSize,
|
2021-02-09 11:56:33 +00:00
|
|
|
@[0x2D'u8, 0x2D'u8, 0x2D'u8], itemComp))
|
|
|
|
test "BoundedStream(boundary) reading incomplete test [" &
|
|
|
|
suffix & "]":
|
2023-06-26 13:28:33 +00:00
|
|
|
check waitFor(boundaryTest(BoundaryIncomplete, itemSize,
|
2021-02-09 11:56:33 +00:00
|
|
|
@[0x2D'u8, 0x2D'u8, 0x2D'u8], itemComp))
|
|
|
|
test "BoundedStream(boundary) empty message test [" &
|
|
|
|
suffix & "]":
|
2023-06-26 13:28:33 +00:00
|
|
|
check waitFor(boundaryTest(BoundaryEmpty, itemSize,
|
2021-02-09 11:56:33 +00:00
|
|
|
@[0x2D'u8, 0x2D'u8, 0x2D'u8], itemComp))
|
2021-01-24 21:40:52 +00:00
|
|
|
|
2021-04-24 17:32:21 +00:00
|
|
|
test "BoundedStream read small chunks test":
|
2023-06-26 13:28:33 +00:00
|
|
|
proc checkVector(inputstr: seq[byte],
|
2021-04-24 17:32:21 +00:00
|
|
|
writeChunkSize: int,
|
|
|
|
readChunkSize: int): Future[seq[byte]] {.async.} =
|
|
|
|
proc serveClient(server: StreamServer,
|
|
|
|
transp: StreamTransport) {.async.} =
|
|
|
|
var wstream = newAsyncStreamWriter(transp)
|
2021-04-26 11:05:37 +00:00
|
|
|
var wstream2 = newBoundedStreamWriter(wstream, uint64(len(inputstr)))
|
2021-04-24 17:32:21 +00:00
|
|
|
var data = inputstr
|
|
|
|
var offset = 0
|
|
|
|
while true:
|
|
|
|
if len(data) == offset:
|
|
|
|
break
|
|
|
|
let toWrite = min(writeChunkSize, len(data) - offset)
|
|
|
|
await wstream2.write(addr data[offset], toWrite)
|
|
|
|
offset = offset + toWrite
|
|
|
|
await wstream2.finish()
|
|
|
|
await wstream2.closeWait()
|
|
|
|
await wstream.closeWait()
|
|
|
|
await transp.closeWait()
|
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
|
2023-06-26 13:28:33 +00:00
|
|
|
var server = createStreamServer(initTAddress("127.0.0.1:0"),
|
|
|
|
serveClient, {ReuseAddr})
|
2021-04-24 17:32:21 +00:00
|
|
|
server.start()
|
2023-06-26 13:28:33 +00:00
|
|
|
var transp = await connect(server.localAddress())
|
2021-04-24 17:32:21 +00:00
|
|
|
var rstream = newAsyncStreamReader(transp)
|
|
|
|
var rstream2 = newBoundedStreamReader(rstream, 1048576,
|
|
|
|
comparison = BoundCmp.LessOrEqual)
|
|
|
|
var res: seq[byte]
|
|
|
|
while not(rstream2.atEof()):
|
|
|
|
var chunk = await rstream2.read(readChunkSize)
|
|
|
|
res.add(chunk)
|
|
|
|
await rstream2.closeWait()
|
|
|
|
await rstream.closeWait()
|
|
|
|
await transp.closeWait()
|
|
|
|
await server.join()
|
|
|
|
return res
|
|
|
|
|
2023-06-26 13:28:33 +00:00
|
|
|
proc testSmallChunk(datasize: int, writeChunkSize: int,
|
2021-04-24 17:32:21 +00:00
|
|
|
readChunkSize: int): Future[bool] {.async.} =
|
|
|
|
var data = createBigMessage("0123456789ABCDEFGHI", datasize)
|
2023-06-26 13:28:33 +00:00
|
|
|
var check = await checkVector(data, writeChunkSize, readChunkSize)
|
2021-04-24 17:32:21 +00:00
|
|
|
return (data == check)
|
|
|
|
|
2023-06-26 13:28:33 +00:00
|
|
|
check waitFor(testSmallChunk(4457, 128, 1)) == true
|
|
|
|
check waitFor(testSmallChunk(65600, 1024, 17)) == true
|
|
|
|
check waitFor(testSmallChunk(262400, 4096, 61)) == true
|
|
|
|
check waitFor(testSmallChunk(767309, 4457, 173)) == true
|
2021-04-24 17:32:21 +00:00
|
|
|
|
2021-05-07 15:52:44 +00:00
|
|
|
test "BoundedStream zero-sized streams test":
|
2023-06-26 13:28:33 +00:00
|
|
|
proc checkEmptyStreams(): Future[bool] {.async.} =
|
2021-05-07 15:52:44 +00:00
|
|
|
var writer1Res = false
|
|
|
|
proc serveClient(server: StreamServer,
|
|
|
|
transp: StreamTransport) {.async.} =
|
|
|
|
var wstream = newAsyncStreamWriter(transp)
|
|
|
|
var wstream2 = newBoundedStreamWriter(wstream, 0'u64)
|
|
|
|
await wstream2.finish()
|
|
|
|
let res = wstream2.atEof()
|
|
|
|
await wstream2.closeWait()
|
|
|
|
await wstream.closeWait()
|
|
|
|
await transp.closeWait()
|
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
writer1Res = res
|
|
|
|
|
2023-06-26 13:28:33 +00:00
|
|
|
var server = createStreamServer(initTAddress("127.0.0.1:0"),
|
|
|
|
serveClient, {ReuseAddr})
|
2021-05-07 15:52:44 +00:00
|
|
|
server.start()
|
2023-06-26 13:28:33 +00:00
|
|
|
var transp = await connect(server.localAddress())
|
2021-05-07 15:52:44 +00:00
|
|
|
var rstream = newAsyncStreamReader(transp)
|
|
|
|
var wstream3 = newAsyncStreamWriter(transp)
|
|
|
|
var rstream2 = newBoundedStreamReader(rstream, 0'u64)
|
|
|
|
var wstream4 = newBoundedStreamWriter(wstream3, 0'u64)
|
|
|
|
|
|
|
|
let readerRes = rstream2.atEof()
|
|
|
|
let writer2Res =
|
|
|
|
try:
|
|
|
|
await wstream4.write("data")
|
|
|
|
false
|
|
|
|
except BoundedStreamOverflowError:
|
|
|
|
true
|
|
|
|
except CatchableError:
|
|
|
|
false
|
|
|
|
|
|
|
|
await wstream4.closeWait()
|
|
|
|
await wstream3.closeWait()
|
|
|
|
await rstream2.closeWait()
|
|
|
|
await rstream.closeWait()
|
|
|
|
await transp.closeWait()
|
|
|
|
await server.join()
|
|
|
|
return (writer1Res and writer2Res and readerRes)
|
|
|
|
|
2023-06-26 13:28:33 +00:00
|
|
|
check waitFor(checkEmptyStreams()) == true
|
2021-04-24 17:32:21 +00:00
|
|
|
|
2021-01-24 21:40:52 +00:00
|
|
|
test "BoundedStream leaks test":
|
2023-07-14 10:35:08 +00:00
|
|
|
checkLeaks()
|