about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/html/dom.nim2
-rw-r--r--src/loader/connecterror.nim1
-rw-r--r--src/loader/loader.nim42
-rw-r--r--src/loader/loaderhandle.nim7
4 files changed, 31 insertions, 21 deletions
diff --git a/src/html/dom.nim b/src/html/dom.nim
index 265810ce..be297d70 100644
--- a/src/html/dom.nim
+++ b/src/html/dom.nim
@@ -2936,7 +2936,7 @@ proc loadResource(window: Window; image: HTMLImageElement) =
         response.unregisterFun()
         response.body.sclose()
         if "X-Image-Dimensions" notin response.headers.table:
-          window.console.error("X-Image-Dimensions missing")
+          window.console.error("X-Image-Dimensions missing in", $response.url)
           return
         let dims = response.headers.table["X-Image-Dimensions"][0]
         let width = parseUInt64(dims.until('x'), allowSign = false)
diff --git a/src/loader/connecterror.nim b/src/loader/connecterror.nim
index 08f7b436..c3099b0f 100644
--- a/src/loader/connecterror.nim
+++ b/src/loader/connecterror.nim
@@ -1,4 +1,5 @@
 type ConnectErrorCode* = enum
+  ERROR_FAILED_TO_REDIRECT = (-17, "failed to redirect request body")
   ERROR_URL_NOT_IN_CACHE = (-16, "URL was not found in the cache")
   ERROR_FILE_NOT_IN_CACHE = (-15, "file was not found in the cache")
   ERROR_FAILED_TO_EXECUTE_CGI_SCRIPT = (-14, "failed to execute CGI script")
diff --git a/src/loader/loader.nim b/src/loader/loader.nim
index 89d97cde..f0ecb384 100644
--- a/src/loader/loader.nim
+++ b/src/loader/loader.nim
@@ -216,16 +216,21 @@ proc getOutputId(ctx: LoaderContext): int =
 
 proc redirectToStream(ctx: LoaderContext; output: OutputHandle;
     ps: PosixStream): bool =
-  if output.currentBuffer != nil:
-    let n = ps.sendData(output.currentBuffer, output.currentBufferIdx)
-    if unlikely(n < output.currentBuffer.len - output.currentBufferIdx):
-      ps.sclose()
-      return false
-  for buffer in output.buffers:
-    let n = ps.sendData(buffer)
-    if unlikely(n < buffer.len):
-      ps.sclose()
-      return false
+  try:
+    if output.currentBuffer != nil:
+      let n = ps.sendData(output.currentBuffer, output.currentBufferIdx)
+      if unlikely(n < output.currentBuffer.len - output.currentBufferIdx):
+        ps.sclose()
+        return false
+    for buffer in output.buffers:
+      let n = ps.sendData(buffer)
+      if unlikely(n < buffer.len):
+        ps.sclose()
+        return false
+  except ErrorBrokenPipe:
+    # ps or output is dead; give up.
+    ps.sclose()
+    return false
   if output.istreamAtEnd:
     ps.sclose()
   elif output.parent != nil:
@@ -329,8 +334,7 @@ proc loadStreamRegular(ctx: LoaderContext; handle, cachedHandle: LoaderHandle) =
     handle.outputs.del(i)
   for output in handle.outputs:
     if r == hrrBrokenPipe:
-      output.ostream.sclose()
-      output.ostream = nil
+      output.oclose()
     elif cachedHandle != nil:
       output.parent = cachedHandle
       cachedHandle.outputs.add(output)
@@ -341,8 +345,7 @@ proc loadStreamRegular(ctx: LoaderContext; handle, cachedHandle: LoaderHandle) =
       ctx.outputMap[output.ostream.fd] = output
     else:
       assert output.ostream.fd notin ctx.outputMap
-      output.ostream.sclose()
-      output.ostream = nil
+      output.oclose()
   handle.outputs.setLen(0)
   handle.iclose()
 
@@ -418,13 +421,16 @@ proc loadResource(ctx: LoaderContext; client: ClientData; config: LoaderClientCo
       handle.loadCGI(request, ctx.config.cgiDir, prevurl,
         config.insecureSSLNoVerify, ostream)
       if handle.istream != nil:
-        ctx.addFd(handle)
         if ostream != nil:
           let output = ctx.findOutput(request.body.outputId, client)
           if output != nil:
-            doAssert ctx.redirectToStream(output, ostream)
+            if not ctx.redirectToStream(output, ostream):
+              # give up.
+              handle.rejectHandle(ERROR_FAILED_TO_REDIRECT)
+              return
           else:
             ostream.sclose()
+        ctx.addFd(handle)
       else:
         handle.close()
     elif request.url.scheme == "stream":
@@ -704,6 +710,7 @@ proc acceptConnection(ctx: LoaderContext) =
         ctx.resume(stream, client, r)
   except ErrorBrokenPipe:
     # receiving end died while reading the file; give up.
+    assert stream.fd notin ctx.outputMap
     stream.sclose()
 
 proc exitLoader(ctx: LoaderContext) =
@@ -820,8 +827,7 @@ proc finishCycle(ctx: LoaderContext; unregRead: var seq[LoaderHandle];
       if output.registered:
         ctx.selector.unregister(output.ostream.fd)
       ctx.outputMap.del(output.ostream.fd)
-      output.ostream.sclose()
-      output.ostream = nil
+      output.oclose()
       let handle = output.parent
       if handle != nil: # may be nil if from loadStream S_ISREG
         let i = handle.outputs.find(output)
diff --git a/src/loader/loaderhandle.nim b/src/loader/loaderhandle.nim
index 31a41571..42f10c6e 100644
--- a/src/loader/loaderhandle.nim
+++ b/src/loader/loaderhandle.nim
@@ -185,10 +185,13 @@ proc iclose*(handle: LoaderHandle) =
     handle.istream.sclose()
     handle.istream = nil
 
+proc oclose*(output: OutputHandle) =
+  output.ostream.sclose()
+  output.ostream = nil
+
 proc close*(handle: LoaderHandle) =
   handle.iclose()
   for output in handle.outputs:
     #TODO assert not output.registered
     if output.ostream != nil:
-      output.ostream.sclose()
-      output.ostream = nil
+      output.oclose()