Merge pull request #1743 from cowboy-coders/httpclient_net_module

Switch httpclient to use net module instead of sockets
This commit is contained in:
Dominik Picheta 2014-12-18 00:58:35 +00:00
commit 2024ca454f

View file

@ -88,10 +88,9 @@
## constructor should be used for this purpose. However, ## constructor should be used for this purpose. However,
## currently only basic authentication is supported. ## currently only basic authentication is supported.
import sockets, strutils, parseurl, parseutils, strtabs, base64, os import net, strutils, uri, parseutils, strtabs, base64, os
import asyncnet, asyncdispatch import asyncnet, asyncdispatch
import rawsockets import rawsockets
from net import nil
type type
Response* = tuple[ Response* = tuple[
@ -101,7 +100,7 @@ type
body: string] body: string]
Proxy* = ref object Proxy* = ref object
url*: Url url*: Uri
auth*: string auth*: string
ProtocolError* = object of IOError ## exception that is raised when server ProtocolError* = object of IOError ## exception that is raised when server
@ -279,7 +278,7 @@ else:
proc newProxy*(url: string, auth = ""): Proxy = proc newProxy*(url: string, auth = ""): Proxy =
## Constructs a new ``TProxy`` object. ## Constructs a new ``TProxy`` object.
result = Proxy(url: parseUrl(url), auth: auth) result = Proxy(url: parseUri(url), auth: auth)
proc request*(url: string, httpMethod = httpGET, extraHeaders = "", proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
body = "", body = "",
@ -290,7 +289,7 @@ proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
## | Extra headers can be specified and must be seperated by ``\c\L`` ## | Extra headers can be specified and must be seperated by ``\c\L``
## | An optional timeout can be specified in miliseconds, if reading from the ## | An optional timeout can be specified in miliseconds, if reading from the
## server takes longer than specified an ETimeout exception will be raised. ## server takes longer than specified an ETimeout exception will be raised.
var r = if proxy == nil: parseUrl(url) else: proxy.url var r = if proxy == nil: parseUri(url) else: proxy.url
var headers = substr($httpMethod, len("http")) var headers = substr($httpMethod, len("http"))
if proxy == nil: if proxy == nil:
headers.add(" /" & r.path & r.query) headers.add(" /" & r.path & r.query)
@ -308,18 +307,18 @@ proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
add(headers, extraHeaders) add(headers, extraHeaders)
add(headers, "\c\L") add(headers, "\c\L")
var s = socket() var s = newSocket()
if s == invalidSocket: raiseOSError(osLastError()) if s == nil: raiseOSError(osLastError())
var port = sockets.Port(80) var port = net.Port(80)
if r.scheme == "https": if r.scheme == "https":
when defined(ssl): when defined(ssl):
sslContext.wrapSocket(s) sslContext.wrapSocket(s)
port = sockets.Port(443) port = net.Port(443)
else: else:
raise newException(HttpRequestError, raise newException(HttpRequestError,
"SSL support is not available. Cannot connect over SSL.") "SSL support is not available. Cannot connect over SSL.")
if r.port != "": if r.port != "":
port = sockets.Port(r.port.parseInt) port = net.Port(r.port.parseInt)
if timeout == -1: if timeout == -1:
s.connect(r.hostname, port) s.connect(r.hostname, port)
@ -342,9 +341,9 @@ proc getNewLocation(lastUrl: string, headers: StringTableRef): string =
result = headers["Location"] result = headers["Location"]
if result == "": httpError("location header expected") if result == "": httpError("location header expected")
# Relative URLs. (Not part of the spec, but soon will be.) # Relative URLs. (Not part of the spec, but soon will be.)
let r = parseURL(result) let r = parseUri(result)
if r.hostname == "" and r.path != "": if r.hostname == "" and r.path != "":
let origParsed = parseURL(lastUrl) let origParsed = parseUri(lastUrl)
result = origParsed.hostname & "/" & r.path result = origParsed.hostname & "/" & r.path
proc get*(url: string, extraHeaders = "", maxRedirects = 5, proc get*(url: string, extraHeaders = "", maxRedirects = 5,
@ -437,7 +436,7 @@ proc downloadFile*(url: string, outputFilename: string,
else: else:
fileError("Unable to open file") fileError("Unable to open file")
proc generateHeaders(r: Url, httpMethod: HttpMethod, proc generateHeaders(r: Uri, httpMethod: HttpMethod,
headers: StringTableRef): string = headers: StringTableRef): string =
result = substr($httpMethod, len("http")) result = substr($httpMethod, len("http"))
# TODO: Proxies # TODO: Proxies
@ -455,7 +454,7 @@ type
AsyncHttpClient* = ref object AsyncHttpClient* = ref object
socket: AsyncSocket socket: AsyncSocket
connected: bool connected: bool
currentURL: Url ## Where we are currently connected. currentURL: Uri ## Where we are currently connected.
headers*: StringTableRef headers*: StringTableRef
maxRedirects: int maxRedirects: int
userAgent: string userAgent: string
@ -499,7 +498,6 @@ proc recvFull(socket: AsyncSocket, size: int): Future[string] {.async.} =
proc parseChunks(client: AsyncHttpClient): Future[string] {.async.} = proc parseChunks(client: AsyncHttpClient): Future[string] {.async.} =
result = "" result = ""
var ri = 0
while true: while true:
var chunkSize = 0 var chunkSize = 0
var chunkSizeStr = await client.socket.recvLine() var chunkSizeStr = await client.socket.recvLine()
@ -607,7 +605,7 @@ proc parseResponse(client: AsyncHttpClient,
else: else:
result.body = "" result.body = ""
proc newConnection(client: AsyncHttpClient, url: Url) {.async.} = proc newConnection(client: AsyncHttpClient, url: Uri) {.async.} =
if client.currentURL.hostname != url.hostname or if client.currentURL.hostname != url.hostname or
client.currentURL.scheme != url.scheme: client.currentURL.scheme != url.scheme:
if client.connected: client.close() if client.connected: client.close()
@ -643,7 +641,7 @@ proc request*(client: AsyncHttpClient, url: string, httpMethod = httpGET,
## connection can be closed by using the ``close`` procedure. ## connection can be closed by using the ``close`` procedure.
## ##
## The returned future will complete once the request is completed. ## The returned future will complete once the request is completed.
let r = parseUrl(url) let r = parseUri(url)
await newConnection(client, r) await newConnection(client, r)
if not client.headers.hasKey("user-agent") and client.userAgent != "": if not client.headers.hasKey("user-agent") and client.userAgent != "":