summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rwxr-xr-xlib/pure/httpserver.nim34
-rwxr-xr-xlib/pure/sockets.nim30
-rwxr-xr-xweb/news.txt3
3 files changed, 56 insertions, 11 deletions
diff --git a/lib/pure/httpserver.nim b/lib/pure/httpserver.nim
index 57d5a8577..52d5decf2 100755
--- a/lib/pure/httpserver.nim
+++ b/lib/pure/httpserver.nim
@@ -208,6 +208,7 @@ type
     port: TPort
     client*: TSocket      ## the socket to write the file data to
     path*, query*: string ## path and query the client requested
+    headers*: PStringTable ## headers with which the client made the request
 
 proc open*(s: var TServer, port = TPort(80)) =
   ## creates a new server at port `port`. If ``port == 0`` a free port is
@@ -224,6 +225,7 @@ proc open*(s: var TServer, port = TPort(80)) =
   s.client = InvalidSocket
   s.path = ""
   s.query = ""
+  s.headers = {:}.newStringTable()
 
 proc port*(s: var TServer): TPort =
   ## get the port number the server has acquired.
@@ -232,15 +234,39 @@ proc port*(s: var TServer): TPort =
 proc next*(s: var TServer) =
   ## proceed to the first/next request.
   s.client = accept(s.socket)
-  headers(s.client, "")
-  var data = recv(s.client).string
-  #discard recvLine(s.client, data)
+  s.headers = {:}.newStringTable()
+  #headers(s.client, "")
+  var data = ""
+  while not s.client.recvLine(data): nil
+  if data == "":
+    # Socket disconnected 
+    s.client.close()
+    next(s)
+    return
+  var header = ""
+  while true:
+    if s.client.recvLine(header):
+      if header == "\c\L": break
+      if header != "":
+        var i = 0
+        var key = ""
+        var value = ""
+        i = header.parseUntil(key, ':')
+        i += header.skipWhiteSpace(i)
+        i += header.parseUntil(value, whitespace, i)
+        s.headers[key] = value
+      else:
+        s.client.close()
+        next(s)
+        return
   
   var i = skipWhitespace(data)
   if skipIgnoreCase(data, "GET") > 0: inc(i, 3)
   elif skipIgnoreCase(data, "POST") > 0: inc(i, 4)
-  else: 
+  else:
     unimplemented(s.client)
+    s.client.close()
+    next(s)
     return
   
   var L = skipWhitespace(data, i)
diff --git a/lib/pure/sockets.nim b/lib/pure/sockets.nim
index 31973c6ce..eeec62843 100755
--- a/lib/pure/sockets.nim
+++ b/lib/pure/sockets.nim
@@ -581,10 +581,19 @@ proc recv*(socket: TSocket, data: var string, size: int, timeout: int): int =
   result = read
 
 proc recvLine*(socket: TSocket, line: var TaintedString): bool =
-  ## returns false if no further data is available. `Line` must be initialized
-  ## and not nil! This does not throw an EOS exception.
-  ## If ``socket`` is disconnected, ``true`` will be returned and line will be
-  ## set to ``""``.
+  ## retrieves a line from ``socket``. If a full line is received ``\r\L`` is not
+  ## added to ``line``, however if solely ``\r\L`` is received then ``data``
+  ## will be set to it.
+  ## 
+  ## ``True`` is returned if data is available. ``False`` usually suggests an
+  ## error, EOS exceptions are not raised in favour of this.
+  ## 
+  ## If the socket is disconnected, ``line`` will be set to ``""`` and ``True``
+  ## will be returned.
+  template addNLIfEmpty(): stmt =
+    if line.len == 0:
+      line.add("\c\L")
+
   setLen(line.string, 0)
   while true:
     var c: char
@@ -596,13 +605,19 @@ proc recvLine*(socket: TSocket, line: var TaintedString): bool =
       if n > 0 and c == '\L':
         discard recv(cint(socket), addr(c), 1, 0'i32)
       elif n <= 0: return false
+      addNlIfEmpty()
+      return true
+    elif c == '\L': 
+      addNlIfEmpty()
       return true
-    elif c == '\L': return true
     add(line.string, c)
 
 proc recvLine*(socket: TSocket, line: var TaintedString, timeout: int): bool =
   ## variant with a ``timeout`` parameter, the timeout parameter specifies
   ## how many miliseconds to wait for data.
+  template addNLIfEmpty(): stmt =
+    if line.len == 0:
+      line.add("\c\L")
   
   var waited = 0.0 # number of seconds already waited
   
@@ -619,8 +634,11 @@ proc recvLine*(socket: TSocket, line: var TaintedString, timeout: int): bool =
       if n > 0 and c == '\L':
         discard recv(cint(socket), addr(c), 1, 0'i32)
       elif n <= 0: return false
+      addNlIfEmpty()
+      return true
+    elif c == '\L': 
+      addNlIfEmpty()
       return true
-    elif c == '\L': return true
     add(line.string, c)
 
 proc recvLineAsync*(socket: TSocket, line: var TaintedString): TRecvLineResult =
diff --git a/web/news.txt b/web/news.txt
index 64d0ce928..578e2203c 100755
--- a/web/news.txt
+++ b/web/news.txt
@@ -15,7 +15,8 @@ Bugfixes
 - Fixed a bug concerning implicit type conversions in ``case`` statements.
 - Fixed a serious code generation bug that caused ``algorithm.sort`` to
   produce segmentation faults.
-
+- Fixed ambiguity in recvLine which meant that receiving ``\r\L`` was
+  indistinguishable from disconnections.
 
 Library Additions
 -----------------