about summary refs log tree commit diff stats
path: root/src/loader/cgi.nim
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2024-05-30 00:19:48 +0200
committerbptato <nincsnevem662@gmail.com>2024-06-20 17:50:22 +0200
commit60dc37269cd2dc8cdf23d9f77680f6af9490032f (patch)
tree9a72ba24daffa546f92704e7e06cf84fded2d89d /src/loader/cgi.nim
parenta146a22b11cea39bc691417d9d9a1292b7177552 (diff)
downloadchawan-60dc37269cd2dc8cdf23d9f77680f6af9490032f.tar.gz
img, loader: separate out png codec into cgi, misc improvements
* multi-processed and sandboxed PNG decoding & encoding (through local
  CGI)
* improved request body passing (including support for output id as
  response body)
* simplified & faster blob()/text() - now every request starts
  suspended, and OngoingData.buf has been replaced with loader's
  buffering capability
* image caching: we no longer pull bitmaps from the container after
  every single getLines call

Next steps: replace our bespoke PNG decoder with something more usable,
add other decoders, and make them stream.
Diffstat (limited to 'src/loader/cgi.nim')
-rw-r--r--src/loader/cgi.nim53
1 files changed, 21 insertions, 32 deletions
diff --git a/src/loader/cgi.nim b/src/loader/cgi.nim
index f3c5b1e3..ee3d3160 100644
--- a/src/loader/cgi.nim
+++ b/src/loader/cgi.nim
@@ -42,8 +42,8 @@ proc setupEnv(cmd, scriptName, pathInfo, requestURI, myDir: string;
   if url.query.isSome:
     putEnv("QUERY_STRING", url.query.get)
   if request.httpMethod == hmPost:
-    if request.multipart.isSome:
-      putEnv("CONTENT_TYPE", request.multipart.get.getContentType())
+    if request.body.t == rbtMultipart:
+      putEnv("CONTENT_TYPE", request.body.multipart.getContentType())
     else:
       putEnv("CONTENT_TYPE", request.headers.getOrDefault("Content-Type", ""))
     putEnv("CONTENT_LENGTH", $contentLen)
@@ -126,7 +126,7 @@ proc handleLine(handle: LoaderHandle; line: string; headers: Headers) =
   headers.add(k, v)
 
 proc loadCGI*(handle: LoaderHandle; request: Request; cgiDir: seq[string];
-    prevURL: URL; insecureSSLNoVerify: bool) =
+    prevURL: URL; insecureSSLNoVerify: bool; ostream: var PosixStream) =
   if cgiDir.len == 0:
     handle.sendResult(ERROR_NO_CGI_DIR)
     return
@@ -181,16 +181,11 @@ proc loadCGI*(handle: LoaderHandle; request: Request; cgiDir: seq[string];
     return
   # Pipe the request body as stdin for POST.
   var pipefd_read: array[0..1, cint] # parent -> child
-  let needsPipe = request.body.isSome or request.multipart.isSome
-  if needsPipe:
+  if request.body.t != rbtNone:
     if pipe(pipefd_read) == -1:
       handle.sendResult(ERROR_FAIL_SETUP_CGI)
       return
-  var contentLen = 0
-  if request.body.isSome:
-    contentLen = request.body.get.len
-  elif request.multipart.isSome:
-    contentLen = request.multipart.get.calcLength()
+  let contentLen = request.body.contentLength()
   stdout.flushFile()
   stderr.flushFile()
   let pid = fork()
@@ -199,7 +194,7 @@ proc loadCGI*(handle: LoaderHandle; request: Request; cgiDir: seq[string];
   elif pid == 0:
     discard close(pipefd[0]) # close read
     discard dup2(pipefd[1], 1) # dup stdout
-    if needsPipe:
+    if request.body.t != rbtNone:
       discard close(pipefd_read[1]) # close write
       if pipefd_read[0] != 0:
         discard dup2(pipefd_read[0], 0) # dup stdin
@@ -220,38 +215,32 @@ proc loadCGI*(handle: LoaderHandle; request: Request; cgiDir: seq[string];
     quit(1)
   else:
     discard close(pipefd[1]) # close write
-    if needsPipe:
+    if request.body.t != rbtNone:
       discard close(pipefd_read[0]) # close read
       let ps = newPosixStream(pipefd_read[1])
-      if request.body.isSome:
-        ps.write(request.body.get)
-      elif request.multipart.isSome:
-        let multipart = request.multipart.get
-        for entry in multipart.entries:
-          ps.writeEntry(entry, multipart.boundary)
-        ps.writeEnd(multipart.boundary)
-      ps.sclose()
+      case request.body.t
+      of rbtString:
+        ps.write(request.body.s)
+        ps.sclose()
+      of rbtMultipart:
+        let boundary = request.body.multipart.boundary
+        for entry in request.body.multipart.entries:
+          ps.writeEntry(entry, boundary)
+        ps.writeEnd(boundary)
+        ps.sclose()
+      of rbtOutput:
+        ostream = ps
+      of rbtNone: discard
     handle.parser = HeaderParser(headers: newHeaders())
     handle.istream = newPosixStream(pipefd[0])
 
-proc killHandle(handle: LoaderHandle) =
-  if handle.parser.state != hpsBeforeLines:
-    # not an ideal solution, but better than silently eating malformed
-    # headers
-    handle.output.ostream.setBlocking(true)
-    handle.sendStatus(500)
-    handle.sendHeaders(newHeaders())
-    const msg = "Error: malformed header in CGI script"
-    discard handle.output.ostream.sendData(msg)
-  handle.parser = nil
-
 proc parseHeaders0(handle: LoaderHandle; buffer: LoaderBuffer): int =
   let parser = handle.parser
   var s = parser.lineBuffer
   let L = if buffer == nil: 1 else: buffer.len
   for i in 0 ..< L:
     template die =
-      handle.killHandle()
+      handle.parser = nil
       return -1
     let c = if buffer != nil:
       char(buffer.page[i])