summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2013-06-27 19:57:24 +0200
committerAraq <rumpf_a@web.de>2013-06-27 19:57:24 +0200
commitb6f2902905443434ca6d83556168555ab9ddee72 (patch)
tree6d078b3b169f146f276463cde1a743c56c1977e8
parent83876b1b8113ddeaa1b0376d39ef2da2525a73b3 (diff)
parenta9f2c3ffaf0959be03c290f9e72ed71495b156aa (diff)
downloadNim-b6f2902905443434ca6d83556168555ab9ddee72.tar.gz
Merge branch 'master' of github.com:Araq/Nimrod
-rw-r--r--lib/pure/httpserver.nim202
-rw-r--r--lib/pure/memfiles.nim34
-rw-r--r--lib/pure/redis.nim59
-rw-r--r--tests/compile/tsockets.nim6
4 files changed, 150 insertions, 151 deletions
diff --git a/lib/pure/httpserver.nim b/lib/pure/httpserver.nim
index 61399c2d8..e24709451 100644
--- a/lib/pure/httpserver.nim
+++ b/lib/pure/httpserver.nim
@@ -47,10 +47,11 @@ proc badRequest(client: TSocket) =
   send(client, "<p>Your browser sent a bad request, " &
                "such as a POST without a Content-Length.</p>" & wwwNL)
 
-proc cannotExec(client: TSocket) =
-  send(client, "HTTP/1.1 500 Internal Server Error" & wwwNL)
-  sendTextContentType(client)
-  send(client, "<P>Error prohibited CGI execution." & wwwNL)
+when false:
+  proc cannotExec(client: TSocket) =
+    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) =
   # XXX could use filename to determine file type
@@ -79,11 +80,11 @@ proc unimplemented(client: TSocket) =
 
 # ----------------- file serving ---------------------------------------------
 
-proc discardHeaders(client: TSocket) = skip(client)
+when false:
+  proc discardHeaders(client: TSocket) = skip(client)
 
 proc serveFile*(client: TSocket, filename: string) =
   ## serves a file to the client.
-  when false: discardHeaders(client)
   var f: TFile
   if open(f, filename):
     headers(client, filename)
@@ -96,7 +97,7 @@ proc serveFile*(client: TSocket, filename: string) =
         if bytesread != bytesWritten:
           dealloc(buf)
           close(f)
-          OSError()
+          OSError(OSLastError())
       if bytesread != bufSize: break
     dealloc(buf)
     close(f)
@@ -104,108 +105,109 @@ proc serveFile*(client: TSocket, filename: string) =
     notFound(client)
 
 # ------------------ CGI execution -------------------------------------------
+when false:
+  # TODO: Fix this, or get rid of it.
+  type
+    TRequestMethod = enum reqGet, reqPost
+
+  proc executeCgi(client: TSocket, path, query: string, meth: TRequestMethod) =
+    var env = newStringTable(modeCaseInsensitive)
+    var contentLength = -1
+    case meth
+    of reqGet:
+      discardHeaders(client)
+
+      env["REQUEST_METHOD"] = "GET"
+      env["QUERY_STRING"] = query
+    of reqPost:
+      var buf = TaintedString""
+      var dataAvail = false
+      while dataAvail:
+        dataAvail = recvLine(client, buf) # TODO: This is incorrect.
+        var L = toLower(buf.string)
+        if L.startsWith("content-length:"):
+          var i = len("content-length:")
+          while L[i] in Whitespace: inc(i)
+          contentLength = parseInt(substr(L, i))
+
+      if contentLength < 0:
+        badRequest(client)
+        return
 
-type
-  TRequestMethod = enum reqGet, reqPost
-
-proc executeCgi(client: TSocket, path, query: string, meth: TRequestMethod) =
-  var env = newStringTable(modeCaseInsensitive)
-  var contentLength = -1
-  case meth
-  of reqGet:
-    discardHeaders(client)
-
-    env["REQUEST_METHOD"] = "GET"
-    env["QUERY_STRING"] = query
-  of reqPost:
-    var buf = TaintedString""
-    var dataAvail = false
-    while dataAvail:
-      dataAvail = recvLine(client, buf) # TODO: This is incorrect.
-      var L = toLower(buf.string)
-      if L.startsWith("content-length:"):
-        var i = len("content-length:")
-        while L[i] in Whitespace: inc(i)
-        contentLength = parseInt(substr(L, i))
-
-    if contentLength < 0:
-      badRequest(client)
-      return
-
-    env["REQUEST_METHOD"] = "POST"
-    env["CONTENT_LENGTH"] = $contentLength
+      env["REQUEST_METHOD"] = "POST"
+      env["CONTENT_LENGTH"] = $contentLength
 
-  send(client, "HTTP/1.0 200 OK" & wwwNL)
+    send(client, "HTTP/1.0 200 OK" & wwwNL)
 
-  var process = startProcess(command=path, env=env)
-  if meth == reqPost:
-    # get from client and post to CGI program:
-    var buf = alloc(contentLength)
-    if recv(client, buf, contentLength) != contentLength: 
+    var process = startProcess(command=path, env=env)
+    if meth == reqPost:
+      # get from client and post to CGI program:
+      var buf = alloc(contentLength)
+      if recv(client, buf, contentLength) != contentLength: 
+        dealloc(buf)
+        OSError()
+      var inp = process.inputStream
+      inp.writeData(buf, contentLength)
       dealloc(buf)
-      OSError()
-    var inp = process.inputStream
-    inp.writeData(buf, contentLength)
-    dealloc(buf)
 
-  var outp = process.outputStream
-  var line = newStringOfCap(120).TaintedString
-  while true:
-    if outp.readLine(line):
-      send(client, line.string)
-      send(client, wwwNL)
-    elif not running(process): break
-
-# --------------- Server Setup -----------------------------------------------
-
-proc acceptRequest(client: TSocket) =
-  var cgi = false
-  var query = ""
-  var buf = TaintedString""
-  discard recvLine(client, buf)
-  var path = ""
-  var data = buf.string.split()
-  var meth = reqGet
-
-  var q = find(data[1], '?')
-
-  # extract path
-  if q >= 0:
-    # strip "?..." from path, this may be found in both POST and GET
-    path = "." & data[1].substr(0, q-1)
-  else:
-    path = "." & data[1]
-  # path starts with "/", by adding "." in front of it we serve files from cwd
-  
-  if cmpIgnoreCase(data[0], "GET") == 0:
-    if q >= 0:
-      cgi = true
-      query = data[1].substr(q+1)
-  elif cmpIgnoreCase(data[0], "POST") == 0:
-    cgi = true
-    meth = reqPost
-  else:
-    unimplemented(client)
+    var outp = process.outputStream
+    var line = newStringOfCap(120).TaintedString
+    while true:
+      if outp.readLine(line):
+        send(client, line.string)
+        send(client, wwwNL)
+      elif not running(process): break
 
-  if path[path.len-1] == '/' or existsDir(path):
-    path = path / "index.html"
+  # --------------- Server Setup -----------------------------------------------
 
-  if not ExistsFile(path):
-    discardHeaders(client)
-    notFound(client)
-  else:
-    when defined(Windows):
-      var ext = splitFile(path).ext.toLower
-      if ext == ".exe" or ext == ".cgi":
-        # XXX: extract interpreter information here?
-        cgi = true
+  proc acceptRequest(client: TSocket) =
+    var cgi = false
+    var query = ""
+    var buf = TaintedString""
+    discard recvLine(client, buf)
+    var path = ""
+    var data = buf.string.split()
+    var meth = reqGet
+
+    var q = find(data[1], '?')
+
+    # extract path
+    if q >= 0:
+      # strip "?..." from path, this may be found in both POST and GET
+      path = "." & data[1].substr(0, q-1)
     else:
-      if {fpUserExec, fpGroupExec, fpOthersExec} * path.getFilePermissions != {}:
+      path = "." & data[1]
+    # path starts with "/", by adding "." in front of it we serve files from cwd
+    
+    if cmpIgnoreCase(data[0], "GET") == 0:
+      if q >= 0:
         cgi = true
-    if not cgi:
-      serveFile(client, path)
+        query = data[1].substr(q+1)
+    elif cmpIgnoreCase(data[0], "POST") == 0:
+      cgi = true
+      meth = reqPost
+    else:
+      unimplemented(client)
+
+    if path[path.len-1] == '/' or existsDir(path):
+      path = path / "index.html"
+
+    if not ExistsFile(path):
+      discardHeaders(client)
+      notFound(client)
     else:
-      executeCgi(client, path, query, meth)
+      when defined(Windows):
+        var ext = splitFile(path).ext.toLower
+        if ext == ".exe" or ext == ".cgi":
+          # XXX: extract interpreter information here?
+          cgi = true
+      else:
+        if {fpUserExec, fpGroupExec, fpOthersExec} * path.getFilePermissions != {}:
+          cgi = true
+      if not cgi:
+        serveFile(client, path)
+      else:
+        executeCgi(client, path, query, meth)
 
 type
   TServer* = object of TObject  ## contains the current server state
@@ -226,7 +228,7 @@ proc open*(s: var TServer, port = TPort(80)) =
   ## 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)
-  if s.socket == InvalidSocket: OSError()
+  if s.socket == InvalidSocket: OSError(OSLastError())
   bindAddr(s.socket, port)
   listen(s.socket)
 
diff --git a/lib/pure/memfiles.nim b/lib/pure/memfiles.nim
index 84a87ba15..9f4094b40 100644
--- a/lib/pure/memfiles.nim
+++ b/lib/pure/memfiles.nim
@@ -50,11 +50,11 @@ proc open*(filename: string, mode: TFileMode = fmRead,
     result.size = 0
 
   when defined(windows):
-    template fail(msg: expr) =
+    template fail(errCode: TOSErrorCode, msg: expr) =
       rollback()
       if result.fHandle != 0: discard CloseHandle(result.fHandle)
       if result.mapHandle != 0: discard CloseHandle(result.mapHandle)
-      OSError()
+      OSError(errCode)
       # return false
       #raise newException(EIO, msg)
 
@@ -74,7 +74,7 @@ proc open*(filename: string, mode: TFileMode = fmRead,
       result.fHandle = callCreateFile(CreateFileA, filename)
 
     if result.fHandle == INVALID_HANDLE_VALUE:
-      fail "error opening file"
+      fail(OSLastError(), "error opening file")
 
     if newFileSize != -1:
       var 
@@ -83,9 +83,10 @@ proc open*(filename: string, mode: TFileMode = fmRead,
 
       var status = SetFilePointer(result.fHandle, sizeLow, addr(sizeHigh),
                                   FILE_BEGIN)
-      if (status == INVALID_SET_FILE_POINTER and GetLastError() != NO_ERROR) or
+      let lastErr = OSLastError()
+      if (status == INVALID_SET_FILE_POINTER and lastErr.int32 != NO_ERROR) or
          (SetEndOfFile(result.fHandle) == 0):
-        fail "error setting file size"
+        fail(lastErr, "error setting file size")
 
     # since the strings are always 'nil', we simply always call
     # CreateFileMappingW which should be slightly faster anyway:
@@ -95,7 +96,7 @@ proc open*(filename: string, mode: TFileMode = fmRead,
       0, 0, nil)
 
     if result.mapHandle == 0:
-      fail "error creating mapping"
+      fail(OSLastError(), "error creating mapping")
 
     result.mem = MapViewOfFileEx(
       result.mapHandle,
@@ -106,22 +107,22 @@ proc open*(filename: string, mode: TFileMode = fmRead,
       nil)
 
     if result.mem == nil:
-      fail "error mapping view"
+      fail(OSLastError(), "error mapping view")
 
     var hi, low: int32
     low = GetFileSize(result.fHandle, addr(hi))
     if low == INVALID_FILE_SIZE:
-      fail "error getting file size"
+      fail(OSLastError(), "error getting file size")
     else:
       var fileSize = (int64(hi) shr 32) or low
       if mappedSize != -1: result.size = min(fileSize, mappedSize).int
       else: result.size = fileSize.int
 
   else:
-    template fail(msg: expr) =
+    template fail(errCode: TOSErrorCode, msg: expr) =
       rollback()
       if result.handle != 0: discard close(result.handle)
-      OSError()
+      OSError(errCode)
   
     var flags = if readonly: O_RDONLY else: O_RDWR
 
@@ -132,11 +133,11 @@ proc open*(filename: string, mode: TFileMode = fmRead,
     if result.handle == -1:
       # XXX: errno is supposed to be set here
       # Is there an exception that wraps it?
-      fail "error opening file"
+      fail(OSLastError(), "error opening file")
 
     if newFileSize != -1:
       if ftruncate(result.handle, newFileSize) == -1:
-        fail "error setting file size"
+        fail(OSLastError(), "error setting file size")
 
     if mappedSize != -1:
       result.size = mappedSize
@@ -147,7 +148,7 @@ proc open*(filename: string, mode: TFileMode = fmRead,
         # Why is mmap taking int anyway?
         result.size = int(stat.st_size)
       else:
-        fail "error getting file size"
+        fail(OSLastError(), "error getting file size")
 
     result.mem = mmap(
       nil,
@@ -158,21 +159,24 @@ proc open*(filename: string, mode: TFileMode = fmRead,
       offset)
 
     if result.mem == cast[pointer](MAP_FAILED):
-      fail "file mapping failed"
+      fail(OSLastError(), "file mapping failed")
 
 proc close*(f: var TMemFile) =
   ## closes the memory mapped file `f`. All changes are written back to the
   ## file system, if `f` was opened with write access.
   
   var error = false
+  var lastErr: TOSErrorCode
 
   when defined(windows):
     if f.fHandle != INVALID_HANDLE_VALUE:
+      lastErr = OSLastError()
       error = UnmapViewOfFile(f.mem) == 0
       error = (CloseHandle(f.mapHandle) == 0) or error
       error = (CloseHandle(f.fHandle) == 0) or error
   else:
     if f.handle != 0:
+      lastErr = OSLastError()
       error = munmap(f.mem, f.size) != 0
       error = (close(f.handle) != 0) or error
 
@@ -185,5 +189,5 @@ proc close*(f: var TMemFile) =
   else:
     f.handle = 0
   
-  if error: OSError()
+  if error: OSError(lastErr)
 
diff --git a/lib/pure/redis.nim b/lib/pure/redis.nim
index bb6ea6768..8171dc12b 100644
--- a/lib/pure/redis.nim
+++ b/lib/pure/redis.nim
@@ -36,7 +36,7 @@ proc open*(host = "localhost", port = 6379.TPort): TRedis =
   ## Opens a connection to the redis server.
   result.socket = socket(buffered = false)
   if result.socket == InvalidSocket:
-    OSError()
+    OSError(OSLastError())
   result.socket.connect(host, port)
 
 proc raiseInvalidReply(expected, got: char) =
@@ -50,34 +50,31 @@ proc raiseNoOK(status: string) =
 
 proc parseStatus(r: TRedis): TRedisStatus =
   var line = ""
-  if r.socket.recvLine(line):
-    if line == "":
-      raise newException(ERedis, "Server closed connection prematurely")
+  r.socket.readLine(line)
+  if line == "":
+    raise newException(ERedis, "Server closed connection prematurely")
+
+  if line[0] == '-':
+    raise newException(ERedis, strip(line))
+  if line[0] != '+':
+    raiseInvalidReply('+', line[0])
   
-    if line[0] == '-':
-      raise newException(ERedis, strip(line))
-    if line[0] != '+':
-      raiseInvalidReply('+', line[0])
-    
-    return line.substr(1) # Strip '+'
-  else:
-    OSError()
+  return line.substr(1) # Strip '+'
   
 proc parseInteger(r: TRedis): TRedisInteger =
   var line = ""
-  if r.socket.recvLine(line):
-    if line == "":
-      raise newException(ERedis, "Server closed connection prematurely")
-
-    if line[0] == '-':
-      raise newException(ERedis, strip(line))
-    if line[0] != ':':
-      raiseInvalidReply(':', line[0])
-    
-    # Strip ':'
-    if parseBiggestInt(line, result, 1) == 0:
-      raise newException(EInvalidReply, "Unable to parse integer.") 
-  else: OSError()
+  r.socket.readLine(line)
+  if line == "":
+    raise newException(ERedis, "Server closed connection prematurely")
+
+  if line[0] == '-':
+    raise newException(ERedis, strip(line))
+  if line[0] != ':':
+    raiseInvalidReply(':', line[0])
+  
+  # Strip ':'
+  if parseBiggestInt(line, result, 1) == 0:
+    raise newException(EInvalidReply, "Unable to parse integer.") 
 
 proc recv(sock: TSocket, size: int): TaintedString =
   result = newString(size).TaintedString
@@ -86,8 +83,7 @@ proc recv(sock: TSocket, size: int): TaintedString =
 
 proc parseBulk(r: TRedis, allowMBNil = False): TRedisString =
   var line = ""
-  if not r.socket.recvLine(line.TaintedString):
-    raise newException(EInvalidReply, "recvLine failed")
+  r.socket.readLine(line.TaintedString)
   
   # Error.
   if line[0] == '-':
@@ -110,8 +106,7 @@ proc parseBulk(r: TRedis, allowMBNil = False): TRedisString =
 
 proc parseMultiBulk(r: TRedis): TRedisList =
   var line = TaintedString""
-  if not r.socket.recvLine(line):
-    raise newException(EInvalidReply, "recvLine failed")
+  r.socket.readLine(line)
     
   if line.string[0] != '*':
     raiseInvalidReply('*', line.string[0])
@@ -848,10 +843,8 @@ proc shutdown*(r: TRedis) =
   ## Synchronously save the dataset to disk and then shut down the server
   r.sendCommand("SHUTDOWN")
   var s = "".TaintedString
-  if r.socket.recvLine(s):
-    if s.string.len != 0: raise newException(ERedis, s.string)
-  else:
-    OSError()
+  r.socket.readLine(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/tests/compile/tsockets.nim b/tests/compile/tsockets.nim
index cc7d18b87..6078504f5 100644
--- a/tests/compile/tsockets.nim
+++ b/tests/compile/tsockets.nim
@@ -4,8 +4,8 @@ s = socket()
 
 s.connect("www.google.com", TPort(80))
 
-var recvData: string = ""
-echo(s.recvLine(recvData))
-echo(recvData)
+var data: string = ""
+s.readLine(data)
+echo(data)