mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-08 05:53:22 +00:00
Merge pull request #1653 from def-/name-fixes-2
Fix some deprecation warnings caused by renames
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
|
||||
{.deadCodeElim:on.}
|
||||
|
||||
from posix import TSocketHandle
|
||||
from posix import SocketHandle
|
||||
|
||||
const
|
||||
EPOLLIN* = 0x00000001
|
||||
@@ -58,7 +58,7 @@ proc epoll_create1*(flags: cint): cint {.importc: "epoll_create1",
|
||||
## Same as epoll_create but with an FLAGS parameter. The unused SIZE
|
||||
## parameter has been dropped.
|
||||
|
||||
proc epoll_ctl*(epfd: cint; op: cint; fd: cint | TSocketHandle; event: ptr epoll_event): cint {.
|
||||
proc epoll_ctl*(epfd: cint; op: cint; fd: cint | SocketHandle; event: ptr epoll_event): cint {.
|
||||
importc: "epoll_ctl", header: "<sys/epoll.h>".}
|
||||
## Manipulate an epoll instance "epfd". Returns 0 in case of success,
|
||||
## -1 in case of error ( the "errno" variable will contain the
|
||||
|
||||
@@ -242,7 +242,7 @@ proc echoOriginalStackTrace[T](future: Future[T]) =
|
||||
|
||||
proc read*[T](future: Future[T]): T =
|
||||
## Retrieves the value of ``future``. Future must be finished otherwise
|
||||
## this function will fail with a ``EInvalidValue`` exception.
|
||||
## this function will fail with a ``ValueError`` exception.
|
||||
##
|
||||
## If the result of the future is an error then that error will be raised.
|
||||
if future.finished:
|
||||
@@ -808,13 +808,13 @@ else:
|
||||
TAsyncFD* = distinct cint
|
||||
TCallback = proc (fd: TAsyncFD): bool {.closure,gcsafe.}
|
||||
|
||||
PData* = ref object of PObject
|
||||
PData* = ref object of RootRef
|
||||
fd: TAsyncFD
|
||||
readCBs: seq[TCallback]
|
||||
writeCBs: seq[TCallback]
|
||||
|
||||
PDispatcher* = ref object of PDispatcherBase
|
||||
selector: PSelector
|
||||
selector: Selector
|
||||
|
||||
proc `==`*(x, y: TAsyncFD): bool {.borrow.}
|
||||
|
||||
@@ -828,7 +828,7 @@ else:
|
||||
if gDisp.isNil: gDisp = newDispatcher()
|
||||
result = gDisp
|
||||
|
||||
proc update(fd: TAsyncFD, events: set[TEvent]) =
|
||||
proc update(fd: TAsyncFD, events: set[Event]) =
|
||||
let p = getGlobalDispatcher()
|
||||
assert fd.SocketHandle in p.selector
|
||||
discard p.selector.update(fd.SocketHandle, events)
|
||||
@@ -836,16 +836,16 @@ else:
|
||||
proc register*(fd: TAsyncFD) =
|
||||
let p = getGlobalDispatcher()
|
||||
var data = PData(fd: fd, readCBs: @[], writeCBs: @[])
|
||||
p.selector.register(fd.SocketHandle, {}, data.PObject)
|
||||
p.selector.register(fd.SocketHandle, {}, data.RootRef)
|
||||
|
||||
proc newAsyncRawSocket*(domain: cint, typ: cint, protocol: cint): TAsyncFD =
|
||||
result = newRawSocket(domain, typ, protocol).TAsyncFD
|
||||
result.SocketHandle.setBlocking(false)
|
||||
register(result)
|
||||
|
||||
proc newAsyncRawSocket*(domain: TDomain = AF_INET,
|
||||
typ: TType = SOCK_STREAM,
|
||||
protocol: TProtocol = IPPROTO_TCP): TAsyncFD =
|
||||
proc newAsyncRawSocket*(domain: Domain = AF_INET,
|
||||
typ: SockType = SOCK_STREAM,
|
||||
protocol: Protocol = IPPROTO_TCP): TAsyncFD =
|
||||
result = newRawSocket(domain, typ, protocol).TAsyncFD
|
||||
result.SocketHandle.setBlocking(false)
|
||||
register(result)
|
||||
@@ -861,14 +861,14 @@ else:
|
||||
proc addRead*(fd: TAsyncFD, cb: TCallback) =
|
||||
let p = getGlobalDispatcher()
|
||||
if fd.SocketHandle notin p.selector:
|
||||
raise newException(EInvalidValue, "File descriptor not registered.")
|
||||
raise newException(ValueError, "File descriptor not registered.")
|
||||
p.selector[fd.SocketHandle].data.PData.readCBs.add(cb)
|
||||
update(fd, p.selector[fd.SocketHandle].events + {EvRead})
|
||||
|
||||
proc addWrite*(fd: TAsyncFD, cb: TCallback) =
|
||||
let p = getGlobalDispatcher()
|
||||
if fd.SocketHandle notin p.selector:
|
||||
raise newException(EInvalidValue, "File descriptor not registered.")
|
||||
raise newException(ValueError, "File descriptor not registered.")
|
||||
p.selector[fd.SocketHandle].data.PData.writeCBs.add(cb)
|
||||
update(fd, p.selector[fd.SocketHandle].events + {EvWrite})
|
||||
|
||||
@@ -898,7 +898,7 @@ else:
|
||||
data.writeCBs.add(cb)
|
||||
|
||||
if info.key in p.selector:
|
||||
var newEvents: set[TEvent]
|
||||
var newEvents: set[Event]
|
||||
if data.readCBs.len != 0: newEvents = {EvRead}
|
||||
if data.writeCBs.len != 0: newEvents = newEvents + {EvWrite}
|
||||
if newEvents != info.key.events:
|
||||
@@ -910,7 +910,7 @@ else:
|
||||
|
||||
processTimers(p)
|
||||
|
||||
proc connect*(socket: TAsyncFD, address: string, port: TPort,
|
||||
proc connect*(socket: TAsyncFD, address: string, port: Port,
|
||||
af = AF_INET): Future[void] =
|
||||
var retFuture = newFuture[void]("connect")
|
||||
|
||||
@@ -921,7 +921,7 @@ else:
|
||||
|
||||
var aiList = getAddrInfo(address, port, af)
|
||||
var success = false
|
||||
var lastError: TOSErrorCode
|
||||
var lastError: OSErrorCode
|
||||
var it = aiList
|
||||
while it != nil:
|
||||
var ret = connect(socket.SocketHandle, it.ai_addr, it.ai_addrlen.Socklen)
|
||||
@@ -942,11 +942,11 @@ else:
|
||||
|
||||
dealloc(aiList)
|
||||
if not success:
|
||||
retFuture.fail(newException(EOS, osErrorMsg(lastError)))
|
||||
retFuture.fail(newException(OSError, osErrorMsg(lastError)))
|
||||
return retFuture
|
||||
|
||||
proc recv*(socket: TAsyncFD, size: int,
|
||||
flags = {TSocketFlags.SafeDisconn}): Future[string] =
|
||||
flags = {SocketFlag.SafeDisconn}): Future[string] =
|
||||
var retFuture = newFuture[string]("recv")
|
||||
|
||||
var readBuffer = newString(size)
|
||||
@@ -962,7 +962,7 @@ else:
|
||||
if flags.isDisconnectionError(lastError):
|
||||
retFuture.complete("")
|
||||
else:
|
||||
retFuture.fail(newException(EOS, osErrorMsg(lastError)))
|
||||
retFuture.fail(newException(OSError, osErrorMsg(lastError)))
|
||||
else:
|
||||
result = false # We still want this callback to be called.
|
||||
elif res == 0:
|
||||
@@ -977,7 +977,7 @@ else:
|
||||
return retFuture
|
||||
|
||||
proc send*(socket: TAsyncFD, data: string,
|
||||
flags = {TSocketFlags.SafeDisconn}): Future[void] =
|
||||
flags = {SocketFlag.SafeDisconn}): Future[void] =
|
||||
var retFuture = newFuture[void]("send")
|
||||
|
||||
var written = 0
|
||||
@@ -994,7 +994,7 @@ else:
|
||||
if flags.isDisconnectionError(lastError):
|
||||
retFuture.complete()
|
||||
else:
|
||||
retFuture.fail(newException(EOS, osErrorMsg(lastError)))
|
||||
retFuture.fail(newException(OSError, osErrorMsg(lastError)))
|
||||
else:
|
||||
result = false # We still want this callback to be called.
|
||||
else:
|
||||
@@ -1008,7 +1008,7 @@ else:
|
||||
addWrite(socket, cb)
|
||||
return retFuture
|
||||
|
||||
proc acceptAddr*(socket: TAsyncFD, flags = {TSocketFlags.SafeDisconn}):
|
||||
proc acceptAddr*(socket: TAsyncFD, flags = {SocketFlag.SafeDisconn}):
|
||||
Future[tuple[address: string, client: TAsyncFD]] =
|
||||
var retFuture = newFuture[tuple[address: string,
|
||||
client: TAsyncFD]]("acceptAddr")
|
||||
@@ -1027,7 +1027,7 @@ else:
|
||||
if flags.isDisconnectionError(lastError):
|
||||
return false
|
||||
else:
|
||||
retFuture.fail(newException(EOS, osErrorMsg(lastError)))
|
||||
retFuture.fail(newException(OSError, osErrorMsg(lastError)))
|
||||
else:
|
||||
register(client.TAsyncFD)
|
||||
retFuture.complete(($inet_ntoa(sockAddress.sin_addr), client.TAsyncFD))
|
||||
@@ -1302,7 +1302,7 @@ macro async*(prc: stmt): stmt {.immediate.} =
|
||||
outerProcBody.add(closureIterator)
|
||||
|
||||
# -> createCb(retFuture)
|
||||
var cbName = newIdentNode("cb")
|
||||
#var cbName = newIdentNode("cb")
|
||||
var procCb = newCall(bindSym"createCb", retFutureSym, iteratorNameSym,
|
||||
newStrLitNode(prc[0].getName))
|
||||
outerProcBody.add procCb
|
||||
@@ -1372,7 +1372,7 @@ proc runForever*() =
|
||||
while true:
|
||||
poll()
|
||||
|
||||
proc waitFor*[T](fut: PFuture[T]): T =
|
||||
proc waitFor*[T](fut: Future[T]): T =
|
||||
## **Blocks** the current thread until the specified future completes.
|
||||
while not fut.finished:
|
||||
poll()
|
||||
|
||||
@@ -180,10 +180,10 @@ proc asyncSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM,
|
||||
if result.socket == invalidSocket: raiseOSError(osLastError())
|
||||
result.socket.setBlocking(false)
|
||||
|
||||
proc toAsyncSocket*(sock: Socket, state: SocketStatus = SockConnected): PAsyncSocket =
|
||||
## Wraps an already initialized ``TSocket`` into a PAsyncSocket.
|
||||
proc toAsyncSocket*(sock: Socket, state: SocketStatus = SockConnected): AsyncSocket =
|
||||
## Wraps an already initialized ``TSocket`` into a AsyncSocket.
|
||||
## This is useful if you want to use an already connected TSocket as an
|
||||
## asynchronous PAsyncSocket in asyncio's event loop.
|
||||
## asynchronous AsyncSocket in asyncio's event loop.
|
||||
##
|
||||
## ``state`` may be overriden, i.e. if ``sock`` is not connected it should be
|
||||
## adjusted properly. By default it will be assumed that the socket is
|
||||
@@ -201,7 +201,7 @@ proc toAsyncSocket*(sock: Socket, state: SocketStatus = SockConnected): PAsyncSo
|
||||
## SockUDPBound Socket is a UDP socket which is listening for data.
|
||||
## ================ ================================================================
|
||||
##
|
||||
## **Warning**: If ``state`` is set incorrectly the resulting ``PAsyncSocket``
|
||||
## **Warning**: If ``state`` is set incorrectly the resulting ``AsyncSocket``
|
||||
## object may not work properly.
|
||||
##
|
||||
## **Note**: This will set ``sock`` to be non-blocking.
|
||||
@@ -213,8 +213,8 @@ proc toAsyncSocket*(sock: Socket, state: SocketStatus = SockConnected): PAsyncSo
|
||||
|
||||
proc asyncSockHandleRead(h: RootRef) =
|
||||
when defined(ssl):
|
||||
if PAsyncSocket(h).socket.isSSL and not
|
||||
PAsyncSocket(h).socket.gotHandshake:
|
||||
if AsyncSocket(h).socket.isSSL and not
|
||||
AsyncSocket(h).socket.gotHandshake:
|
||||
return
|
||||
|
||||
if AsyncSocket(h).info != SockListening:
|
||||
@@ -226,8 +226,8 @@ proc asyncSockHandleRead(h: RootRef) =
|
||||
proc close*(sock: AsyncSocket) {.gcsafe.}
|
||||
proc asyncSockHandleWrite(h: RootRef) =
|
||||
when defined(ssl):
|
||||
if PAsyncSocket(h).socket.isSSL and not
|
||||
PAsyncSocket(h).socket.gotHandshake:
|
||||
if AsyncSocket(h).socket.isSSL and not
|
||||
AsyncSocket(h).socket.gotHandshake:
|
||||
return
|
||||
|
||||
if AsyncSocket(h).info == SockConnecting:
|
||||
@@ -266,17 +266,17 @@ proc asyncSockHandleWrite(h: RootRef) =
|
||||
|
||||
when defined(ssl):
|
||||
proc asyncSockDoHandshake(h: PObject) {.gcsafe.} =
|
||||
if PAsyncSocket(h).socket.isSSL and not
|
||||
PAsyncSocket(h).socket.gotHandshake:
|
||||
if PAsyncSocket(h).sslNeedAccept:
|
||||
if AsyncSocket(h).socket.isSSL and not
|
||||
AsyncSocket(h).socket.gotHandshake:
|
||||
if AsyncSocket(h).sslNeedAccept:
|
||||
var d = ""
|
||||
let ret = PAsyncSocket(h).socket.acceptAddrSSL(PAsyncSocket(h).socket, d)
|
||||
let ret = AsyncSocket(h).socket.acceptAddrSSL(AsyncSocket(h).socket, d)
|
||||
assert ret != AcceptNoClient
|
||||
if ret == AcceptSuccess:
|
||||
PAsyncSocket(h).info = SockConnected
|
||||
AsyncSocket(h).info = SockConnected
|
||||
else:
|
||||
# handshake will set socket's ``sslNoHandshake`` field.
|
||||
discard PAsyncSocket(h).socket.handshake()
|
||||
discard AsyncSocket(h).socket.handshake()
|
||||
|
||||
|
||||
proc asyncSockTask(h: RootRef) =
|
||||
@@ -453,7 +453,7 @@ proc setHandleWrite*(s: AsyncSocket,
|
||||
##
|
||||
## To remove this event you should use the ``delHandleWrite`` function.
|
||||
## It is advised to use that function instead of just setting the event to
|
||||
## ``proc (s: PAsyncSocket) = nil`` as that would mean that that function
|
||||
## ``proc (s: AsyncSocket) = nil`` as that would mean that that function
|
||||
## would be called constantly.
|
||||
s.deleg.mode = fmReadWrite
|
||||
s.handleWrite = handleWrite
|
||||
@@ -655,10 +655,10 @@ proc len*(disp: Dispatcher): int =
|
||||
|
||||
when isMainModule:
|
||||
|
||||
proc testConnect(s: PAsyncSocket, no: int) =
|
||||
proc testConnect(s: AsyncSocket, no: int) =
|
||||
echo("Connected! " & $no)
|
||||
|
||||
proc testRead(s: PAsyncSocket, no: int) =
|
||||
proc testRead(s: AsyncSocket, no: int) =
|
||||
echo("Reading! " & $no)
|
||||
var data = ""
|
||||
if not s.readLine(data): return
|
||||
@@ -668,15 +668,15 @@ when isMainModule:
|
||||
echo(data)
|
||||
echo("Finished reading! " & $no)
|
||||
|
||||
proc testAccept(s: PAsyncSocket, disp: PDispatcher, no: int) =
|
||||
proc testAccept(s: AsyncSocket, disp: PDispatcher, no: int) =
|
||||
echo("Accepting client! " & $no)
|
||||
var client: PAsyncSocket
|
||||
var client: AsyncSocket
|
||||
new(client)
|
||||
var address = ""
|
||||
s.acceptAddr(client, address)
|
||||
echo("Accepted ", address)
|
||||
client.handleRead =
|
||||
proc (s: PAsyncSocket) =
|
||||
proc (s: AsyncSocket) =
|
||||
testRead(s, 2)
|
||||
disp.register(client)
|
||||
|
||||
@@ -686,16 +686,16 @@ when isMainModule:
|
||||
var s = asyncSocket()
|
||||
s.connect("amber.tenthbit.net", TPort(6667))
|
||||
s.handleConnect =
|
||||
proc (s: PAsyncSocket) =
|
||||
proc (s: AsyncSocket) =
|
||||
testConnect(s, 1)
|
||||
s.handleRead =
|
||||
proc (s: PAsyncSocket) =
|
||||
proc (s: AsyncSocket) =
|
||||
testRead(s, 1)
|
||||
d.register(s)
|
||||
|
||||
var server = asyncSocket()
|
||||
server.handleAccept =
|
||||
proc (s: PAsyncSocket) =
|
||||
proc (s: AsyncSocket) =
|
||||
testAccept(s, d, 78)
|
||||
server.bindAddr(TPort(5555))
|
||||
server.listen()
|
||||
|
||||
@@ -67,7 +67,7 @@ when defined(ssl):
|
||||
|
||||
type
|
||||
# TODO: I would prefer to just do:
|
||||
# PAsyncSocket* {.borrow: `.`.} = distinct PSocket. But that doesn't work.
|
||||
# AsyncSocket* {.borrow: `.`.} = distinct Socket. But that doesn't work.
|
||||
AsyncSocketDesc = object
|
||||
fd*: SocketHandle
|
||||
closed*: bool ## determines whether this socket has been closed
|
||||
@@ -91,7 +91,7 @@ type
|
||||
|
||||
# TODO: Save AF, domain etc info and reuse it in procs which need it like connect.
|
||||
|
||||
proc newSocket(fd: TAsyncFD, isBuff: bool): PAsyncSocket =
|
||||
proc newSocket(fd: TAsyncFD, isBuff: bool): AsyncSocket =
|
||||
assert fd != osInvalidSocket.TAsyncFD
|
||||
new(result)
|
||||
result.fd = fd.SocketHandle
|
||||
@@ -99,12 +99,12 @@ proc newSocket(fd: TAsyncFD, isBuff: bool): PAsyncSocket =
|
||||
if isBuff:
|
||||
result.currPos = 0
|
||||
|
||||
proc newAsyncSocket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM,
|
||||
protocol: TProtocol = IPPROTO_TCP, buffered = true): PAsyncSocket =
|
||||
proc newAsyncSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM,
|
||||
protocol: Protocol = IPPROTO_TCP, buffered = true): AsyncSocket =
|
||||
## Creates a new asynchronous socket.
|
||||
result = newSocket(newAsyncRawSocket(domain, typ, protocol), buffered)
|
||||
|
||||
proc newAsyncSocket*(domain, typ, protocol: cint, buffered = true): PAsyncSocket =
|
||||
proc newAsyncSocket*(domain, typ, protocol: cint, buffered = true): AsyncSocket =
|
||||
## Creates a new asynchronous socket.
|
||||
result = newSocket(newAsyncRawSocket(domain, typ, protocol), buffered)
|
||||
|
||||
@@ -126,7 +126,7 @@ when defined(ssl):
|
||||
else: raiseSSLError("Unknown Error")
|
||||
|
||||
proc sendPendingSslData(socket: AsyncSocket,
|
||||
flags: set[TSocketFlags]) {.async.} =
|
||||
flags: set[SocketFlag]) {.async.} =
|
||||
let len = bioCtrlPending(socket.bioOut)
|
||||
if len > 0:
|
||||
var data = newStringOfCap(len)
|
||||
@@ -137,7 +137,7 @@ when defined(ssl):
|
||||
data.setLen(read)
|
||||
await socket.fd.TAsyncFd.send(data, flags)
|
||||
|
||||
proc appeaseSsl(socket: AsyncSocket, flags: set[TSocketFlags],
|
||||
proc appeaseSsl(socket: AsyncSocket, flags: set[SocketFlag],
|
||||
sslError: cint) {.async.} =
|
||||
case sslError
|
||||
of SSL_ERROR_WANT_WRITE:
|
||||
@@ -150,7 +150,7 @@ when defined(ssl):
|
||||
else:
|
||||
raiseSSLError("Cannot appease SSL.")
|
||||
|
||||
template sslLoop(socket: AsyncSocket, flags: set[TSocketFlags],
|
||||
template sslLoop(socket: AsyncSocket, flags: set[SocketFlag],
|
||||
op: expr) =
|
||||
var opResult {.inject.} = -1.cint
|
||||
while opResult < 0:
|
||||
@@ -162,21 +162,21 @@ when defined(ssl):
|
||||
let err = getSslError(socket.sslHandle, opResult.cint)
|
||||
yield appeaseSsl(socket, flags, err.cint)
|
||||
|
||||
proc connect*(socket: PAsyncSocket, address: string, port: TPort,
|
||||
proc connect*(socket: AsyncSocket, address: string, port: Port,
|
||||
af = AF_INET) {.async.} =
|
||||
## Connects ``socket`` to server at ``address:port``.
|
||||
##
|
||||
## Returns a ``Future`` which will complete when the connection succeeds
|
||||
## or an error occurs.
|
||||
await connect(socket.fd.TAsyncFD, address, port, af)
|
||||
let flags = {TSocketFlags.SafeDisconn}
|
||||
if socket.isSsl:
|
||||
when defined(ssl):
|
||||
let flags = {SocketFlag.SafeDisconn}
|
||||
sslSetConnectState(socket.sslHandle)
|
||||
sslLoop(socket, flags, sslDoHandshake(socket.sslHandle))
|
||||
|
||||
proc readInto(buf: cstring, size: int, socket: PAsyncSocket,
|
||||
flags: set[TSocketFlags]): Future[int] {.async.} =
|
||||
proc readInto(buf: cstring, size: int, socket: AsyncSocket,
|
||||
flags: set[SocketFlag]): Future[int] {.async.} =
|
||||
if socket.isSsl:
|
||||
when defined(ssl):
|
||||
# SSL mode.
|
||||
@@ -190,14 +190,14 @@ proc readInto(buf: cstring, size: int, socket: PAsyncSocket,
|
||||
# Not in SSL mode.
|
||||
result = data.len
|
||||
|
||||
proc readIntoBuf(socket: PAsyncSocket,
|
||||
flags: set[TSocketFlags]): Future[int] {.async.} =
|
||||
proc readIntoBuf(socket: AsyncSocket,
|
||||
flags: set[SocketFlag]): Future[int] {.async.} =
|
||||
result = await readInto(addr socket.buffer[0], BufferSize, socket, flags)
|
||||
socket.currPos = 0
|
||||
socket.bufLen = result
|
||||
|
||||
proc recv*(socket: PAsyncSocket, size: int,
|
||||
flags = {TSocketFlags.SafeDisconn}): Future[string] {.async.} =
|
||||
proc recv*(socket: AsyncSocket, size: int,
|
||||
flags = {SocketFlag.SafeDisconn}): Future[string] {.async.} =
|
||||
## Reads **up to** ``size`` bytes from ``socket``.
|
||||
##
|
||||
## For buffered sockets this function will attempt to read all the requested
|
||||
@@ -218,7 +218,7 @@ proc recv*(socket: PAsyncSocket, size: int,
|
||||
let originalBufPos = socket.currPos
|
||||
|
||||
if socket.bufLen == 0:
|
||||
let res = await socket.readIntoBuf(flags - {TSocketFlags.Peek})
|
||||
let res = await socket.readIntoBuf(flags - {SocketFlag.Peek})
|
||||
if res == 0:
|
||||
result.setLen(0)
|
||||
return
|
||||
@@ -226,10 +226,10 @@ proc recv*(socket: PAsyncSocket, size: int,
|
||||
var read = 0
|
||||
while read < size:
|
||||
if socket.currPos >= socket.bufLen:
|
||||
if TSocketFlags.Peek in flags:
|
||||
if SocketFlag.Peek in flags:
|
||||
# We don't want to get another buffer if we're peeking.
|
||||
break
|
||||
let res = await socket.readIntoBuf(flags - {TSocketFlags.Peek})
|
||||
let res = await socket.readIntoBuf(flags - {SocketFlag.Peek})
|
||||
if res == 0:
|
||||
break
|
||||
|
||||
@@ -238,7 +238,7 @@ proc recv*(socket: PAsyncSocket, size: int,
|
||||
read.inc(chunk)
|
||||
socket.currPos.inc(chunk)
|
||||
|
||||
if TSocketFlags.Peek in flags:
|
||||
if SocketFlag.Peek in flags:
|
||||
# Restore old buffer cursor position.
|
||||
socket.currPos = originalBufPos
|
||||
result.setLen(read)
|
||||
@@ -247,8 +247,8 @@ proc recv*(socket: PAsyncSocket, size: int,
|
||||
let read = await readInto(addr result[0], size, socket, flags)
|
||||
result.setLen(read)
|
||||
|
||||
proc send*(socket: PAsyncSocket, data: string,
|
||||
flags = {TSocketFlags.SafeDisconn}) {.async.} =
|
||||
proc send*(socket: AsyncSocket, data: string,
|
||||
flags = {SocketFlag.SafeDisconn}) {.async.} =
|
||||
## Sends ``data`` to ``socket``. The returned future will complete once all
|
||||
## data has been sent.
|
||||
assert socket != nil
|
||||
@@ -261,12 +261,12 @@ proc send*(socket: PAsyncSocket, data: string,
|
||||
else:
|
||||
await send(socket.fd.TAsyncFD, data, flags)
|
||||
|
||||
proc acceptAddr*(socket: PAsyncSocket, flags = {TSocketFlags.SafeDisconn}):
|
||||
Future[tuple[address: string, client: PAsyncSocket]] =
|
||||
proc acceptAddr*(socket: AsyncSocket, flags = {SocketFlag.SafeDisconn}):
|
||||
Future[tuple[address: string, client: AsyncSocket]] =
|
||||
## Accepts a new connection. Returns a future containing the client socket
|
||||
## corresponding to that connection and the remote address of the client.
|
||||
## The future will complete when the connection is successfully accepted.
|
||||
var retFuture = newFuture[tuple[address: string, client: PAsyncSocket]]("asyncnet.acceptAddr")
|
||||
var retFuture = newFuture[tuple[address: string, client: AsyncSocket]]("asyncnet.acceptAddr")
|
||||
var fut = acceptAddr(socket.fd.TAsyncFD, flags)
|
||||
fut.callback =
|
||||
proc (future: Future[tuple[address: string, client: TAsyncFD]]) =
|
||||
@@ -279,15 +279,15 @@ proc acceptAddr*(socket: PAsyncSocket, flags = {TSocketFlags.SafeDisconn}):
|
||||
retFuture.complete(resultTup)
|
||||
return retFuture
|
||||
|
||||
proc accept*(socket: PAsyncSocket,
|
||||
flags = {TSocketFlags.SafeDisconn}): Future[PAsyncSocket] =
|
||||
proc accept*(socket: AsyncSocket,
|
||||
flags = {SocketFlag.SafeDisconn}): Future[AsyncSocket] =
|
||||
## Accepts a new connection. Returns a future containing the client socket
|
||||
## corresponding to that connection.
|
||||
## The future will complete when the connection is successfully accepted.
|
||||
var retFut = newFuture[PAsyncSocket]("asyncnet.accept")
|
||||
var retFut = newFuture[AsyncSocket]("asyncnet.accept")
|
||||
var fut = acceptAddr(socket, flags)
|
||||
fut.callback =
|
||||
proc (future: Future[tuple[address: string, client: PAsyncSocket]]) =
|
||||
proc (future: Future[tuple[address: string, client: AsyncSocket]]) =
|
||||
assert future.finished
|
||||
if future.failed:
|
||||
retFut.fail(future.readError)
|
||||
@@ -295,8 +295,8 @@ proc accept*(socket: PAsyncSocket,
|
||||
retFut.complete(future.read.client)
|
||||
return retFut
|
||||
|
||||
proc recvLine*(socket: PAsyncSocket,
|
||||
flags = {TSocketFlags.SafeDisconn}): Future[string] {.async.} =
|
||||
proc recvLine*(socket: AsyncSocket,
|
||||
flags = {SocketFlag.SafeDisconn}): Future[string] {.async.} =
|
||||
## Reads a line of data from ``socket``. Returned future will complete once
|
||||
## a full line is read or an error occurs.
|
||||
##
|
||||
@@ -317,7 +317,7 @@ proc recvLine*(socket: PAsyncSocket,
|
||||
template addNLIfEmpty(): stmt =
|
||||
if result.len == 0:
|
||||
result.add("\c\L")
|
||||
assert TSocketFlags.Peek notin flags ## TODO:
|
||||
assert SocketFlag.Peek notin flags ## TODO:
|
||||
if socket.isBuffered:
|
||||
result = ""
|
||||
if socket.bufLen == 0:
|
||||
@@ -365,7 +365,7 @@ proc recvLine*(socket: PAsyncSocket,
|
||||
return
|
||||
add(result.string, c)
|
||||
|
||||
proc listen*(socket: PAsyncSocket, backlog = SOMAXCONN) {.tags: [ReadIOEffect].} =
|
||||
proc listen*(socket: AsyncSocket, backlog = SOMAXCONN) {.tags: [ReadIOEffect].} =
|
||||
## Marks ``socket`` as accepting connections.
|
||||
## ``Backlog`` specifies the maximum length of the
|
||||
## queue of pending connections.
|
||||
@@ -373,7 +373,7 @@ proc listen*(socket: PAsyncSocket, backlog = SOMAXCONN) {.tags: [ReadIOEffect].}
|
||||
## Raises an EOS error upon failure.
|
||||
if listen(socket.fd, backlog) < 0'i32: raiseOSError(osLastError())
|
||||
|
||||
proc bindAddr*(socket: PAsyncSocket, port = Port(0), address = "") {.
|
||||
proc bindAddr*(socket: AsyncSocket, port = Port(0), address = "") {.
|
||||
tags: [ReadIOEffect].} =
|
||||
## Binds ``address``:``port`` to the socket.
|
||||
##
|
||||
@@ -397,7 +397,7 @@ proc bindAddr*(socket: PAsyncSocket, port = Port(0), address = "") {.
|
||||
raiseOSError(osLastError())
|
||||
dealloc(aiList)
|
||||
|
||||
proc close*(socket: PAsyncSocket) =
|
||||
proc close*(socket: AsyncSocket) =
|
||||
## Closes the socket.
|
||||
socket.fd.TAsyncFD.closeSocket()
|
||||
when defined(ssl):
|
||||
@@ -419,7 +419,7 @@ when defined(ssl):
|
||||
## prone to security vulnerabilities.
|
||||
socket.isSsl = true
|
||||
socket.sslContext = ctx
|
||||
socket.sslHandle = SSLNew(PSSLCTX(socket.sslContext))
|
||||
socket.sslHandle = SSLNew(SSLCTX(socket.sslContext))
|
||||
if socket.sslHandle == nil:
|
||||
raiseSslError()
|
||||
|
||||
@@ -449,7 +449,7 @@ when isMainModule:
|
||||
when test == HighClient:
|
||||
proc main() {.async.} =
|
||||
var sock = newAsyncSocket()
|
||||
await sock.connect("irc.freenode.net", TPort(6667))
|
||||
await sock.connect("irc.freenode.net", Port(6667))
|
||||
while true:
|
||||
let line = await sock.recvLine()
|
||||
if line == "":
|
||||
@@ -460,7 +460,7 @@ when isMainModule:
|
||||
asyncCheck main()
|
||||
elif test == LowClient:
|
||||
var sock = newAsyncSocket()
|
||||
var f = connect(sock, "irc.freenode.net", TPort(6667))
|
||||
var f = connect(sock, "irc.freenode.net", Port(6667))
|
||||
f.callback =
|
||||
proc (future: Future[void]) =
|
||||
echo("Connected in future!")
|
||||
@@ -471,9 +471,9 @@ when isMainModule:
|
||||
echo("Read ", future.read.len, ": ", future.read.repr)
|
||||
elif test == LowServer:
|
||||
var sock = newAsyncSocket()
|
||||
sock.bindAddr(TPort(6667))
|
||||
sock.bindAddr(Port(6667))
|
||||
sock.listen()
|
||||
proc onAccept(future: Future[PAsyncSocket]) =
|
||||
proc onAccept(future: Future[AsyncSocket]) =
|
||||
let client = future.read
|
||||
echo "Accepted ", client.fd.cint
|
||||
var t = send(client, "test\c\L")
|
||||
|
||||
@@ -18,17 +18,17 @@ type
|
||||
|
||||
{.deprecated: [TQueue: Queue].}
|
||||
|
||||
proc initQueue*[T](initialSize=4): TQueue[T] =
|
||||
proc initQueue*[T](initialSize=4): Queue[T] =
|
||||
## creates a new queue. `initialSize` needs to be a power of 2.
|
||||
assert isPowerOfTwo(initialSize)
|
||||
result.mask = initialSize-1
|
||||
newSeq(result.data, initialSize)
|
||||
|
||||
proc len*[T](q: TQueue[T]): int =
|
||||
proc len*[T](q: Queue[T]): int =
|
||||
## returns the number of elements of `q`.
|
||||
result = q.count
|
||||
|
||||
iterator items*[T](q: TQueue[T]): T =
|
||||
iterator items*[T](q: Queue[T]): T =
|
||||
## yields every element of `q`.
|
||||
var i = q.rd
|
||||
var c = q.count
|
||||
@@ -37,7 +37,7 @@ iterator items*[T](q: TQueue[T]): T =
|
||||
yield q.data[i]
|
||||
i = (i + 1) and q.mask
|
||||
|
||||
proc add*[T](q: var TQueue[T], item: T) =
|
||||
proc add*[T](q: var Queue[T], item: T) =
|
||||
## adds an `item` to the end of the queue `q`.
|
||||
var cap = q.mask+1
|
||||
if q.count >= cap:
|
||||
@@ -55,18 +55,18 @@ proc add*[T](q: var TQueue[T], item: T) =
|
||||
q.data[q.wr] = item
|
||||
q.wr = (q.wr + 1) and q.mask
|
||||
|
||||
proc enqueue*[T](q: var TQueue[T], item: T) =
|
||||
proc enqueue*[T](q: var Queue[T], item: T) =
|
||||
## alias for the ``add`` operation.
|
||||
add(q, item)
|
||||
|
||||
proc dequeue*[T](q: var TQueue[T]): T =
|
||||
proc dequeue*[T](q: var Queue[T]): T =
|
||||
## removes and returns the first element of the queue `q`.
|
||||
assert q.count > 0
|
||||
dec q.count
|
||||
result = q.data[q.rd]
|
||||
q.rd = (q.rd + 1) and q.mask
|
||||
|
||||
proc `$`*[T](q: TQueue[T]): string =
|
||||
proc `$`*[T](q: Queue[T]): string =
|
||||
## turns a queue into its string representation.
|
||||
result = "["
|
||||
for x in items(q):
|
||||
|
||||
@@ -57,7 +57,7 @@ proc advice*(s: var ThreadPoolState): ThreadPoolAdvice =
|
||||
s.prevProcKernel = procKernel
|
||||
s.prevProcUser = procUser
|
||||
elif defined(linux):
|
||||
proc fscanf(c: TFile, frmt: cstring) {.varargs, importc,
|
||||
proc fscanf(c: File, frmt: cstring) {.varargs, importc,
|
||||
header: "<stdio.h>".}
|
||||
|
||||
var f = open("/proc/loadavg")
|
||||
|
||||
@@ -101,7 +101,7 @@ type
|
||||
body: string]
|
||||
|
||||
Proxy* = ref object
|
||||
url*: TUrl
|
||||
url*: Url
|
||||
auth*: string
|
||||
|
||||
ProtocolError* = object of IOError ## exception that is raised when server
|
||||
@@ -130,7 +130,7 @@ proc fileError(msg: string) =
|
||||
e.msg = msg
|
||||
raise e
|
||||
|
||||
proc parseChunks(s: TSocket, timeout: int): string =
|
||||
proc parseChunks(s: Socket, timeout: int): string =
|
||||
result = ""
|
||||
var ri = 0
|
||||
while true:
|
||||
@@ -168,7 +168,7 @@ proc parseChunks(s: TSocket, timeout: int): string =
|
||||
# Trailer headers will only be sent if the request specifies that we want
|
||||
# them: http://tools.ietf.org/html/rfc2616#section-3.6.1
|
||||
|
||||
proc parseBody(s: TSocket, headers: PStringTable, timeout: int): string =
|
||||
proc parseBody(s: Socket, headers: StringTableRef, timeout: int): string =
|
||||
result = ""
|
||||
if headers["Transfer-Encoding"] == "chunked":
|
||||
result = parseChunks(s, timeout)
|
||||
@@ -203,7 +203,7 @@ proc parseBody(s: TSocket, headers: PStringTable, timeout: int): string =
|
||||
buf.setLen(r)
|
||||
result.add(buf)
|
||||
|
||||
proc parseResponse(s: TSocket, getBody: bool, timeout: int): TResponse =
|
||||
proc parseResponse(s: Socket, getBody: bool, timeout: int): Response =
|
||||
var parsedStatus = false
|
||||
var linei = 0
|
||||
var fullyRead = false
|
||||
@@ -272,20 +272,20 @@ type
|
||||
{.deprecated: [THttpMethod: HttpMethod].}
|
||||
|
||||
when not defined(ssl):
|
||||
type PSSLContext = ref object
|
||||
let defaultSSLContext: PSSLContext = nil
|
||||
type SSLContext = ref object
|
||||
let defaultSSLContext: SSLContext = nil
|
||||
else:
|
||||
let defaultSSLContext = newContext(verifyMode = CVerifyNone)
|
||||
|
||||
proc newProxy*(url: string, auth = ""): PProxy =
|
||||
proc newProxy*(url: string, auth = ""): Proxy =
|
||||
## Constructs a new ``TProxy`` object.
|
||||
result = PProxy(url: parseUrl(url), auth: auth)
|
||||
result = Proxy(url: parseUrl(url), auth: auth)
|
||||
|
||||
proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
|
||||
body = "",
|
||||
sslContext: PSSLContext = defaultSSLContext,
|
||||
sslContext: SSLContext = defaultSSLContext,
|
||||
timeout = -1, userAgent = defUserAgent,
|
||||
proxy: PProxy = nil): TResponse =
|
||||
proxy: Proxy = nil): Response =
|
||||
## | Requests ``url`` with the specified ``httpMethod``.
|
||||
## | Extra headers can be specified and must be seperated by ``\c\L``
|
||||
## | An optional timeout can be specified in miliseconds, if reading from the
|
||||
@@ -310,16 +310,16 @@ proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
|
||||
|
||||
var s = socket()
|
||||
if s == invalidSocket: raiseOSError(osLastError())
|
||||
var port = sockets.TPort(80)
|
||||
var port = sockets.Port(80)
|
||||
if r.scheme == "https":
|
||||
when defined(ssl):
|
||||
sslContext.wrapSocket(s)
|
||||
port = sockets.TPort(443)
|
||||
port = sockets.Port(443)
|
||||
else:
|
||||
raise newException(EHttpRequestErr,
|
||||
raise newException(HttpRequestError,
|
||||
"SSL support is not available. Cannot connect over SSL.")
|
||||
if r.port != "":
|
||||
port = sockets.TPort(r.port.parseInt)
|
||||
port = sockets.Port(r.port.parseInt)
|
||||
|
||||
if timeout == -1:
|
||||
s.connect(r.hostname, port)
|
||||
@@ -338,7 +338,7 @@ proc redirection(status: string): bool =
|
||||
if status.startsWith(i):
|
||||
return true
|
||||
|
||||
proc getNewLocation(lastUrl: string, headers: PStringTable): string =
|
||||
proc getNewLocation(lastUrl: string, headers: StringTableRef): string =
|
||||
result = headers["Location"]
|
||||
if result == "": httpError("location header expected")
|
||||
# Relative URLs. (Not part of the spec, but soon will be.)
|
||||
@@ -348,10 +348,10 @@ proc getNewLocation(lastUrl: string, headers: PStringTable): string =
|
||||
result = origParsed.hostname & "/" & r.path
|
||||
|
||||
proc get*(url: string, extraHeaders = "", maxRedirects = 5,
|
||||
sslContext: PSSLContext = defaultSSLContext,
|
||||
sslContext: SSLContext = defaultSSLContext,
|
||||
timeout = -1, userAgent = defUserAgent,
|
||||
proxy: PProxy = nil): TResponse =
|
||||
## | GETs the ``url`` and returns a ``TResponse`` object
|
||||
proxy: Proxy = nil): Response =
|
||||
## | GETs the ``url`` and returns a ``Response`` object
|
||||
## | This proc also handles redirection
|
||||
## | Extra headers can be specified and must be separated by ``\c\L``.
|
||||
## | An optional timeout can be specified in miliseconds, if reading from the
|
||||
@@ -367,9 +367,9 @@ proc get*(url: string, extraHeaders = "", maxRedirects = 5,
|
||||
lastUrl = redirectTo
|
||||
|
||||
proc getContent*(url: string, extraHeaders = "", maxRedirects = 5,
|
||||
sslContext: PSSLContext = defaultSSLContext,
|
||||
sslContext: SSLContext = defaultSSLContext,
|
||||
timeout = -1, userAgent = defUserAgent,
|
||||
proxy: PProxy = nil): string =
|
||||
proxy: Proxy = nil): string =
|
||||
## | GETs the body and returns it as a string.
|
||||
## | Raises exceptions for the status codes ``4xx`` and ``5xx``
|
||||
## | Extra headers can be specified and must be separated by ``\c\L``.
|
||||
@@ -378,16 +378,16 @@ proc getContent*(url: string, extraHeaders = "", maxRedirects = 5,
|
||||
var r = get(url, extraHeaders, maxRedirects, sslContext, timeout, userAgent,
|
||||
proxy)
|
||||
if r.status[0] in {'4','5'}:
|
||||
raise newException(EHTTPRequestErr, r.status)
|
||||
raise newException(HttpRequestError, r.status)
|
||||
else:
|
||||
return r.body
|
||||
|
||||
proc post*(url: string, extraHeaders = "", body = "",
|
||||
maxRedirects = 5,
|
||||
sslContext: PSSLContext = defaultSSLContext,
|
||||
sslContext: SSLContext = defaultSSLContext,
|
||||
timeout = -1, userAgent = defUserAgent,
|
||||
proxy: PProxy = nil): TResponse =
|
||||
## | POSTs ``body`` to the ``url`` and returns a ``TResponse`` object.
|
||||
proxy: Proxy = nil): Response =
|
||||
## | POSTs ``body`` to the ``url`` and returns a ``Response`` object.
|
||||
## | This proc adds the necessary Content-Length header.
|
||||
## | This proc also handles redirection.
|
||||
## | Extra headers can be specified and must be separated by ``\c\L``.
|
||||
@@ -407,9 +407,9 @@ proc post*(url: string, extraHeaders = "", body = "",
|
||||
|
||||
proc postContent*(url: string, extraHeaders = "", body = "",
|
||||
maxRedirects = 5,
|
||||
sslContext: PSSLContext = defaultSSLContext,
|
||||
sslContext: SSLContext = defaultSSLContext,
|
||||
timeout = -1, userAgent = defUserAgent,
|
||||
proxy: PProxy = nil): string =
|
||||
proxy: Proxy = nil): string =
|
||||
## | POSTs ``body`` to ``url`` and returns the response's body as a string
|
||||
## | Raises exceptions for the status codes ``4xx`` and ``5xx``
|
||||
## | Extra headers can be specified and must be separated by ``\c\L``.
|
||||
@@ -418,18 +418,18 @@ proc postContent*(url: string, extraHeaders = "", body = "",
|
||||
var r = post(url, extraHeaders, body, maxRedirects, sslContext, timeout,
|
||||
userAgent, proxy)
|
||||
if r.status[0] in {'4','5'}:
|
||||
raise newException(EHTTPRequestErr, r.status)
|
||||
raise newException(HttpRequestError, r.status)
|
||||
else:
|
||||
return r.body
|
||||
|
||||
proc downloadFile*(url: string, outputFilename: string,
|
||||
sslContext: PSSLContext = defaultSSLContext,
|
||||
sslContext: SSLContext = defaultSSLContext,
|
||||
timeout = -1, userAgent = defUserAgent,
|
||||
proxy: PProxy = nil) =
|
||||
proxy: Proxy = nil) =
|
||||
## | Downloads ``url`` and saves it to ``outputFilename``
|
||||
## | An optional timeout can be specified in miliseconds, if reading from the
|
||||
## server takes longer than specified an ETimeout exception will be raised.
|
||||
var f: TFile
|
||||
var f: File
|
||||
if open(f, outputFilename, fmWrite):
|
||||
f.write(getContent(url, sslContext = sslContext, timeout = timeout,
|
||||
userAgent = userAgent, proxy = proxy))
|
||||
@@ -437,8 +437,8 @@ proc downloadFile*(url: string, outputFilename: string,
|
||||
else:
|
||||
fileError("Unable to open file")
|
||||
|
||||
proc generateHeaders(r: TURL, httpMethod: THttpMethod,
|
||||
headers: PStringTable): string =
|
||||
proc generateHeaders(r: Url, httpMethod: HttpMethod,
|
||||
headers: StringTableRef): string =
|
||||
result = substr($httpMethod, len("http"))
|
||||
# TODO: Proxies
|
||||
result.add(" /" & r.path & r.query)
|
||||
@@ -455,7 +455,7 @@ type
|
||||
AsyncHttpClient* = ref object
|
||||
socket: AsyncSocket
|
||||
connected: bool
|
||||
currentURL: TURL ## Where we are currently connected.
|
||||
currentURL: Url ## Where we are currently connected.
|
||||
headers*: StringTableRef
|
||||
maxRedirects: int
|
||||
userAgent: string
|
||||
@@ -466,7 +466,7 @@ type
|
||||
|
||||
proc newAsyncHttpClient*(userAgent = defUserAgent,
|
||||
maxRedirects = 5, sslContext = defaultSslContext): AsyncHttpClient =
|
||||
## Creates a new PAsyncHttpClient instance.
|
||||
## Creates a new AsyncHttpClient instance.
|
||||
##
|
||||
## ``userAgent`` specifies the user agent that will be used when making
|
||||
## requests.
|
||||
@@ -488,7 +488,7 @@ proc close*(client: AsyncHttpClient) =
|
||||
client.socket.close()
|
||||
client.connected = false
|
||||
|
||||
proc recvFull(socket: PAsyncSocket, size: int): Future[string] {.async.} =
|
||||
proc recvFull(socket: AsyncSocket, size: int): Future[string] {.async.} =
|
||||
## Ensures that all the data requested is read and returned.
|
||||
result = ""
|
||||
while true:
|
||||
@@ -497,7 +497,7 @@ proc recvFull(socket: PAsyncSocket, size: int): Future[string] {.async.} =
|
||||
if data == "": break # We've been disconnected.
|
||||
result.add data
|
||||
|
||||
proc parseChunks(client: PAsyncHttpClient): Future[string] {.async.} =
|
||||
proc parseChunks(client: AsyncHttpClient): Future[string] {.async.} =
|
||||
result = ""
|
||||
var ri = 0
|
||||
while true:
|
||||
@@ -529,8 +529,8 @@ proc parseChunks(client: PAsyncHttpClient): Future[string] {.async.} =
|
||||
# Trailer headers will only be sent if the request specifies that we want
|
||||
# them: http://tools.ietf.org/html/rfc2616#section-3.6.1
|
||||
|
||||
proc parseBody(client: PAsyncHttpClient,
|
||||
headers: PStringTable): Future[string] {.async.} =
|
||||
proc parseBody(client: AsyncHttpClient,
|
||||
headers: StringTableRef): Future[string] {.async.} =
|
||||
result = ""
|
||||
if headers["Transfer-Encoding"] == "chunked":
|
||||
result = await parseChunks(client)
|
||||
@@ -559,8 +559,8 @@ proc parseBody(client: PAsyncHttpClient,
|
||||
if buf == "": break
|
||||
result.add(buf)
|
||||
|
||||
proc parseResponse(client: PAsyncHttpClient,
|
||||
getBody: bool): Future[TResponse] {.async.} =
|
||||
proc parseResponse(client: AsyncHttpClient,
|
||||
getBody: bool): Future[Response] {.async.} =
|
||||
var parsedStatus = false
|
||||
var linei = 0
|
||||
var fullyRead = false
|
||||
@@ -607,34 +607,34 @@ proc parseResponse(client: PAsyncHttpClient,
|
||||
else:
|
||||
result.body = ""
|
||||
|
||||
proc newConnection(client: PAsyncHttpClient, url: TURL) {.async.} =
|
||||
proc newConnection(client: AsyncHttpClient, url: Url) {.async.} =
|
||||
if client.currentURL.hostname != url.hostname or
|
||||
client.currentURL.scheme != url.scheme:
|
||||
if client.connected: client.close()
|
||||
client.socket = newAsyncSocket()
|
||||
|
||||
# TODO: I should be able to write 'net.TPort' here...
|
||||
# TODO: I should be able to write 'net.Port' here...
|
||||
let port =
|
||||
if url.port == "":
|
||||
if url.scheme.toLower() == "https":
|
||||
rawsockets.TPort(443)
|
||||
rawsockets.Port(443)
|
||||
else:
|
||||
rawsockets.TPort(80)
|
||||
else: rawsockets.TPort(url.port.parseInt)
|
||||
rawsockets.Port(80)
|
||||
else: rawsockets.Port(url.port.parseInt)
|
||||
|
||||
if url.scheme.toLower() == "https":
|
||||
when defined(ssl):
|
||||
client.sslContext.wrapSocket(client.socket)
|
||||
else:
|
||||
raise newException(EHttpRequestErr,
|
||||
raise newException(HttpRequestError,
|
||||
"SSL support is not available. Cannot connect over SSL.")
|
||||
|
||||
await client.socket.connect(url.hostname, port)
|
||||
client.currentURL = url
|
||||
client.connected = true
|
||||
|
||||
proc request*(client: PAsyncHttpClient, url: string, httpMethod = httpGET,
|
||||
body = ""): Future[TResponse] {.async.} =
|
||||
proc request*(client: AsyncHttpClient, url: string, httpMethod = httpGET,
|
||||
body = ""): Future[Response] {.async.} =
|
||||
## Connects to the hostname specified by the URL and performs a request
|
||||
## using the method specified.
|
||||
##
|
||||
@@ -657,7 +657,7 @@ proc request*(client: PAsyncHttpClient, url: string, httpMethod = httpGET,
|
||||
|
||||
result = await parseResponse(client, httpMethod != httpHEAD)
|
||||
|
||||
proc get*(client: PAsyncHttpClient, url: string): Future[TResponse] {.async.} =
|
||||
proc get*(client: AsyncHttpClient, url: string): Future[Response] {.async.} =
|
||||
## Connects to the hostname specified by the URL and performs a GET request.
|
||||
##
|
||||
## This procedure will follow redirects up to a maximum number of redirects
|
||||
|
||||
@@ -15,12 +15,12 @@
|
||||
## import strutils, sockets, httpserver
|
||||
##
|
||||
## var counter = 0
|
||||
## proc handleRequest(client: TSocket, path, query: string): bool {.procvar.} =
|
||||
## proc handleRequest(client: Socket, path, query: string): bool {.procvar.} =
|
||||
## inc(counter)
|
||||
## client.send("Hello for the $#th time." % $counter & wwwNL)
|
||||
## return false # do not stop processing
|
||||
##
|
||||
## run(handleRequest, TPort(80))
|
||||
## run(handleRequest, Port(80))
|
||||
##
|
||||
|
||||
import parseutils, strutils, os, osproc, strtabs, streams, sockets, asyncio
|
||||
@@ -31,14 +31,14 @@ const
|
||||
|
||||
# --------------- output messages --------------------------------------------
|
||||
|
||||
proc sendTextContentType(client: TSocket) =
|
||||
proc sendTextContentType(client: Socket) =
|
||||
send(client, "Content-type: text/html" & wwwNL)
|
||||
send(client, wwwNL)
|
||||
|
||||
proc sendStatus(client: TSocket, status: string) =
|
||||
proc sendStatus(client: Socket, status: string) =
|
||||
send(client, "HTTP/1.1 " & status & wwwNL)
|
||||
|
||||
proc badRequest(client: TSocket) =
|
||||
proc badRequest(client: Socket) =
|
||||
# Inform the client that a request it has made has a problem.
|
||||
send(client, "HTTP/1.1 400 Bad Request" & wwwNL)
|
||||
sendTextContentType(client)
|
||||
@@ -46,18 +46,18 @@ proc badRequest(client: TSocket) =
|
||||
"such as a POST without a Content-Length.</p>" & wwwNL)
|
||||
|
||||
when false:
|
||||
proc cannotExec(client: TSocket) =
|
||||
proc cannotExec(client: Socket) =
|
||||
send(client, "HTTP/1.1 500 Internal Server Error" & wwwNL)
|
||||
sendTextContentType(client)
|
||||
send(client, "<P>Error prohibited CGI execution." & wwwNL)
|
||||
|
||||
proc headers(client: TSocket, filename: string) =
|
||||
proc headers(client: Socket, filename: string) =
|
||||
# XXX could use filename to determine file type
|
||||
send(client, "HTTP/1.1 200 OK" & wwwNL)
|
||||
send(client, ServerSig)
|
||||
sendTextContentType(client)
|
||||
|
||||
proc notFound(client: TSocket) =
|
||||
proc notFound(client: Socket) =
|
||||
send(client, "HTTP/1.1 404 NOT FOUND" & wwwNL)
|
||||
send(client, ServerSig)
|
||||
sendTextContentType(client)
|
||||
@@ -67,7 +67,7 @@ proc notFound(client: TSocket) =
|
||||
send(client, "is unavailable or nonexistent.</p>" & wwwNL)
|
||||
send(client, "</body></html>" & wwwNL)
|
||||
|
||||
proc unimplemented(client: TSocket) =
|
||||
proc unimplemented(client: Socket) =
|
||||
send(client, "HTTP/1.1 501 Method Not Implemented" & wwwNL)
|
||||
send(client, ServerSig)
|
||||
sendTextContentType(client)
|
||||
@@ -79,11 +79,11 @@ proc unimplemented(client: TSocket) =
|
||||
# ----------------- file serving ---------------------------------------------
|
||||
|
||||
when false:
|
||||
proc discardHeaders(client: TSocket) = skip(client)
|
||||
proc discardHeaders(client: Socket) = skip(client)
|
||||
|
||||
proc serveFile*(client: TSocket, filename: string) =
|
||||
proc serveFile*(client: Socket, filename: string) =
|
||||
## serves a file to the client.
|
||||
var f: TFile
|
||||
var f: File
|
||||
if open(f, filename):
|
||||
headers(client, filename)
|
||||
const bufSize = 8000 # != 8K might be good for memory manager
|
||||
@@ -108,7 +108,7 @@ when false:
|
||||
type
|
||||
TRequestMethod = enum reqGet, reqPost
|
||||
|
||||
proc executeCgi(client: TSocket, path, query: string, meth: TRequestMethod) =
|
||||
proc executeCgi(client: Socket, path, query: string, meth: TRequestMethod) =
|
||||
var env = newStringTable(modeCaseInsensitive)
|
||||
var contentLength = -1
|
||||
case meth
|
||||
@@ -158,7 +158,7 @@ when false:
|
||||
|
||||
# --------------- Server Setup -----------------------------------------------
|
||||
|
||||
proc acceptRequest(client: TSocket) =
|
||||
proc acceptRequest(client: Socket) =
|
||||
var cgi = false
|
||||
var query = ""
|
||||
var buf = TaintedString""
|
||||
@@ -208,21 +208,21 @@ when false:
|
||||
executeCgi(client, path, query, meth)
|
||||
|
||||
type
|
||||
TServer* = object of TObject ## contains the current server state
|
||||
socket: TSocket
|
||||
port: TPort
|
||||
client*: TSocket ## the socket to write the file data to
|
||||
reqMethod*: string ## Request method. GET or POST.
|
||||
path*, query*: string ## path and query the client requested
|
||||
headers*: PStringTable ## headers with which the client made the request
|
||||
body*: string ## only set with POST requests
|
||||
ip*: string ## ip address of the requesting client
|
||||
TServer* = object of RootObj ## contains the current server state
|
||||
socket: Socket
|
||||
port: Port
|
||||
client*: Socket ## the socket to write the file data to
|
||||
reqMethod*: string ## Request method. GET or POST.
|
||||
path*, query*: string ## path and query the client requested
|
||||
headers*: StringTableRef ## headers with which the client made the request
|
||||
body*: string ## only set with POST requests
|
||||
ip*: string ## ip address of the requesting client
|
||||
|
||||
PAsyncHTTPServer* = ref TAsyncHTTPServer
|
||||
TAsyncHTTPServer = object of TServer
|
||||
asyncSocket: PAsyncSocket
|
||||
asyncSocket: AsyncSocket
|
||||
|
||||
proc open*(s: var TServer, port = TPort(80), reuseAddr = false) =
|
||||
proc open*(s: var TServer, port = Port(80), reuseAddr = false) =
|
||||
## creates a new server at port `port`. If ``port == 0`` a free port is
|
||||
## acquired that can be accessed later by the ``port`` proc.
|
||||
s.socket = socket(AF_INET)
|
||||
@@ -232,7 +232,7 @@ proc open*(s: var TServer, port = TPort(80), reuseAddr = false) =
|
||||
bindAddr(s.socket, port)
|
||||
listen(s.socket)
|
||||
|
||||
if port == TPort(0):
|
||||
if port == Port(0):
|
||||
s.port = getSockName(s.socket)
|
||||
else:
|
||||
s.port = port
|
||||
@@ -243,13 +243,13 @@ proc open*(s: var TServer, port = TPort(80), reuseAddr = false) =
|
||||
s.query = ""
|
||||
s.headers = {:}.newStringTable()
|
||||
|
||||
proc port*(s: var TServer): TPort =
|
||||
proc port*(s: var TServer): Port =
|
||||
## get the port number the server has acquired.
|
||||
result = s.port
|
||||
|
||||
proc next*(s: var TServer) =
|
||||
## proceed to the first/next request.
|
||||
var client: TSocket
|
||||
var client: Socket
|
||||
new(client)
|
||||
var ip: string
|
||||
acceptAddr(s.socket, client, ip)
|
||||
@@ -358,9 +358,9 @@ proc close*(s: TServer) =
|
||||
## closes the server (and the socket the server uses).
|
||||
close(s.socket)
|
||||
|
||||
proc run*(handleRequest: proc (client: TSocket,
|
||||
proc run*(handleRequest: proc (client: Socket,
|
||||
path, query: string): bool {.closure.},
|
||||
port = TPort(80)) =
|
||||
port = Port(80)) =
|
||||
## encapsulates the server object and main loop
|
||||
var s: TServer
|
||||
open(s, port)
|
||||
@@ -375,7 +375,7 @@ proc run*(handleRequest: proc (client: TSocket,
|
||||
|
||||
proc nextAsync(s: PAsyncHTTPServer) =
|
||||
## proceed to the first/next request.
|
||||
var client: TSocket
|
||||
var client: Socket
|
||||
new(client)
|
||||
var ip: string
|
||||
acceptAddr(getSocket(s.asyncSocket), client, ip)
|
||||
@@ -474,16 +474,16 @@ proc nextAsync(s: PAsyncHTTPServer) =
|
||||
s.query = ""
|
||||
s.path = data.substr(i, last-1)
|
||||
|
||||
proc asyncHTTPServer*(handleRequest: proc (server: PAsyncHTTPServer, client: TSocket,
|
||||
proc asyncHTTPServer*(handleRequest: proc (server: PAsyncHTTPServer, client: Socket,
|
||||
path, query: string): bool {.closure, gcsafe.},
|
||||
port = TPort(80), address = "",
|
||||
port = Port(80), address = "",
|
||||
reuseAddr = false): PAsyncHTTPServer =
|
||||
## Creates an Asynchronous HTTP server at ``port``.
|
||||
var capturedRet: PAsyncHTTPServer
|
||||
new(capturedRet)
|
||||
capturedRet.asyncSocket = asyncSocket()
|
||||
capturedRet.asyncSocket.handleAccept =
|
||||
proc (s: PAsyncSocket) =
|
||||
proc (s: AsyncSocket) =
|
||||
nextAsync(capturedRet)
|
||||
let quit = handleRequest(capturedRet, capturedRet.client, capturedRet.path,
|
||||
capturedRet.query)
|
||||
@@ -493,7 +493,7 @@ proc asyncHTTPServer*(handleRequest: proc (server: PAsyncHTTPServer, client: TSo
|
||||
|
||||
capturedRet.asyncSocket.bindAddr(port, address)
|
||||
capturedRet.asyncSocket.listen()
|
||||
if port == TPort(0):
|
||||
if port == Port(0):
|
||||
capturedRet.port = getSockName(capturedRet.asyncSocket)
|
||||
else:
|
||||
capturedRet.port = port
|
||||
@@ -506,8 +506,8 @@ proc asyncHTTPServer*(handleRequest: proc (server: PAsyncHTTPServer, client: TSo
|
||||
capturedRet.headers = {:}.newStringTable()
|
||||
result = capturedRet
|
||||
|
||||
proc register*(d: PDispatcher, s: PAsyncHTTPServer) =
|
||||
## Registers a ``PAsyncHTTPServer`` with a ``PDispatcher``.
|
||||
proc register*(d: Dispatcher, s: PAsyncHTTPServer) =
|
||||
## Registers a ``PAsyncHTTPServer`` with a ``Dispatcher``.
|
||||
d.register(s.asyncSocket)
|
||||
|
||||
proc close*(h: PAsyncHTTPServer) =
|
||||
@@ -518,7 +518,7 @@ when isMainModule:
|
||||
var counter = 0
|
||||
|
||||
var s: TServer
|
||||
open(s, TPort(0))
|
||||
open(s, Port(0))
|
||||
echo("httpserver running on port ", s.port)
|
||||
while true:
|
||||
next(s)
|
||||
|
||||
@@ -196,7 +196,6 @@ when not defined(JS):
|
||||
## computes x to power raised of y.
|
||||
|
||||
# C procs:
|
||||
proc gettime(dummy: ptr cint): cint {.importc: "time", header: "<time.h>".}
|
||||
proc srand(seed: cint) {.importc: "srand", header: "<stdlib.h>".}
|
||||
proc rand(): cint {.importc: "rand", header: "<stdlib.h>".}
|
||||
|
||||
@@ -331,6 +330,8 @@ proc standardDeviation*(s: RunningStat): float =
|
||||
{.pop.}
|
||||
|
||||
when isMainModule and not defined(JS):
|
||||
proc gettime(dummy: ptr cint): cint {.importc: "time", header: "<time.h>".}
|
||||
|
||||
# Verifies random seed initialization.
|
||||
let seed = gettime(nil)
|
||||
randomize(seed)
|
||||
|
||||
@@ -54,8 +54,8 @@ type
|
||||
when defined(ssl):
|
||||
case isSsl*: bool
|
||||
of true:
|
||||
sslHandle*: PSSL
|
||||
sslContext*: PSSLContext
|
||||
sslHandle*: SSLPtr
|
||||
sslContext*: SSLContext
|
||||
sslNoHandshake*: bool # True if needs handshake.
|
||||
sslHasPeekChar*: bool
|
||||
sslPeekChar*: char
|
||||
@@ -147,11 +147,11 @@ when defined(ssl):
|
||||
raise newException(SSLError, $errStr)
|
||||
|
||||
# http://simplestcodings.blogspot.co.uk/2010/08/secure-server-client-using-openssl-in-c.html
|
||||
proc loadCertificates(ctx: PSSL_CTX, certFile, keyFile: string) =
|
||||
proc loadCertificates(ctx: SSL_CTX, certFile, keyFile: string) =
|
||||
if certFile != "" and not existsFile(certFile):
|
||||
raise newException(system.EIO, "Certificate file could not be found: " & certFile)
|
||||
raise newException(system.IOError, "Certificate file could not be found: " & certFile)
|
||||
if keyFile != "" and not existsFile(keyFile):
|
||||
raise newException(system.EIO, "Key file could not be found: " & keyFile)
|
||||
raise newException(system.IOError, "Key file could not be found: " & keyFile)
|
||||
|
||||
if certFile != "":
|
||||
var ret = SSLCTXUseCertificateChainFile(ctx, certFile)
|
||||
@@ -168,7 +168,7 @@ when defined(ssl):
|
||||
raiseSSLError("Verification of private key file failed.")
|
||||
|
||||
proc newContext*(protVersion = protSSLv23, verifyMode = CVerifyPeer,
|
||||
certFile = "", keyFile = ""): PSSLContext =
|
||||
certFile = "", keyFile = ""): SSLContext =
|
||||
## Creates an SSL context.
|
||||
##
|
||||
## Protocol version specifies the protocol to use. SSLv2, SSLv3, TLSv1
|
||||
@@ -184,7 +184,7 @@ when defined(ssl):
|
||||
## path, a server socket will most likely not work without these.
|
||||
## Certificates can be generated using the following command:
|
||||
## ``openssl req -x509 -nodes -days 365 -newkey rsa:1024 -keyout mycert.pem -out mycert.pem``.
|
||||
var newCTX: PSSL_CTX
|
||||
var newCTX: SSL_CTX
|
||||
case protVersion
|
||||
of protSSLv23:
|
||||
newCTX = SSL_CTX_new(SSLv23_method()) # SSlv2,3 and TLS1 support.
|
||||
@@ -210,9 +210,9 @@ when defined(ssl):
|
||||
|
||||
discard newCTX.SSLCTXSetMode(SSL_MODE_AUTO_RETRY)
|
||||
newCTX.loadCertificates(certFile, keyFile)
|
||||
return PSSLContext(newCTX)
|
||||
return SSLContext(newCTX)
|
||||
|
||||
proc wrapSocket*(ctx: PSSLContext, socket: PSocket) =
|
||||
proc wrapSocket*(ctx: SSLContext, socket: Socket) =
|
||||
## Wraps a socket in an SSL context. This function effectively turns
|
||||
## ``socket`` into an SSL socket.
|
||||
##
|
||||
@@ -221,7 +221,7 @@ when defined(ssl):
|
||||
|
||||
socket.isSSL = true
|
||||
socket.sslContext = ctx
|
||||
socket.sslHandle = SSLNew(PSSLCTX(socket.sslContext))
|
||||
socket.sslHandle = SSLNew(SSLCTX(socket.sslContext))
|
||||
socket.sslNoHandshake = false
|
||||
socket.sslHasPeekChar = false
|
||||
if socket.sslHandle == nil:
|
||||
@@ -350,9 +350,9 @@ proc acceptAddr*(server: Socket, client: var Socket, address: var string,
|
||||
address = $inet_ntoa(sockAddress.sin_addr)
|
||||
|
||||
when false: #defined(ssl):
|
||||
proc acceptAddrSSL*(server: PSocket, client: var PSocket,
|
||||
proc acceptAddrSSL*(server: Socket, client: var Socket,
|
||||
address: var string): TSSLAcceptResult {.
|
||||
tags: [FReadIO].} =
|
||||
tags: [ReadIOEffect].} =
|
||||
## This procedure should only be used for non-blocking **SSL** sockets.
|
||||
## It will immediately return with one of the following values:
|
||||
##
|
||||
@@ -480,7 +480,7 @@ proc connect*(socket: Socket, address: string, port = Port(0),
|
||||
socketError(socket, ret)
|
||||
|
||||
when defined(ssl):
|
||||
proc handshake*(socket: PSocket): bool {.tags: [FReadIO, FWriteIO].} =
|
||||
proc handshake*(socket: Socket): bool {.tags: [ReadIOEffect, WriteIOEffect].} =
|
||||
## This proc needs to be called on a socket after it connects. This is
|
||||
## only applicable when using ``connectAsync``.
|
||||
## This proc performs the SSL handshake.
|
||||
@@ -510,7 +510,7 @@ when defined(ssl):
|
||||
else:
|
||||
raiseSSLError("Socket is not an SSL socket.")
|
||||
|
||||
proc gotHandshake*(socket: PSocket): bool =
|
||||
proc gotHandshake*(socket: Socket): bool =
|
||||
## Determines whether a handshake has occurred between a client (``socket``)
|
||||
## and the server that ``socket`` is connected to.
|
||||
##
|
||||
|
||||
@@ -54,12 +54,12 @@ type
|
||||
|
||||
{.deprecated: [EInvalidReply: ReplyError, TMessage: Message, TSMTP: Smtp].}
|
||||
|
||||
proc debugSend(smtp: TSMTP, cmd: string) =
|
||||
proc debugSend(smtp: Smtp, cmd: string) =
|
||||
if smtp.debug:
|
||||
echo("C:" & cmd)
|
||||
smtp.sock.send(cmd)
|
||||
|
||||
proc debugRecv(smtp: var TSMTP): TaintedString =
|
||||
proc debugRecv(smtp: var Smtp): TaintedString =
|
||||
var line = TaintedString""
|
||||
smtp.sock.readLine(line)
|
||||
|
||||
@@ -67,11 +67,11 @@ proc debugRecv(smtp: var TSMTP): TaintedString =
|
||||
echo("S:" & line.string)
|
||||
return line
|
||||
|
||||
proc quitExcpt(smtp: TSMTP, msg: string) =
|
||||
proc quitExcpt(smtp: Smtp, msg: string) =
|
||||
smtp.debugSend("QUIT")
|
||||
raise newException(EInvalidReply, msg)
|
||||
raise newException(ReplyError, msg)
|
||||
|
||||
proc checkReply(smtp: var TSMTP, reply: string) =
|
||||
proc checkReply(smtp: var Smtp, reply: string) =
|
||||
var line = smtp.debugRecv()
|
||||
if not line.string.startswith(reply):
|
||||
quitExcpt(smtp, "Expected " & reply & " reply, got: " & line.string)
|
||||
@@ -86,9 +86,9 @@ else:
|
||||
|
||||
proc connect*(address: string, port = Port(25),
|
||||
ssl = false, debug = false,
|
||||
sslContext = defaultSSLContext): TSMTP =
|
||||
sslContext = defaultSSLContext): Smtp =
|
||||
## Establishes a connection with a SMTP server.
|
||||
## May fail with EInvalidReply or with a socket error.
|
||||
## May fail with ReplyError or with a socket error.
|
||||
result.sock = newSocket()
|
||||
if ssl:
|
||||
when compiledWithSsl:
|
||||
@@ -103,10 +103,10 @@ proc connect*(address: string, port = Port(25),
|
||||
result.debugSend("HELO " & address & "\c\L")
|
||||
result.checkReply("250")
|
||||
|
||||
proc auth*(smtp: var TSMTP, username, password: string) =
|
||||
proc auth*(smtp: var Smtp, username, password: string) =
|
||||
## Sends an AUTH command to the server to login as the `username`
|
||||
## using `password`.
|
||||
## May fail with EInvalidReply.
|
||||
## May fail with ReplyError.
|
||||
|
||||
smtp.debugSend("AUTH LOGIN\c\L")
|
||||
smtp.checkReply("334") # TODO: Check whether it's asking for the "Username:"
|
||||
@@ -117,11 +117,11 @@ proc auth*(smtp: var TSMTP, username, password: string) =
|
||||
smtp.debugSend(encode(password) & "\c\L")
|
||||
smtp.checkReply("235") # Check whether the authentification was successful.
|
||||
|
||||
proc sendmail*(smtp: var TSMTP, fromaddr: string,
|
||||
proc sendmail*(smtp: var Smtp, fromaddr: string,
|
||||
toaddrs: seq[string], msg: string) =
|
||||
## Sends `msg` from `fromaddr` to `toaddr`.
|
||||
## Messages may be formed using ``createMessage`` by converting the
|
||||
## TMessage into a string.
|
||||
## Message into a string.
|
||||
|
||||
smtp.debugSend("MAIL FROM:<" & fromaddr & ">\c\L")
|
||||
smtp.checkReply("250")
|
||||
@@ -136,13 +136,13 @@ proc sendmail*(smtp: var TSMTP, fromaddr: string,
|
||||
smtp.debugSend(".\c\L")
|
||||
smtp.checkReply("250")
|
||||
|
||||
proc close*(smtp: TSMTP) =
|
||||
proc close*(smtp: Smtp) =
|
||||
## Disconnects from the SMTP server and closes the socket.
|
||||
smtp.debugSend("QUIT\c\L")
|
||||
smtp.sock.close()
|
||||
|
||||
proc createMessage*(mSubject, mBody: string, mTo, mCc: seq[string],
|
||||
otherHeaders: openarray[tuple[name, value: string]]): TMessage =
|
||||
otherHeaders: openarray[tuple[name, value: string]]): Message =
|
||||
## Creates a new MIME compliant message.
|
||||
result.msgTo = mTo
|
||||
result.msgCc = mCc
|
||||
@@ -153,7 +153,7 @@ proc createMessage*(mSubject, mBody: string, mTo, mCc: seq[string],
|
||||
result.msgOtherHeaders[n] = v
|
||||
|
||||
proc createMessage*(mSubject, mBody: string, mTo,
|
||||
mCc: seq[string] = @[]): TMessage =
|
||||
mCc: seq[string] = @[]): Message =
|
||||
## Alternate version of the above.
|
||||
result.msgTo = mTo
|
||||
result.msgCc = mCc
|
||||
@@ -161,8 +161,8 @@ proc createMessage*(mSubject, mBody: string, mTo,
|
||||
result.msgBody = mBody
|
||||
result.msgOtherHeaders = newStringTable()
|
||||
|
||||
proc `$`*(msg: TMessage): string =
|
||||
## stringify for ``TMessage``.
|
||||
proc `$`*(msg: Message): string =
|
||||
## stringify for ``Message``.
|
||||
result = ""
|
||||
if msg.msgTo.len() > 0:
|
||||
result = "TO: " & msg.msgTo.join(", ") & "\c\L"
|
||||
@@ -192,7 +192,7 @@ proc newAsyncSmtp*(address: string, port: Port, useSsl = false,
|
||||
raise newException(ESystem,
|
||||
"SMTP module compiled without SSL support")
|
||||
|
||||
proc quitExcpt(smtp: AsyncSmtp, msg: string): PFuture[void] =
|
||||
proc quitExcpt(smtp: AsyncSmtp, msg: string): Future[void] =
|
||||
var retFuture = newFuture[void]()
|
||||
var sendFut = smtp.sock.send("QUIT")
|
||||
sendFut.callback =
|
||||
@@ -208,7 +208,7 @@ proc checkReply(smtp: AsyncSmtp, reply: string) {.async.} =
|
||||
|
||||
proc connect*(smtp: AsyncSmtp) {.async.} =
|
||||
## Establishes a connection with a SMTP server.
|
||||
## May fail with EInvalidReply or with a socket error.
|
||||
## May fail with ReplyError or with a socket error.
|
||||
await smtp.sock.connect(smtp.address, smtp.port)
|
||||
|
||||
await smtp.checkReply("220")
|
||||
@@ -218,7 +218,7 @@ proc connect*(smtp: AsyncSmtp) {.async.} =
|
||||
proc auth*(smtp: AsyncSmtp, username, password: string) {.async.} =
|
||||
## Sends an AUTH command to the server to login as the `username`
|
||||
## using `password`.
|
||||
## May fail with EInvalidReply.
|
||||
## May fail with ReplyError.
|
||||
|
||||
await smtp.sock.send("AUTH LOGIN\c\L")
|
||||
await smtp.checkReply("334") # TODO: Check whether it's asking for the "Username:"
|
||||
@@ -233,7 +233,7 @@ proc sendMail*(smtp: AsyncSmtp, fromAddr: string,
|
||||
toAddrs: seq[string], msg: string) {.async.} =
|
||||
## Sends ``msg`` from ``fromAddr`` to the addresses specified in ``toAddrs``.
|
||||
## Messages may be formed using ``createMessage`` by converting the
|
||||
## TMessage into a string.
|
||||
## Message into a string.
|
||||
|
||||
await smtp.sock.send("MAIL FROM:<" & fromAddr & ">\c\L")
|
||||
await smtp.checkReply("250")
|
||||
|
||||
@@ -55,7 +55,7 @@ when defined(ssl):
|
||||
SSLProtVersion* = enum
|
||||
protSSLv2, protSSLv3, protTLSv1, protSSLv23
|
||||
|
||||
SSLContext* = distinct PSSLCTX
|
||||
SSLContext* = distinct SSLCTX
|
||||
|
||||
SSLAcceptResult* = enum
|
||||
AcceptNoClient = 0, AcceptNoHandshake, AcceptSuccess
|
||||
@@ -79,7 +79,7 @@ type
|
||||
when defined(ssl):
|
||||
case isSsl: bool
|
||||
of true:
|
||||
sslHandle: PSSL
|
||||
sslHandle: SSLPtr
|
||||
sslContext: SSLContext
|
||||
sslNoHandshake: bool # True if needs handshake.
|
||||
sslHasPeekChar: bool
|
||||
@@ -254,21 +254,21 @@ when defined(ssl):
|
||||
|
||||
proc raiseSSLError(s = "") =
|
||||
if s != "":
|
||||
raise newException(ESSL, s)
|
||||
raise newException(SSLError, s)
|
||||
let err = ErrPeekLastError()
|
||||
if err == 0:
|
||||
raise newException(ESSL, "No error reported.")
|
||||
raise newException(SSLError, "No error reported.")
|
||||
if err == -1:
|
||||
raiseOSError(osLastError())
|
||||
var errStr = ErrErrorString(err, nil)
|
||||
raise newException(ESSL, $errStr)
|
||||
raise newException(SSLError, $errStr)
|
||||
|
||||
# http://simplestcodings.blogspot.co.uk/2010/08/secure-server-client-using-openssl-in-c.html
|
||||
proc loadCertificates(ctx: PSSL_CTX, certFile, keyFile: string) =
|
||||
proc loadCertificates(ctx: SSL_CTX, certFile, keyFile: string) =
|
||||
if certFile != "" and not existsFile(certFile):
|
||||
raise newException(system.EIO, "Certificate file could not be found: " & certFile)
|
||||
raise newException(system.IOError, "Certificate file could not be found: " & certFile)
|
||||
if keyFile != "" and not existsFile(keyFile):
|
||||
raise newException(system.EIO, "Key file could not be found: " & keyFile)
|
||||
raise newException(system.IOError, "Key file could not be found: " & keyFile)
|
||||
|
||||
if certFile != "":
|
||||
var ret = SSLCTXUseCertificateChainFile(ctx, certFile)
|
||||
@@ -285,7 +285,7 @@ when defined(ssl):
|
||||
raiseSslError("Verification of private key file failed.")
|
||||
|
||||
proc newContext*(protVersion = protSSLv23, verifyMode = CVerifyPeer,
|
||||
certFile = "", keyFile = ""): PSSLContext =
|
||||
certFile = "", keyFile = ""): SSLContext =
|
||||
## Creates an SSL context.
|
||||
##
|
||||
## Protocol version specifies the protocol to use. SSLv2, SSLv3, TLSv1 are
|
||||
@@ -301,7 +301,7 @@ when defined(ssl):
|
||||
## path, a server socket will most likely not work without these.
|
||||
## Certificates can be generated using the following command:
|
||||
## ``openssl req -x509 -nodes -days 365 -newkey rsa:1024 -keyout mycert.pem -out mycert.pem``.
|
||||
var newCTX: PSSL_CTX
|
||||
var newCTX: SSL_CTX
|
||||
case protVersion
|
||||
of protSSLv23:
|
||||
newCTX = SSL_CTX_new(SSLv23_method()) # SSlv2,3 and TLS1 support.
|
||||
@@ -327,9 +327,9 @@ when defined(ssl):
|
||||
|
||||
discard newCTX.SSLCTXSetMode(SSL_MODE_AUTO_RETRY)
|
||||
newCTX.loadCertificates(certFile, keyFile)
|
||||
return PSSLContext(newCTX)
|
||||
return SSLContext(newCTX)
|
||||
|
||||
proc wrapSocket*(ctx: PSSLContext, socket: TSocket) =
|
||||
proc wrapSocket*(ctx: SSLContext, socket: Socket) =
|
||||
## Wraps a socket in an SSL context. This function effectively turns
|
||||
## ``socket`` into an SSL socket.
|
||||
##
|
||||
@@ -338,7 +338,7 @@ when defined(ssl):
|
||||
|
||||
socket.isSSL = true
|
||||
socket.sslContext = ctx
|
||||
socket.sslHandle = SSLNew(PSSLCTX(socket.sslContext))
|
||||
socket.sslHandle = SSLNew(SSLCTX(socket.sslContext))
|
||||
socket.sslNoHandshake = false
|
||||
socket.sslHasPeekChar = false
|
||||
if socket.sslHandle == nil:
|
||||
@@ -561,9 +561,9 @@ proc setBlocking*(s: Socket, blocking: bool) {.tags: [], gcsafe.}
|
||||
## Sets blocking mode on socket
|
||||
|
||||
when defined(ssl):
|
||||
proc acceptAddrSSL*(server: TSocket, client: var TSocket,
|
||||
address: var string): TSSLAcceptResult {.
|
||||
tags: [FReadIO].} =
|
||||
proc acceptAddrSSL*(server: Socket, client: var Socket,
|
||||
address: var string): SSLAcceptResult {.
|
||||
tags: [ReadIOEffect].} =
|
||||
## This procedure should only be used for non-blocking **SSL** sockets.
|
||||
## It will immediately return with one of the following values:
|
||||
##
|
||||
@@ -886,7 +886,7 @@ proc connectAsync*(socket: Socket, name: string, port = Port(0),
|
||||
socket.sslNoHandshake = true
|
||||
|
||||
when defined(ssl):
|
||||
proc handshake*(socket: TSocket): bool {.tags: [FReadIO, FWriteIO].} =
|
||||
proc handshake*(socket: Socket): bool {.tags: [ReadIOEffect, WriteIOEffect].} =
|
||||
## This proc needs to be called on a socket after it connects. This is
|
||||
## only applicable when using ``connectAsync``.
|
||||
## This proc performs the SSL handshake.
|
||||
@@ -916,7 +916,7 @@ when defined(ssl):
|
||||
else:
|
||||
raiseSslError("Socket is not an SSL socket.")
|
||||
|
||||
proc gotHandshake*(socket: TSocket): bool =
|
||||
proc gotHandshake*(socket: Socket): bool =
|
||||
## Determines whether a handshake has occurred between a client (``socket``)
|
||||
## and the server that ``socket`` is connected to.
|
||||
##
|
||||
@@ -1689,7 +1689,7 @@ proc setBlocking(s: Socket, blocking: bool) =
|
||||
raiseOSError(osLastError())
|
||||
s.nonblocking = not blocking
|
||||
|
||||
discard """ proc setReuseAddr*(s: TSocket) =
|
||||
discard """ proc setReuseAddr*(s: Socket) =
|
||||
var blah: int = 1
|
||||
var mode = SO_REUSEADDR
|
||||
if setsockopt(s.fd, SOL_SOCKET, mode, addr blah, TSOcklen(sizeof(int))) == -1:
|
||||
|
||||
Reference in New Issue
Block a user