add support for DNS resolution (#81)

* add support for DNS resolution

- reworked API to be more consistent
  - string addresses and Uri types will be now resolved
- made the API more consistent

* log failed connection attempt

* agent string can't contain spaces

* add websock topic (#83)

* style

Co-authored-by: Tanguy Cizain <tanguycizain@gmail.com>
This commit is contained in:
Dmitriy Ryajov 2021-07-14 18:51:39 -06:00 committed by GitHub
parent fec0f2bac1
commit 06ae75cf7f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 64 additions and 100 deletions

View File

@ -19,19 +19,18 @@ const
# so we are using different port
when defined tls:
const
agent = "websock secure client"
agent = "websock-secure-client"
secure = true
serverPort = 9002
else:
const
agent = "websock client"
agent = "websock-client"
secure = false
serverPort = 9001
proc connectServer(path: string, factories: seq[ExtFactory] = @[]): Future[WSSession] {.async.} =
let ws = await WebSocket.connect(
host = "127.0.0.1",
port = Port(serverPort),
host = "127.0.0.1:$1" % [$serverPort],
path = path,
secure=secure,
flags=clientFlags,

View File

@ -17,14 +17,12 @@ import ../websock/websock
proc main() {.async.} =
let ws = when defined tls:
await WebSocket.connect(
"127.0.0.1",
Port(8888),
"127.0.0.1:8888",
path = "/wss",
flags = {TLSFlags.NoVerifyHost, TLSFlags.NoVerifyServerName})
else:
await WebSocket.connect(
"127.0.0.1",
Port(8888),
"127.0.0.1:8888",
path = "/ws")
trace "Websocket client: ", State = ws.readyState

View File

@ -48,8 +48,7 @@ suite "permessage deflate compression":
server.start()
let client = await WebSocket.connect(
host = "127.0.0.1",
port = Port(8888),
host = "127.0.0.1:8888",
path = "/ws",
protocols = @["proto"],
factories = @[deflateFactory]
@ -89,8 +88,7 @@ suite "permessage deflate compression":
server.start()
let client = await WebSocket.connect(
host = "127.0.0.1",
port = Port(8888),
host = "127.0.0.1:8888",
path = "/ws",
protocols = @["proto"],
factories = @[deflateFactory]

View File

@ -43,8 +43,7 @@ suite "multiple extensions flow":
server.start()
let client = await WebSocket.connect(
host = "127.0.0.1",
port = Port(8888),
host = "127.0.0.1:8888",
path = "/ws",
protocols = @["proto"],
factories = @[hexFactory, base64Factory]
@ -76,8 +75,7 @@ suite "multiple extensions flow":
server.start()
let client = await WebSocket.connect(
host = "127.0.0.1",
port = Port(8888),
host = "127.0.0.1:8888",
path = "/ws",
protocols = @["proto"],
factories = @[base64Factory, hexFactory]

View File

@ -96,7 +96,7 @@ proc connectClient*(
rng: Rng = nil): Future[WSSession] {.async.} =
let secure = when defined secure: true else: false
return await WebSocket.connect(
address = address,
host = address,
flags = flags,
path = path,
secure = secure,

View File

@ -110,8 +110,7 @@ suite "UTF-8 validator in action":
server.start()
let session = await WebSocket.connect(
"127.0.0.1",
Port(8888),
"127.0.0.1:8888",
path = "/ws",
protocols = @["proto"],
)
@ -152,8 +151,7 @@ suite "UTF-8 validator in action":
server.start()
let session = await WebSocket.connect(
"127.0.0.1",
Port(8888),
"127.0.0.1:8888",
path = "/ws",
protocols = @["proto"],
)
@ -178,8 +176,7 @@ suite "UTF-8 validator in action":
server.start()
let session = await WebSocket.connect(
"127.0.0.1",
Port(8888),
"127.0.0.1:8888",
path = "/ws",
protocols = @["proto"]
)
@ -204,8 +201,7 @@ suite "UTF-8 validator in action":
server.start()
let session = await WebSocket.connect(
"127.0.0.1",
Port(8888),
"127.0.0.1:8888",
path = "/ws",
protocols = @["proto"]
)

View File

@ -33,7 +33,6 @@ suite "Test handshake":
test "Should not select incorrect protocol":
proc handle(request: HttpRequest) {.async.} =
check request.uri.path == WSPath
let
server = WSServer.new(protos = ["proto"])
ws = await server.handleRequest(request)

View File

@ -103,9 +103,6 @@ proc request*(
else:
url
if requestUrl.scheme == "":
raise newException(HttpError, "No uri scheme supplied.")
let headerString = generateHeaders(requestUrl, httpMethod, client.version, headers)
await client.stream.writer.write(headerString)
@ -129,7 +126,8 @@ proc connect*(
version = HttpVersion11,
tlsFlags: set[TLSFlags] = {},
tlsMinVersion = TLSVersion.TLS11,
tlsMaxVersion = TLSVersion.TLS12): Future[T] {.async.} =
tlsMaxVersion = TLSVersion.TLS12,
hostName = ""): Future[T] {.async.} =
let transp = await connect(address)
let client = T(
@ -150,7 +148,7 @@ proc connect*(
let tlsStream = newTLSClientAsyncStream(
stream.reader,
stream.writer,
address.host,
serverName = hostName,
minVersion = tlsMinVersion,
maxVersion = tlsMaxVersion,
flags = tlsFlags)
@ -167,16 +165,27 @@ proc connect*(
proc connect*(
T: typedesc[HttpClient | TlsHttpClient],
host: string,
port: int = 80,
version = HttpVersion11,
tlsFlags: set[TLSFlags] = {},
tlsMinVersion = TLSVersion.TLS11,
tlsMaxVersion = TLSVersion.TLS12): Future[T]
{.raises: [Defect, HttpError].} =
{.async, raises: [Defect, HttpError].} =
let address = try:
initTAddress(host, port)
except TransportAddressError as exc:
raise newException(HttpError, exc.msg)
let hostPort = host.split(":")
let addrs = resolveTAddress(host)
for a in addrs:
try:
let conn = await T.connect(
a,
version,
tlsFlags,
tlsMinVersion,
tlsMaxVersion,
hostName = hostPort[0])
return T.connect(address, version, tlsFlags, tlsMinVersion, tlsMaxVersion)
return conn
except TransportError as exc:
trace "Error connecting to address", address = $a, exc = exc.msg
raise newException(HttpError,
"Unable to connect to host on any address!")

View File

@ -103,8 +103,8 @@ type
ExtFactoryProc* = proc(
isServer: bool,
args: seq[ExtParam]): Result[Ext, string] {.
gcsafe, raises: [Defect].}
args: seq[ExtParam]): Result[Ext, string]
{.gcsafe, raises: [Defect].}
ExtFactory* = object
name*: string

View File

@ -105,9 +105,11 @@ proc selectExt(isServer: bool,
proc connect*(
_: type WebSocket,
uri: Uri,
host: string | TransportAddress,
path: string,
protocols: seq[string] = @[],
factories: seq[ExtFactory] = @[],
secure = false,
flags: set[TLSFlags] = {},
version = WSDefaultVersion,
frameSize = WSDefaultFrameSize,
@ -115,22 +117,15 @@ proc connect*(
onPong: ControlCb = nil,
onClose: CloseCb = nil,
rng: Rng = nil): Future[WSSession] {.async.} =
## create a new websockets client
##
var rng = if isNil(rng): newRng() else: rng
var key = Base64Pad.encode(genWebSecKey(rng))
var uri = uri
let client = case uri.scheme:
of "wss":
uri.scheme = "https"
await TlsHttpClient.connect(uri.hostname, uri.port.parseInt(), tlsFlags = flags)
of "ws":
uri.scheme = "http"
await HttpClient.connect(uri.hostname, uri.port.parseInt())
let
rng = if isNil(rng): newRng() else: rng
key = Base64Pad.encode(genWebSecKey(rng))
let client = if secure:
await TlsHttpClient.connect(host, tlsFlags = flags)
else:
raise newException(WSWrongUriSchemeError,
"uri scheme has to be 'ws' or 'wss'")
await HttpClient.connect(host)
let headerData = [
("Connection", "Upgrade"),
@ -138,7 +133,7 @@ proc connect*(
("Cache-Control", "no-cache"),
("Sec-WebSocket-Version", $version),
("Sec-WebSocket-Key", key),
("Host", uri.hostname & ":" & uri.port)]
("Host", $host)]
var headers = HttpTable.init(headerData)
if protocols.len > 0:
@ -154,7 +149,7 @@ proc connect*(
headers.add("Sec-WebSocket-Extensions", extOffer)
let response = try:
await client.request(uri, headers = headers)
await client.request(path, headers = headers)
except CatchableError as exc:
trace "Websocket failed during handshake", exc = exc.msg
await client.close()
@ -195,63 +190,35 @@ proc connect*(
proc connect*(
_: type WebSocket,
address: TransportAddress,
path: string,
uri: Uri,
protocols: seq[string] = @[],
factories: seq[ExtFactory] = @[],
secure = false,
flags: set[TLSFlags] = {},
version = WSDefaultVersion,
frameSize = WSDefaultFrameSize,
onPing: ControlCb = nil,
onPong: ControlCb = nil,
onClose: CloseCb = nil,
rng: Rng = nil): Future[WSSession] {.async.} =
rng: Rng = nil): Future[WSSession]
{.raises: [Defect, WSWrongUriSchemeError].} =
## Create a new websockets client
## using a string path
## using a Uri
##
var uri = if secure:
&"wss://"
let secure = case uri.scheme:
of "wss": true
of "ws": false
else:
&"ws://"
raise newException(WSWrongUriSchemeError,
"uri scheme has to be 'ws' or 'wss'")
uri &= address.host & ":" & $address.port
if path.startsWith("/"):
uri.add path
else:
uri.add &"/{path}"
var uri = uri
if uri.port.len <= 0:
uri.port = if secure: "443" else: "80"
return await WebSocket.connect(
uri = parseUri(uri),
protocols = protocols,
factories = factories,
flags = flags,
version = version,
frameSize = frameSize,
onPing = onPing,
onPong = onPong,
onClose = onClose)
proc connect*(
_: type WebSocket,
host: string,
port: Port,
path: string,
protocols: seq[string] = @[],
factories: seq[ExtFactory] = @[],
secure = false,
flags: set[TLSFlags] = {},
version = WSDefaultVersion,
frameSize = WSDefaultFrameSize,
onPing: ControlCb = nil,
onPong: ControlCb = nil,
onClose: CloseCb = nil,
rng: Rng = nil): Future[WSSession] {.async.} =
return await WebSocket.connect(
address = initTAddress(host, port),
path = path,
return WebSocket.connect(
host = uri.hostname & ":" & uri.port,
path = uri.path,
protocols = protocols,
factories = factories,
secure = secure,