about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--src/loader/loader.nim71
1 files changed, 39 insertions, 32 deletions
diff --git a/src/loader/loader.nim b/src/loader/loader.nim
index b08d66a6..54ecb77d 100644
--- a/src/loader/loader.nim
+++ b/src/loader/loader.nim
@@ -273,8 +273,17 @@ proc addFd(ctx: LoaderContext; handle: InputHandle) =
 type ControlResult = enum
   crDone, crContinue, crError
 
-proc handleFirstLine(handle: InputHandle; line: string; headers: Headers;
-    status: var uint16): ControlResult =
+proc handleFirstLine(handle: InputHandle; line: string): ControlResult =
+  if line.startsWithIgnoreCase("HTTP/1.0") or
+      line.startsWithIgnoreCase("HTTP/1.1"):
+    let codes = line.until(' ', "HTTP/1.0 ".len)
+    let code = parseUInt16(codes)
+    if codes.len > 3 or code.isNone:
+      handle.sendResult(ceCGIMalformedHeader)
+      return crError
+    handle.sendResult(0) # Success
+    handle.parser.status = code.get
+    return crDone
   let k = line.until(':')
   if k.len == line.len:
     # invalid
@@ -283,67 +292,67 @@ proc handleFirstLine(handle: InputHandle; line: string; headers: Headers;
   let v = line.substr(k.len + 1).strip()
   if k.equalsIgnoreCase("Status"):
     handle.sendResult(0) # success
-    status = parseUInt16(v, allowSign = false).get(0)
+    let code = parseUInt16(v)
+    if v.len > 3 or code.isNone:
+      handle.sendResult(ceCGIMalformedHeader)
+      return crError
+    handle.parser.status = code.get
     return crContinue
   if k.equalsIgnoreCase("Cha-Control"):
     if v.startsWithIgnoreCase("Connected"):
       handle.sendResult(0) # success
       return crContinue
-    elif v.startsWithIgnoreCase("ConnectionError"):
+    if v.startsWithIgnoreCase("ConnectionError"):
       let errs = v.split(' ')
-      if errs.len <= 1:
-        handle.sendResult(ceCGIInvalidChaControl)
-      else:
-        var code = int32(ceCGIInvalidChaControl)
+      var code = int32(ceCGIInvalidChaControl)
+      var message = ""
+      if errs.len > 1:
         if (let x = parseInt32(errs[1]); x.isSome):
           code = x.get
         elif (let x = strictParseEnum[ConnectionError](errs[1]); x.isSome):
           code = int32(x.get)
-        var message = ""
         if errs.len > 2:
           message &= errs[2]
           for i in 3 ..< errs.len:
             message &= ' '
             message &= errs[i]
-        handle.sendResult(code, message)
+      handle.sendResult(code, message)
       return crError
-    elif v.startsWithIgnoreCase("ControlDone"):
+    if v.startsWithIgnoreCase("ControlDone"):
       return crDone
     handle.sendResult(ceCGIInvalidChaControl)
     return crError
   handle.sendResult(0) # success
-  headers.add(k, v)
+  handle.parser.headers.add(k, v)
   return crDone
 
-proc handleControlLine(handle: InputHandle; line: string; headers: Headers;
-    status: var uint16): ControlResult =
+proc handleControlLine(handle: InputHandle; line: string): ControlResult =
   let k = line.until(':')
   if k.len == line.len:
     # invalid
     return crError
   let v = line.substr(k.len + 1).strip()
   if k.equalsIgnoreCase("Status"):
-    status = parseUInt16(v, allowSign = false).get(0)
+    let code = parseUInt16(v)
+    if v.len > 3 or code.isNone:
+      return crError
+    handle.parser.status = parseUInt16(v).get(0)
     return crContinue
   if k.equalsIgnoreCase("Cha-Control"):
     if v.startsWithIgnoreCase("ControlDone"):
       return crDone
     return crError
-  headers.add(k, v)
+  handle.parser.headers.add(k, v)
   return crDone
 
-# returns false if transfer was interrupted
-proc handleLine(handle: InputHandle; line: string; headers: Headers) =
+proc handleLine(handle: InputHandle; line: string) =
   let k = line.until(':')
-  if k.len == line.len:
-    # invalid
-    return
-  let v = line.substr(k.len + 1).strip()
-  headers.add(k, v)
+  if k.len < line.len:
+    let v = line.substr(k.len + 1).strip()
+    handle.parser.headers.add(k, v)
 
 proc parseHeaders0(handle: InputHandle; data: openArray[char]): int =
   let parser = handle.parser
-  var s = parser.lineBuffer
   for i, c in data:
     template die =
       handle.parser = nil
@@ -354,7 +363,7 @@ proc parseHeaders0(handle: InputHandle; data: openArray[char]): int =
     if c == '\r':
       parser.crSeen = true
     elif c == '\n':
-      if s == "":
+      if parser.lineBuffer == "":
         if parser.state == hpsBeforeLines:
           # body comes immediately, so we haven't had a chance to send result
           # yet.
@@ -365,22 +374,20 @@ proc parseHeaders0(handle: InputHandle; data: openArray[char]): int =
         return i + 1 # +1 to skip \n
       case parser.state
       of hpsBeforeLines:
-        case handle.handleFirstLine(s, parser.headers, parser.status)
+        case handle.handleFirstLine(parser.lineBuffer)
         of crDone: parser.state = hpsControlDone
         of crContinue: parser.state = hpsAfterFirstLine
         of crError: die
       of hpsAfterFirstLine:
-        case handle.handleControlLine(s, parser.headers, parser.status)
+        case handle.handleControlLine(parser.lineBuffer)
         of crDone: parser.state = hpsControlDone
         of crContinue: discard
         of crError: die
       of hpsControlDone:
-        handle.handleLine(s, parser.headers)
-      s = ""
+        handle.handleLine(parser.lineBuffer)
+      parser.lineBuffer = ""
     else:
-      s &= c
-  if s != "":
-    parser.lineBuffer = s
+      parser.lineBuffer &= c
   return data.len
 
 proc parseHeaders(handle: InputHandle; buffer: LoaderBuffer): int =