summary refs log tree commit diff stats
path: root/lib/pure/httpclient.nim
diff options
context:
space:
mode:
authorDominik Picheta <dominikpicheta@googlemail.com>2014-08-31 12:54:43 +0100
committerDominik Picheta <dominikpicheta@googlemail.com>2014-08-31 12:55:04 +0100
commitbb1e87ce4d3e3e81e65609354667e5ed860f02c8 (patch)
tree7a457d72e48c330d33672690772d157d041f866d /lib/pure/httpclient.nim
parentd26d42b88e2abacb74cd3bfedf7b9a0d8d0a7eee (diff)
downloadNim-bb1e87ce4d3e3e81e65609354667e5ed860f02c8.tar.gz
Async SSL support.
Diffstat (limited to 'lib/pure/httpclient.nim')
-rw-r--r--lib/pure/httpclient.nim57
1 files changed, 37 insertions, 20 deletions
diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim
index c5e657bab..8b19c58f8 100644
--- a/lib/pure/httpclient.nim
+++ b/lib/pure/httpclient.nim
@@ -78,6 +78,7 @@
 import sockets, strutils, parseurl, parseutils, strtabs, base64, os
 import asyncnet, asyncdispatch
 import rawsockets
+from net import nil
 
 type
   Response* = tuple[
@@ -164,16 +165,17 @@ proc parseBody(s: TSocket, headers: PStringTable, timeout: int): string =
     var contentLengthHeader = headers["Content-Length"]
     if contentLengthHeader != "":
       var length = contentLengthHeader.parseint()
-      result = newString(length)
-      var received = 0
-      while true:
-        if received >= length: break
-        let r = s.recv(addr(result[received]), length-received, timeout)
-        if r == 0: break
-        received += r
-      if received != length:
-        httpError("Got invalid content length. Expected: " & $length &
-                  " got: " & $received)
+      if length > 0:
+        result = newString(length)
+        var received = 0
+        while true:
+          if received >= length: break
+          let r = s.recv(addr(result[received]), length-received, timeout)
+          if r == 0: break
+          received += r
+        if received != length:
+          httpError("Got invalid content length. Expected: " & $length &
+                    " got: " & $received)
     else:
       # (http://tools.ietf.org/html/rfc2616#section-4.4) NR.4 TODO
       
@@ -444,11 +446,13 @@ type
     headers: StringTableRef
     maxRedirects: int
     userAgent: string
+    when defined(ssl):
+      sslContext: net.SslContext
 
 {.deprecated: [PAsyncHttpClient: AsyncHttpClient].}
 
 proc newAsyncHttpClient*(userAgent = defUserAgent,
-    maxRedirects = 5): AsyncHttpClient =
+    maxRedirects = 5, sslContext = defaultSslContext): AsyncHttpClient =
   ## Creates a new PAsyncHttpClient instance.
   ##
   ## ``userAgent`` specifies the user agent that will be used when making
@@ -456,10 +460,13 @@ proc newAsyncHttpClient*(userAgent = defUserAgent,
   ##
   ## ``maxRedirects`` specifies the maximum amount of redirects to follow,
   ## default is 5.
+  ##
+  ## ``sslContext`` specifies the SSL context to use for HTTPS requests.
   new result
   result.headers = newStringTable(modeCaseInsensitive)
   result.userAgent = defUserAgent
   result.maxRedirects = maxRedirects
+  result.sslContext = net.SslContext(sslContext)
 
 proc close*(client: AsyncHttpClient) =
   ## Closes any connections held by the HTTP client.
@@ -519,12 +526,13 @@ proc parseBody(client: PAsyncHttpClient,
     var contentLengthHeader = headers["Content-Length"]
     if contentLengthHeader != "":
       var length = contentLengthHeader.parseint()
-      result = await client.socket.recvFull(length)
-      if result == "":
-        httpError("Got disconnected while trying to read body.")
-      if result.len != length:
-        httpError("Received length doesn't match expected length. Wanted " &
-                  $length & " got " & $result.len)
+      if length > 0:
+        result = await client.socket.recvFull(length)
+        if result == "":
+          httpError("Got disconnected while trying to read body.")
+        if result.len != length:
+          httpError("Received length doesn't match expected length. Wanted " &
+                    $length & " got " & $result.len)
     else:
       # (http://tools.ietf.org/html/rfc2616#section-4.4) NR.4 TODO
       
@@ -590,14 +598,23 @@ proc newConnection(client: PAsyncHttpClient, url: TURL) {.async.} =
       client.currentURL.scheme != url.scheme:
     if client.connected: client.close()
     client.socket = newAsyncSocket()
-    if url.scheme == "https":
-      assert false, "TODO SSL"
 
     # TODO: I should be able to write 'net.TPort' here...
     let port =
-      if url.port == "": rawsockets.TPort(80)
+      if url.port == "":
+        if url.scheme.toLower() == "https":
+          rawsockets.TPort(443)
+        else:
+          rawsockets.TPort(80)
       else: rawsockets.TPort(url.port.parseInt)
     
+    if url.scheme.toLower() == "https":
+      when defined(ssl):
+        client.sslContext.wrapSocket(client.socket)
+      else:
+        raise newException(EHttpRequestErr,
+                  "SSL support is not available. Cannot connect over SSL.")
+    
     await client.socket.connect(url.hostname, port)
     client.currentURL = url
     client.connected = true