about summary refs log tree commit diff stats
path: root/src/local
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2024-05-11 19:56:25 +0200
committerbptato <nincsnevem662@gmail.com>2024-05-11 20:06:10 +0200
commitb8345d19efdecb27139e011e92f89efbb7618c08 (patch)
tree5d0f3de089ef40f1f653ee386771e326f9847cd6 /src/local
parent2c1d1899e424c5e055214d3647979f7f0ba4dcfe (diff)
downloadchawan-b8345d19efdecb27139e011e92f89efbb7618c08.tar.gz
buffer: fix multipart forms
* fix enctype not getting picked up
* fix form data constructor requiring open() syscall (which gets blocked
  by our seccomp filter)
* add closing boundary to multipart end
* pass fds instead of path names through WebFile/Blob and send those
  through bufwriter/bufreader
Diffstat (limited to 'src/local')
-rw-r--r--src/local/client.nim11
-rw-r--r--src/local/container.nim40
-rw-r--r--src/local/pager.nim18
3 files changed, 46 insertions, 23 deletions
diff --git a/src/local/client.nim b/src/local/client.nim
index af5e89a0..dc79438e 100644
--- a/src/local/client.nim
+++ b/src/local/client.nim
@@ -658,11 +658,12 @@ proc clientLoadJSModule(ctx: JSContext; module_name: cstringConst;
     JS_ThrowTypeError(ctx, "Failed to open file %s", module_name)
     return nil
 
-proc readBlob(client: Client; path: string): Option[WebFile] {.jsfunc.} =
-  try:
-    return some(newWebFile(path))
-  except IOError:
-    discard
+proc readBlob(client: Client; path: string): WebFile {.jsfunc.} =
+  let ps = newPosixStream(path, O_RDONLY, 0)
+  if ps == nil:
+    return nil
+  let name = path.afterLast('/')
+  return newWebFile(name, ps.fd)
 
 #TODO this is dumb
 proc readFile(client: Client; path: string): string {.jsfunc.} =
diff --git a/src/local/container.nim b/src/local/container.nim
index 502b1de1..5b593f2a 100644
--- a/src/local/container.nim
+++ b/src/local/container.nim
@@ -7,6 +7,7 @@ import std/unicode
 
 import config/config
 import config/mimetypes
+import io/bufstream
 import io/dynstream
 import io/promise
 import io/serversocket
@@ -46,8 +47,8 @@ type
     setxsave: bool
 
   ContainerEventType* = enum
-    cetAnchor, cetNoAnchor, cetUpdate, cetReadLine, cetReadArea, cetOpen,
-    cetSetLoadInfo, cetStatus, cetAlert, cetLoaded, cetTitle, cetCancel
+    cetAnchor, cetNoAnchor, cetUpdate, cetReadLine, cetReadArea, cetReadFile,
+    cetOpen, cetSetLoadInfo, cetStatus, cetAlert, cetLoaded, cetTitle, cetCancel
 
   ContainerEvent* = object
     case t*: ContainerEventType
@@ -1483,8 +1484,12 @@ proc readCanceled*(container: Container) =
     if repaint:
       container.needslines = true)
 
-proc readSuccess*(container: Container; s: string) =
-  container.iface.readSuccess(s).then(proc(res: ReadSuccessResult) =
+proc readSuccess*(container: Container; s: string; fd = -1) =
+  let p = container.iface.readSuccess(s, fd != -1)
+  if fd != -1:
+    container.iface.stream.reallyFlush()
+    SocketStream(container.iface.stream.source).sendFileHandle(FileHandle(fd))
+  p.then(proc(res: ReadSuccessResult) =
     if res.repaint:
       container.needslines = true
     if res.open.isSome:
@@ -1521,19 +1526,21 @@ proc onclick(container: Container; res: ClickResult; save: bool) =
     container.displaySelect(res.select.get)
   if res.readline.isSome:
     let rl = res.readline.get
-    let event = if rl.area:
-      ContainerEvent(
-        t: cetReadArea,
-        tvalue: rl.value
-      )
-    else:
-      ContainerEvent(
+    case rl.t
+    of rltText:
+      container.triggerEvent(ContainerEvent(
         t: cetReadLine,
         prompt: rl.prompt,
         value: rl.value,
         password: rl.hide
-      )
-    container.triggerEvent(event)
+      ))
+    of rltArea:
+      container.triggerEvent(ContainerEvent(
+        t: cetReadArea,
+        tvalue: rl.value
+      ))
+    of rltFile:
+      container.triggerEvent(ContainerEvent(t: cetReadFile))
 
 proc click*(container: Container) {.jsfunc.} =
   if container.select.open:
@@ -1601,10 +1608,9 @@ func hoverImage(container: Container): string {.jsfget.} =
   return container.hoverText[htImage]
 
 proc handleCommand(container: Container) =
-  var packetid, len: int
-  container.iface.stream.recvDataLoop(addr len, sizeof(len))
-  container.iface.stream.recvDataLoop(addr packetid, sizeof(packetid))
-  container.iface.resolve(packetid, len - sizeof(packetid))
+  var packet: array[3, int] # 0 len, 1 auxLen, 2 packetid
+  container.iface.stream.recvDataLoop(addr packet[0], sizeof(packet))
+  container.iface.resolve(packet[2], packet[0] - sizeof(packet[2]), packet[1])
 
 proc startLoad(container: Container) =
   container.iface.load().then(proc(res: int) =
diff --git a/src/local/pager.nim b/src/local/pager.nim
index 93bf562c..c1bd18c0 100644
--- a/src/local/pager.nim
+++ b/src/local/pager.nim
@@ -65,6 +65,7 @@ type
     lmISearchB = "?"
     lmGotoLine = "Goto line: "
     lmDownload = "(Download)Save file to: "
+    lmBufferFile = "(Upload)Filename: "
 
   # fdin is the original fd; fdout may be the same, or different if mailcap
   # is used.
@@ -1173,6 +1174,19 @@ proc updateReadLine*(pager: Pager) =
         if pager.commandMode:
           pager.command()
       of lmBuffer: pager.container.readSuccess(lineedit.news)
+      of lmBufferFile:
+        let ps = newPosixStream(lineedit.news, O_RDONLY, 0)
+        if ps == nil:
+          pager.alert("File not found")
+          pager.container.readCanceled()
+        else:
+          var stats: Stat
+          if fstat(ps.fd, stats) < 0 or S_ISDIR(stats.st_mode):
+            pager.alert("Not a file: " & lineedit.news)
+          else:
+            let name = lineedit.news.afterLast('/')
+            pager.container.readSuccess(name, ps.fd)
+          ps.sclose()
       of lmSearchF, lmSearchB:
         if lineedit.news != "":
           let regex = pager.compileSearchRegex(lineedit.news)
@@ -1655,7 +1669,6 @@ proc connected(pager: Pager; container: Container; response: Response) =
     container.process = pager.forkserver.forkBuffer(
       container.config,
       container.url,
-      container.request,
       attrs,
       mailcapRes.ishtml,
       container.charsetStack
@@ -1768,6 +1781,9 @@ proc handleEvent0(pager: Pager; container: Container; event: ContainerEvent):
       else:
         pager.container.readCanceled()
       pager.redraw = true
+  of cetReadFile:
+    if container == pager.container:
+      pager.setLineEdit(lmBufferFile, "")
   of cetOpen:
     let url = event.request.url
     if not event.save and (pager.container != container or