about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2024-02-12 20:35:30 +0100
committerbptato <nincsnevem662@gmail.com>2024-02-12 20:36:39 +0100
commita2eadfb39099b2e8bfd543f00d75b64916931959 (patch)
tree3df7afbb5a75ee51c1503b7961e940a3f37962a2 /src
parent8e6783a45fba48dd8f63fe7486e4691f05220b52 (diff)
downloadchawan-a2eadfb39099b2e8bfd543f00d75b64916931959.tar.gz
Add pager.externFilterSource
useful for filtering stuff through commands like rdrview
Diffstat (limited to 'src')
-rw-r--r--src/html/dom.nim2
-rw-r--r--src/loader/loader.nim18
-rw-r--r--src/local/container.nim4
-rw-r--r--src/local/pager.nim68
-rw-r--r--src/server/buffer.nim9
5 files changed, 85 insertions, 16 deletions
diff --git a/src/html/dom.nim b/src/html/dom.nim
index c5140759..70f907c5 100644
--- a/src/html/dom.nim
+++ b/src/html/dom.nim
@@ -3435,7 +3435,7 @@ proc fetchClassicScript(element: HTMLScriptElement, url: URL,
     return
   let loader = window.loader.get
   let request = createPotentialCORSRequest(url, RequestDestination.SCRIPT, cors)
-  let response = loader.doRequest(request, canredir = false)
+  let response = loader.doRequest(request)
   if response.res != 0:
     element.onComplete(ScriptResult(t: RESULT_NULL))
     return
diff --git a/src/loader/loader.nim b/src/loader/loader.nim
index 0755d427..6183e771 100644
--- a/src/loader/loader.nim
+++ b/src/loader/loader.nim
@@ -233,7 +233,7 @@ proc loadResource(ctx: LoaderContext, request: Request, handle: LoaderHandle) =
     handle.rejectHandle(ERROR_TOO_MANY_REWRITES)
 
 proc loadFromCache(ctx: LoaderContext, stream: SocketStream, request: Request) =
-  let handle = newLoaderHandle(stream, false, request.clientId)
+  let handle = newLoaderHandle(stream, request.canredir, request.clientId)
   let surl = $request.url
   let cachedHandle = ctx.findCachedHandle(surl)
   ctx.cacheMap.withValue(surl, p):
@@ -270,6 +270,17 @@ proc loadFromCache(ctx: LoaderContext, stream: SocketStream, request: Request) =
     output.parent = cachedHandle
     cachedHandle.outputs.add(output)
     ctx.outputMap[output.ostream.fd] = output
+  if handle.outputs.len > 0:
+    let output = handle.output
+    if output.sostream != nil:
+      try:
+        handle.output.sostream.swrite(true)
+      except IOError:
+        # ignore error, that just means the buffer has already closed the
+        # stream
+        discard
+      output.sostream.close()
+      output.sostream = nil
   handle.close()
 
 proc onLoad(ctx: LoaderContext, stream: SocketStream) =
@@ -794,12 +805,9 @@ proc onError*(loader: FileLoader, fd: int) =
     buffer[].buf = ""
     response.unregisterFun()
 
-proc doRequest*(loader: FileLoader, request: Request, canredir = false):
-    Response =
+proc doRequest*(loader: FileLoader, request: Request): Response =
   let response = Response(url: request.url)
   let stream = connectSocketStream(loader.process, false, blocking = true)
-  if canredir:
-    request.canredir = true #TODO set this somewhere else?
   request.clientId = (loader.clientPid, int(stream.fd))
   stream.swrite(LOAD)
   stream.swrite(request)
diff --git a/src/local/container.nim b/src/local/container.nim
index 585c8a3f..9af35c63 100644
--- a/src/local/container.nim
+++ b/src/local/container.nim
@@ -85,6 +85,9 @@ type
     x: int
     y: int
 
+  BufferFilter* = ref object
+    cmd*: string
+
   Container* = ref object
     parent* {.jsget.}: Container
     children* {.jsget.}: seq[Container]
@@ -125,6 +128,7 @@ type
     jumpMark: PagePos
     marks: Table[string, PagePos]
     ishtml*: bool
+    filter*: BufferFilter
 
 jsDestructor(Highlight)
 jsDestructor(Container)
diff --git a/src/local/pager.nim b/src/local/pager.nim
index 3233b012..41ecb6a5 100644
--- a/src/local/pager.nim
+++ b/src/local/pager.nim
@@ -919,13 +919,26 @@ proc externInto(pager: Pager, cmd, ins: string): bool {.jsfunc.} =
   pager.setEnvVars()
   return runProcessInto(cmd, ins)
 
+proc externFilterSource(pager: Pager, cmd: string, c: Container = nil,
+    contentType = opt(string)) {.jsfunc.} =
+  let container = newBufferFrom(
+    pager.forkserver,
+    pager.attrs,
+    if c != nil: c else: pager.container,
+    contentType.get(pager.container.contentType.get(""))
+  )
+  pager.addContainer(container)
+  container.filter = BufferFilter(cmd: cmd)
+
 proc authorize(pager: Pager) =
   pager.setLineEdit("Username: ", USERNAME)
 
+type CheckMailcapResult = tuple[promise: EmptyPromise, connect: bool]
+
 # Pipe input into the mailcap command, then read its output into a buffer.
 # needsterminal is ignored.
 proc runMailcapReadPipe(pager: Pager, container: Container,
-    entry: MailcapEntry, cmd: string): (EmptyPromise, bool) =
+    entry: MailcapEntry, cmd: string): CheckMailcapResult =
   var pipefd_in: array[2, cint]
   if pipe(pipefd_in) == -1:
     raise newException(Defect, "Failed to open pipe.")
@@ -969,7 +982,7 @@ proc runMailcapReadPipe(pager: Pager, container: Container,
 # Pipe input into the mailcap command, and discard its output.
 # If needsterminal, leave stderr and stdout open and wait for the process.
 proc runMailcapWritePipe(pager: Pager, container: Container,
-    entry: MailcapEntry, cmd: string): (EmptyPromise, bool) =
+    entry: MailcapEntry, cmd: string): CheckMailcapResult =
   let needsterminal = NEEDSTERMINAL in entry.flags
   var pipefd: array[2, cint]
   if pipe(pipefd) == -1:
@@ -1008,7 +1021,7 @@ proc runMailcapWritePipe(pager: Pager, container: Container,
 # new buffer.
 # needsterminal is ignored.
 proc runMailcapReadFile(pager: Pager, container: Container,
-    entry: MailcapEntry, cmd, outpath: string): (EmptyPromise, bool) =
+    entry: MailcapEntry, cmd, outpath: string): CheckMailcapResult =
   let fd = open(outpath, O_WRONLY or O_CREAT, 0o600)
   if fd == -1:
     return (nil, false)
@@ -1042,7 +1055,7 @@ proc runMailcapReadFile(pager: Pager, container: Container,
 # Save input in a file, run the command, and discard its output.
 # If needsterminal, leave stderr and stdout open and wait for the process.
 proc runMailcapWriteFile(pager: Pager, container: Container,
-    entry: MailcapEntry, cmd, outpath: string): (EmptyPromise, bool) =
+    entry: MailcapEntry, cmd, outpath: string): CheckMailcapResult =
   let needsterminal = NEEDSTERMINAL in entry.flags
   let fd = open(outpath, O_WRONLY or O_CREAT, 0o600)
   if fd == -1:
@@ -1069,9 +1082,50 @@ proc runMailcapWriteFile(pager: Pager, container: Container,
   )
   return (p, false)
 
+proc filterBuffer(pager: Pager, container: Container): CheckMailcapResult =
+  pager.setEnvVars()
+  let cmd = container.filter.cmd
+  var pipefd_in: array[2, cint]
+  if pipe(pipefd_in) == -1:
+    raise newException(Defect, "Failed to open pipe.")
+  var pipefd_out: array[2, cint]
+  if pipe(pipefd_out) == -1:
+    raise newException(Defect, "Failed to open pipe.")
+  let pid = fork()
+  if pid == -1:
+    return (nil, true)
+  elif pid == 0:
+    # child
+    discard close(pipefd_in[1])
+    discard close(pipefd_out[0])
+    stdout.flushFile()
+    discard dup2(pipefd_in[0], stdin.getFileHandle())
+    discard dup2(pipefd_out[1], stdout.getFileHandle())
+    let devnull = open("/dev/null", O_WRONLY)
+    discard dup2(devnull, stderr.getFileHandle())
+    discard close(devnull)
+    discard close(pipefd_in[0])
+    discard close(pipefd_out[1])
+    discard execCmd(cmd)
+    quit(0)
+  else:
+    # parent
+    discard close(pipefd_in[0])
+    discard close(pipefd_out[1])
+    let fdin = pipefd_in[1]
+    let fdout = pipefd_out[0]
+    let p = container.redirectToFd(fdin, wait = false, cache = false)
+    let p2 = p.then(proc(): auto =
+      discard close(fdin)
+      return container.readFromFd(fdout, $pid, container.ishtml)
+    ).then(proc() =
+      discard close(fdout)
+    )
+    return (p2, true)
+
 # Search for a mailcap entry, and if found, execute the specified command
 # and pipeline the input and output appropriately.
-# There is four possible outcomes:
+# There are four possible outcomes:
 # * pipe stdin, discard stdout
 # * pipe stdin, read stdout
 # * write to file, run, discard stdout
@@ -1080,7 +1134,9 @@ proc runMailcapWriteFile(pager: Pager, container: Container,
 # pager is suspended until the command exits.
 #TODO add support for edit/compose, better error handling (use Promise[bool]
 # instead of tuple[EmptyPromise, bool])
-proc checkMailcap(pager: Pager, container: Container): (EmptyPromise, bool) =
+proc checkMailcap(pager: Pager, container: Container): CheckMailcapResult =
+  if container.filter != nil:
+    return pager.filterBuffer(container)
   if container.contentType.isNone:
     return (nil, true)
   let contentType = container.contentType.get
diff --git a/src/server/buffer.nim b/src/server/buffer.nim
index af857928..19a1407b 100644
--- a/src/server/buffer.nim
+++ b/src/server/buffer.nim
@@ -713,7 +713,7 @@ proc rewind(buffer: Buffer): bool =
   if buffer.loader.rewind(buffer.fd):
     return true
   let request = newRequest(buffer.url, fromcache = true)
-  let response = buffer.loader.doRequest(request, canredir = false)
+  let response = buffer.loader.doRequest(request)
   if response.body != nil:
     buffer.selector.unregister(buffer.fd)
     buffer.loader.unregistered.add(buffer.fd)
@@ -781,7 +781,8 @@ proc connect*(buffer: Buffer): ConnectResult {.proxy.} =
   var cookies: seq[Cookie]
   var referrerpolicy: Option[ReferrerPolicy]
   let request = source.request
-  let response = buffer.loader.doRequest(request, canredir = true)
+  request.canredir = true #TODO set somewhere else?
+  let response = buffer.loader.doRequest(request)
   if response.body == nil:
     return ConnectResult(
       code: response.res,
@@ -820,7 +821,7 @@ proc connect*(buffer: Buffer): ConnectResult {.proxy.} =
 # * connect2, telling loader to load at last (we block loader until then)
 # * redirectToFd, telling loader to load into the passed fd
 proc connect2*(buffer: Buffer) {.proxy.} =
-  if not buffer.source.request.fromcache:
+  if buffer.source.request.canredir:
     # Notify loader that we can proceed with loading the input stream.
     buffer.istream.swrite(false)
     buffer.istream.swrite(true)
@@ -856,7 +857,7 @@ proc readFromFd*(buffer: Buffer, url: URL, ishtml: bool) {.proxy.} =
     charset: buffer.source.charset
   )
   buffer.setHTML(ishtml)
-  let response = buffer.loader.doRequest(request, canredir = false)
+  let response = buffer.loader.doRequest(request)
   buffer.istream = response.body
   buffer.fd = int(response.body.source.getFd())
   buffer.selector.registerHandle(buffer.fd, {Read}, 0)