summary refs log tree commit diff stats
path: root/tests/stdlib
diff options
context:
space:
mode:
authorRuslan Mustakov <endragor@users.noreply.github.com>2017-05-02 14:25:50 +0700
committerAndreas Rumpf <rumpf_a@web.de>2017-05-02 09:25:50 +0200
commitecf278c4672aa680803ee82e1a59a686c765f226 (patch)
treea36d3a10aca0718b191379737653a8fb75b569f2 /tests/stdlib
parent6377b52d8e1e7bbf0ff4a8d71081d44368ea1d94 (diff)
downloadNim-ecf278c4672aa680803ee82e1a59a686c765f226.tar.gz
Implement dial, support IPv6 in httpclient (#5763)
* Implement dial, support IPv6 in httpclient

Added ``dial`` procedure to networking modules: ``net``, ``asyncdispatch``,
``asyncnet``. It merges socket creation, address resolution, and connection
into single step. When using ``dial``, you don't have to worry about
IPv4 vs IPv6 problem.

Fixed addrInfo loop in connect to behave properly.
Previously it would stop on first non-immediate failure, instead of
continuing and trying the remaining addresses.

Fixed newAsyncNativeSocket to raise proper error if socket creation
fails.

Fixes: #3811

* Check domain during connect() only on non-Windows

This is how it was in the previous implementation of connect().

* Call 'osLastError' before 'close' in net.dial

* Record osLastError before freeAddrInfo in net.dial

* Add missing docs for 'dial' proc

* Optimize dial to create one FD per domain, add tests

And make async IPv6 servers work on Windows.

* Add IPv6 test to uri module

* Fix getAddrString error handling
Diffstat (limited to 'tests/stdlib')
-rw-r--r--tests/stdlib/thttpclient.nim40
-rw-r--r--tests/stdlib/tnetdial.nim60
2 files changed, 98 insertions, 2 deletions
diff --git a/tests/stdlib/thttpclient.nim b/tests/stdlib/thttpclient.nim
index 62c1ebee7..40324d92a 100644
--- a/tests/stdlib/thttpclient.nim
+++ b/tests/stdlib/thttpclient.nim
@@ -1,11 +1,13 @@
 discard """
   cmd: "nim c --threads:on -d:ssl $file"
+  exitcode: 0
+  output: "OK"
 """
 
 import strutils
 from net import TimeoutError
 
-import httpclient, asyncdispatch
+import nativesockets, os, httpclient, asyncdispatch
 
 const manualTests = false
 
@@ -112,6 +114,40 @@ proc syncTest() =
   except:
     doAssert false, "TimeoutError should have been raised."
 
-syncTest()
+proc makeIPv6HttpServer(hostname: string, port: Port): AsyncFD =
+  let fd = newNativeSocket(AF_INET6)
+  setSockOptInt(fd, SOL_SOCKET, SO_REUSEADDR, 1)
+  var aiList = getAddrInfo(hostname, port, AF_INET6)
+  if bindAddr(fd, aiList.ai_addr, aiList.ai_addrlen.Socklen) < 0'i32:
+    freeAddrInfo(aiList)
+    raiseOSError(osLastError())
+  freeAddrInfo(aiList)
+  if listen(fd) != 0:
+    raiseOSError(osLastError())
+  setBlocking(fd, false)
+
+  var serverFd = fd.AsyncFD
+  register(serverFd)
+  result = serverFd
+
+  proc onAccept(fut: Future[AsyncFD]) {.gcsafe.} =
+    if not fut.failed:
+      let clientFd = fut.read()
+      clientFd.send("HTTP/1.1 200 OK\r\LContent-Length: 0\r\LConnection: Closed\r\L\r\L").callback = proc() =
+        clientFd.closeSocket()
+      serverFd.accept().callback = onAccept
+  serverFd.accept().callback = onAccept
+
+proc ipv6Test() =
+  var client = newAsyncHttpClient()
+  let serverFd = makeIPv6HttpServer("::1", Port(18473))
+  var resp = waitFor client.request("http://[::1]:18473/")
+  doAssert(resp.status == "200 OK")
+  serverFd.closeSocket()
+  client.close()
 
+syncTest()
 waitFor(asyncTest())
+ipv6Test()
+
+echo "OK"
diff --git a/tests/stdlib/tnetdial.nim b/tests/stdlib/tnetdial.nim
new file mode 100644
index 000000000..da6088d70
--- /dev/null
+++ b/tests/stdlib/tnetdial.nim
@@ -0,0 +1,60 @@
+discard """
+  cmd: "nim c --threads:on $file"
+  exitcode: 0
+  output: "OK"
+"""
+
+import os, net, nativesockets, asyncdispatch
+
+## Test for net.dial
+
+const port = Port(28431)
+
+proc initIPv6Server(hostname: string, port: Port): AsyncFD =
+  let fd = newNativeSocket(AF_INET6)
+  setSockOptInt(fd, SOL_SOCKET, SO_REUSEADDR, 1)
+  var aiList = getAddrInfo(hostname, port, AF_INET6)
+  if bindAddr(fd, aiList.ai_addr, aiList.ai_addrlen.Socklen) < 0'i32:
+    freeAddrInfo(aiList)
+    raiseOSError(osLastError())
+  freeAddrInfo(aiList)
+  if listen(fd) != 0:
+    raiseOSError(osLastError())
+  setBlocking(fd, false)
+
+  var serverFd = fd.AsyncFD
+  register(serverFd)
+  result = serverFd
+
+# Since net.dial is synchronous, we use main thread to setup server,
+# and dial to it from another thread.
+
+proc testThread() {.thread.} =
+  let fd = net.dial("::1", port)
+  var s = newString(5)
+  doAssert fd.recv(addr s[0], 5) == 5
+  if s == "Hello":
+    echo "OK"
+  fd.close()
+
+proc test() =
+  var t: Thread[void]
+  createThread(t, testThread)
+
+  let serverFd = initIPv6Server("::1", port)
+  var done = false
+
+  serverFd.accept().callback = proc(fut: Future[AsyncFD]) =
+    serverFd.closeSocket()
+    if not fut.failed:
+      let fd = fut.read()
+      fd.send("Hello").callback = proc() =
+        fd.closeSocket()
+        done = true
+
+  while not done:
+    poll()
+
+  joinThread(t)
+
+test()
365' href='#n365'>365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463