summary refs log tree commit diff stats
path: root/lib/pure
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2011-09-24 20:22:53 +0200
committerAraq <rumpf_a@web.de>2011-09-24 20:22:53 +0200
commit0f37d0e1f2aeee466b3c6179886963354eaa6222 (patch)
tree51ae4183dabd454877d7570cafb7f72dcf519011 /lib/pure
parent485c371942cbbb1f9a10c64b6fcc699e59511460 (diff)
downloadNim-0f37d0e1f2aeee466b3c6179886963354eaa6222.tar.gz
sockets.recv optimizations; stdlib now supports taint mode
Diffstat (limited to 'lib/pure')
-rwxr-xr-xlib/pure/cgi.nim12
-rwxr-xr-xlib/pure/httpclient.nim12
-rwxr-xr-xlib/pure/httpserver.nim12
-rw-r--r--lib/pure/irc.nim6
-rwxr-xr-xlib/pure/osproc.nim10
-rwxr-xr-xlib/pure/redis.nim22
-rwxr-xr-xlib/pure/smtp.nim12
-rwxr-xr-xlib/pure/sockets.nim45
8 files changed, 72 insertions, 59 deletions
diff --git a/lib/pure/cgi.nim b/lib/pure/cgi.nim
index c8536236d..c6e294374 100755
--- a/lib/pure/cgi.nim
+++ b/lib/pure/cgi.nim
@@ -111,19 +111,19 @@ proc getEncodedData(allowedMethods: set[TRequestMethod]): string =
   of "POST":
     if methodPost notin allowedMethods:
       cgiError("'REQUEST_METHOD' 'POST' is not supported")
-    var L = parseInt(getenv("CONTENT_LENGTH"))
+    var L = parseInt(getenv("CONTENT_LENGTH").string)
     result = newString(L)
     if readBuffer(stdin, addr(result[0]), L) != L:
       cgiError("cannot read from stdin")
   of "GET":
     if methodGet notin allowedMethods:
       cgiError("'REQUEST_METHOD' 'GET' is not supported")
-    result = getenv("QUERY_STRING")
+    result = getenv("QUERY_STRING").string
   else:
     if methodNone notin allowedMethods:
       cgiError("'REQUEST_METHOD' must be 'POST' or 'GET'")
 
-iterator decodeData*(data: string): tuple[key, value: string] =
+iterator decodeData*(data: string): tuple[key, value: TaintedString] =
   ## Reads and decodes CGI data and yields the (name, value) pairs the
   ## data consists of.
   var i = 0
@@ -160,13 +160,13 @@ iterator decodeData*(data: string): tuple[key, value: string] =
       of '&', '\0': break
       else: add(value, data[i])
       inc(i)
-    yield (name, value)
+    yield (name.TaintedString, value.TaintedString)
     if data[i] == '&': inc(i)
     elif data[i] == '\0': break
     else: cgiError("'&' expected")
 
 iterator decodeData*(allowedMethods: set[TRequestMethod] =
-       {methodNone, methodPost, methodGet}): tuple[key, value: string] =
+       {methodNone, methodPost, methodGet}): tuple[key, value: TaintedString] =
   ## Reads and decodes CGI data and yields the (name, value) pairs the
   ## data consists of. If the client does not use a method listed in the
   ## `allowedMethods` set, an `ECgi` exception is raised.
@@ -181,7 +181,7 @@ proc readData*(allowedMethods: set[TRequestMethod] =
   ## `allowedMethods` set, an `ECgi` exception is raised.
   result = newStringTable()
   for name, value in decodeData(allowedMethods):
-    result[name] = value
+    result[name.string] = value.string
 
 proc validateData*(data: PStringTable, validKeys: openarray[string]) =
   ## validates data; raises `ECgi` if this fails. This checks that each variable
diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim
index 73a8cb853..3af08f040 100755
--- a/lib/pure/httpclient.nim
+++ b/lib/pure/httpclient.nim
@@ -75,7 +75,7 @@ proc fileError(msg: string) =
 proc charAt(d: var string, i: var int, s: TSocket): char {.inline.} = 
   result = d[i]
   while result == '\0':
-    d = s.recv()
+    d = string(s.recv())
     i = 0
     result = d[i]
 
@@ -98,7 +98,7 @@ proc parseChunks(d: var string, start: int, s: TSocket): string =
         digitFound = true
         chunkSize = chunkSize shl 4 or (ord(d[i]) - ord('A') + 10)
       of '\0': 
-        d = s.recv()
+        d = string(s.recv())
         i = -1
       else: break
       inc(i)
@@ -123,7 +123,7 @@ proc parseChunks(d: var string, start: int, s: TSocket): string =
         inc(L, bytesRead)
         dec(missing, bytesRead)
       # next chunk:
-      d = s.recv()
+      d = string(s.recv())
       i = 0
     # skip trailing CR-LF:
     while charAt(d, i, s) in {'\C', '\L'}: inc(i)
@@ -139,7 +139,7 @@ proc parseBody(d: var string, start: int, s: TSocket,
     var contentLengthHeader = headers["Content-Length"]
     if contentLengthHeader != "":
       var length = contentLengthHeader.parseint()
-      while result.len() < length: result.add(s.recv())
+      while result.len() < length: result.add(s.recv.string)
     else:
       # (http://tools.ietf.org/html/rfc2616#section-4.4) NR.4 TODO
       
@@ -147,12 +147,12 @@ proc parseBody(d: var string, start: int, s: TSocket,
       # (http://tools.ietf.org/html/rfc2616#section-4.4) NR.5
       if headers["Connection"] == "close":
         while True:
-          var moreData = recv(s)
+          var moreData = recv(s).string
           if moreData.len == 0: break
           result.add(moreData)
 
 proc parseResponse(s: TSocket): TResponse =
-  var d = s.recv()
+  var d = s.recv.string
   var i = 0
 
   # Parse the version
diff --git a/lib/pure/httpserver.nim b/lib/pure/httpserver.nim
index eb5dd7d73..8e95db024 100755
--- a/lib/pure/httpserver.nim
+++ b/lib/pure/httpserver.nim
@@ -113,11 +113,11 @@ proc executeCgi(client: TSocket, path, query: string, meth: TRequestMethod) =
     env["REQUEST_METHOD"] = "GET"
     env["QUERY_STRING"] = query
   of reqPost:
-    var buf = ""
+    var buf = TaintedString""
     var dataAvail = false
     while dataAvail:
       dataAvail = recvLine(client, buf)
-      var L = toLower(buf)
+      var L = toLower(buf.string)
       if L.startsWith("content-length:"):
         var i = len("content-length:")
         while L[i] in Whitespace: inc(i)
@@ -146,7 +146,7 @@ proc executeCgi(client: TSocket, path, query: string, meth: TRequestMethod) =
   var outp = process.outputStream
   while running(process) or not outp.atEnd(outp):
     var line = outp.readLine()
-    send(client, line)
+    send(client, line.string)
     send(client, wwwNL)
 
 # --------------- Server Setup -----------------------------------------------
@@ -154,10 +154,10 @@ proc executeCgi(client: TSocket, path, query: string, meth: TRequestMethod) =
 proc acceptRequest(client: TSocket) =
   var cgi = false
   var query = ""
-  var buf = ""
+  var buf = TaintedString""
   discard recvLine(client, buf)
   var path = ""
-  var data = buf.split()
+  var data = buf.string.split()
   var meth = reqGet
 
   var q = find(data[1], '?')
@@ -231,7 +231,7 @@ proc next*(s: var TServer) =
   ## proceed to the first/next request.
   s.client = accept(s.socket)
   headers(s.client, "")
-  var data = recv(s.client)
+  var data = recv(s.client).string
   #discard recvLine(s.client, data)
   
   var i = skipWhitespace(data)
diff --git a/lib/pure/irc.nim b/lib/pure/irc.nim
index 0397502cd..7e1cd0eca 100644
--- a/lib/pure/irc.nim
+++ b/lib/pure/irc.nim
@@ -205,15 +205,15 @@ proc poll*(irc: var TIRC, ev: var TIRCEvent,
   ## This function should be called often as it also handles pinging
   ## the server.
   if not irc.connected: ev.typ = EvDisconnected
-  var line = ""
+  var line = TaintedString""
   var socks = @[irc.sock]
   var ret = socks.select(timeout)
   if socks.len() == 0 and ret == 1:
     if irc.sock.recvLine(line):
-      if line == "":
+      if line.string.len == 0:
         ev.typ = EvDisconnected
       else:
-        ev = parseMessage(line)
+        ev = parseMessage(line.string)
         if ev.cmd == MPing:
           irc.send("PONG " & ev.params[0])
         if ev.cmd == MPong:
diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim
index bf5dc7970..1b7d41908 100755
--- a/lib/pure/osproc.nim
+++ b/lib/pure/osproc.nim
@@ -41,7 +41,7 @@ type
 
 proc execProcess*(command: string,
                   options: set[TProcessOption] = {poStdErrToStdOut,
-                                                  poUseShell}): string {.
+                                                  poUseShell}): TaintedString {.
                                                   rtl, extern: "nosp$1".}
   ## A convenience procedure that executes ``command`` with ``startProcess``
   ## and returns its output as a string.
@@ -203,13 +203,13 @@ proc select*(readfds: var seq[PProcess], timeout = 500): int
 when not defined(useNimRtl):
   proc execProcess(command: string,
                    options: set[TProcessOption] = {poStdErrToStdOut,
-                                                   poUseShell}): string =
+                                                   poUseShell}): TaintedString =
     var p = startProcessAux(command, options=options)
     var outp = outputStream(p)
-    result = ""
+    result = TaintedString""
     while running(p) or not outp.atEnd(outp):
-      result.add(outp.readLine())
-      result.add("\n")
+      result.string.add(outp.readLine().string)
+      result.string.add("\n")
     outp.close(outp)
     close(p)
 
diff --git a/lib/pure/redis.nim b/lib/pure/redis.nim
index 434378b04..7d5fce710 100755
--- a/lib/pure/redis.nim
+++ b/lib/pure/redis.nim
@@ -49,7 +49,7 @@ proc raiseNoOK(status: string) =
     raise newException(EInvalidReply, "Expected \"OK\" got \"$1\"" % status)
 
 proc parseStatus(r: TRedis): TRedisStatus =
-  var line = r.socket.recv()
+  var line = r.socket.recv.string
   
   if line[0] == '-':
     raise newException(ERedis, strip(line))
@@ -59,7 +59,7 @@ proc parseStatus(r: TRedis): TRedisStatus =
   return line.substr(1, line.len-3) # Strip '+' and \c\L.
   
 proc parseInteger(r: TRedis): TRedisInteger =
-  var line = r.socket.recv()
+  var line = r.socket.recv.string
 
   if line[0] == '-':
     raise newException(ERedis, strip(line))
@@ -70,14 +70,14 @@ proc parseInteger(r: TRedis): TRedisInteger =
   if parseBiggestInt(line, result, 1) == 0:
     raise newException(EInvalidReply, "Unable to parse integer.") 
 
-proc recv(sock: TSocket, size: int): string =
-  result = newString(size)
+proc recv(sock: TSocket, size: int): TaintedString =
+  result = newString(size).TaintedString
   if sock.recv(cstring(result), size) != size:
     raise newException(EInvalidReply, "recv failed")
 
 proc parseBulk(r: TRedis, allowMBNil = False): TRedisString =
   var line = ""
-  if not r.socket.recvLine(line):
+  if not r.socket.recvLine(line.TaintedString):
     raise newException(EInvalidReply, "recvLine failed")
   
   # Error.
@@ -97,17 +97,17 @@ proc parseBulk(r: TRedis, allowMBNil = False): TRedisString =
     return RedisNil
 
   var s = r.socket.recv(numBytes+2)
-  result = strip(s)
+  result = strip(s.string)
 
 proc parseMultiBulk(r: TRedis): TRedisList =
-  var line = ""
+  var line = TaintedString""
   if not r.socket.recvLine(line):
     raise newException(EInvalidReply, "recvLine failed")
     
-  if line[0] != '*':
-    raiseInvalidReply('*', line[0])
+  if line.string[0] != '*':
+    raiseInvalidReply('*', line.string[0])
   
-  var numElems = parseInt(line.substr(1))
+  var numElems = parseInt(line.string.substr(1))
   if numElems == -1: return nil
   result = @[]
   for i in 1..numElems:
@@ -839,7 +839,7 @@ proc shutdown*(r: TRedis) =
   ## Synchronously save the dataset to disk and then shut down the server
   r.sendCommand("SHUTDOWN")
   var s = r.socket.recv()
-  if s != "": raise newException(ERedis, s)
+  if s.string.len != 0: raise newException(ERedis, s.string)
 
 proc slaveof*(r: TRedis, host: string, port: string) =
   ## Make the server a slave of another instance, or promote it as master
diff --git a/lib/pure/smtp.nim b/lib/pure/smtp.nim
index 0dd9f3eca..6137fc02b 100755
--- a/lib/pure/smtp.nim
+++ b/lib/pure/smtp.nim
@@ -59,8 +59,8 @@ proc debugSend(smtp: TSMTP, cmd: string) =
     when not defined(noSSL):
       smtp.sslSock.send(cmd)
 
-proc debugRecv(smtp: TSMTP): string =
-  var line = ""
+proc debugRecv(smtp: TSMTP): TaintedString =
+  var line = TaintedString""
   var ret = False
   if not smtp.ssl:
     ret = smtp.sock.recvLine(line)
@@ -69,11 +69,11 @@ proc debugRecv(smtp: TSMTP): string =
       ret = smtp.sslSock.recvLine(line)
   if ret:
     if smtp.debug:
-      echo("S:" & line)
+      echo("S:" & line.string)
     return line
   else:
     OSError()
-    return ""
+    return TaintedString""
 
 proc quitExcpt(smtp: TSMTP, msg: string) =
   smtp.debugSend("QUIT")
@@ -81,8 +81,8 @@ proc quitExcpt(smtp: TSMTP, msg: string) =
 
 proc checkReply(smtp: TSMTP, reply: string) =
   var line = smtp.debugRecv()
-  if not line.startswith(reply):
-    quitExcpt(smtp, "Expected " & reply & " reply, got: " & line)
+  if not line.string.startswith(reply):
+    quitExcpt(smtp, "Expected " & reply & " reply, got: " & line.string)
 
 proc connect*(address: string, port = 25, 
               ssl = false, debug = false): TSMTP =
diff --git a/lib/pure/sockets.nim b/lib/pure/sockets.nim
index c07974897..e1851301e 100755
--- a/lib/pure/sockets.nim
+++ b/lib/pure/sockets.nim
@@ -553,17 +553,28 @@ proc recv*(socket: TSocket): TaintedString =
   ## If socket is not a connectionless socket and socket is not connected
   ## ``""`` will be returned.
   const bufSize = 1000
-  var buf = newString(bufSize)
-  result = TaintedString""
+  result = newStringOfCap(bufSize).TaintedString
+  var pos = 0
   while true:
-    var bytesRead = recv(socket, cstring(buf), bufSize-1)
-    # Error
+    var bytesRead = recv(socket, addr(string(result)[pos]), bufSize-1)
     if bytesRead == -1: OSError()
-    
-    buf[bytesRead] = '\0' # might not be necessary
-    setLen(buf, bytesRead)
-    add(result.string, buf)
+    setLen(result.string, pos + bytesRead)
     if bytesRead != bufSize-1: break
+    # increase capacity:
+    setLen(result.string, result.string.len + bufSize)
+    inc(pos, bytesRead)
+  when false:
+    var buf = newString(bufSize)
+    result = TaintedString""
+    while true:
+      var bytesRead = recv(socket, cstring(buf), bufSize-1)
+      # Error
+      if bytesRead == -1: OSError()
+      
+      buf[bytesRead] = '\0' # might not be necessary
+      setLen(buf, bytesRead)
+      add(result.string, buf)
+      if bytesRead != bufSize-1: break
 
 proc recvAsync*(socket: TSocket, s: var TaintedString): bool =
   ## receives all the data from a non-blocking socket. If socket is non-blocking 
@@ -572,11 +583,12 @@ proc recvAsync*(socket: TSocket, s: var TaintedString): bool =
   ## If socket is not a connectionless socket and socket is not connected
   ## ``s`` will be set to ``""``.
   const bufSize = 1000
-  var buf = newString(bufSize)
-  s = ""
+  # ensure bufSize capacity:
+  setLen(s.string, bufSize)
+  setLen(s.string, 0)
+  var pos = 0
   while true:
-    var bytesRead = recv(socket, cstring(buf), bufSize-1)
-    # Error
+    var bytesRead = recv(socket, addr(string(s)[pos]), bufSize-1)
     if bytesRead == -1:
       when defined(windows):
         # TODO: Test on Windows
@@ -588,11 +600,12 @@ proc recvAsync*(socket: TSocket, s: var TaintedString): bool =
         if errno == EAGAIN or errno == EWOULDBLOCK:
           return False
         else: OSError()
-    
-    buf[bytesRead] = '\0' # might not be necessary
-    setLen(buf, bytesRead)
-    add(s, buf)
+
+    setLen(s.string, pos + bytesRead)
     if bytesRead != bufSize-1: break
+    # increase capacity:
+    setLen(s.string, s.string.len + bufSize)
+    inc(pos, bytesRead)
   result = True
   
 proc skip*(socket: TSocket) =