about summary refs log tree commit diff
path: root/pkgs/profpatsch/xdg-open/default.nix
diff options
context:
space:
mode:
authorProfpatsch <mail@profpatsch.de>2020-07-03 13:11:03 +0200
committerProfpatsch <mail@profpatsch.de>2020-07-06 20:13:42 +0200
commit97f05263ef490a063a33733d7ea607411a097df8 (patch)
treef1617705e22437c908459e1de059993bcab09ed3 /pkgs/profpatsch/xdg-open/default.nix
parente409df3861f48de44d0e37277ce007e348a7a0dc (diff)
pkgs/profpatsch/xdg-open: Prepare decoding http urls
I want to be able to open http(s) links that are e.g. images directly
in the right application. Aka web urls should be transparent, instead
of always opening everthing in the browser.

This adds some silly ways of connecting to the server and parsing
out the headers, in order to fetch the content-type.
Diffstat (limited to 'pkgs/profpatsch/xdg-open/default.nix')
-rw-r--r--pkgs/profpatsch/xdg-open/default.nix139
1 files changed, 138 insertions, 1 deletions
diff --git a/pkgs/profpatsch/xdg-open/default.nix b/pkgs/profpatsch/xdg-open/default.nix
index a4aaff97..e73f8093 100644
--- a/pkgs/profpatsch/xdg-open/default.nix
+++ b/pkgs/profpatsch/xdg-open/default.nix
@@ -1,9 +1,25 @@
-{ pkgs, getBins, importDhall2, writeExecline, dhall, buildDhallPackage, writeRustSimple, el-exec }:
+{ pkgs, getBins,
+importDhall2,
+writeExecline,
+dhall,
+buildDhallPackage,
+runExeclineLocal,
+writeRustSimple,
+netencode-rs,
+record-get,
+el-exec
+}:
 
 let
   lib = pkgs.lib;
   bins = getBins pkgs.libnotify [ "notify-send" ]
       // getBins pkgs.file [ "file" ]
+      // getBins pkgs.coreutils [ "printf" "ln" "echo" ]
+      // getBins pkgs.fdtools [ "multitee" ]
+      // getBins pkgs.s6 [ "s6-ioconnect" ]
+      // getBins pkgs.s6-portable-utils [ "s6-test" ]
+      // getBins pkgs.s6-networking [ "s6-tcpclient" ]
+      // getBins pkgs.netcat-openbsd [ "nc" ]
       // getBins pkgs.dmenu [ "dmenu" "dmenu_path" ]
       # TODO: make sure these are the ones from the environment
       // getBins pkgs.emacs [ "emacsclient" ]
@@ -122,6 +138,119 @@ let
         ;
     };
 
+  httparse = pkgs.buildRustCrate {
+    pname = "httparse";
+    version = "1.3.4";
+    crateName = "httparse";
+    sha256 = "0dggj4s0cq69bn63q9nqzzay5acmwl33nrbhjjsh5xys8sk2x4jw";
+  };
+
+  stderr-tee = writeExecline "stderr-tee" {} [
+    "pipeline" [ bins.multitee "0-1,2" ] "$@"
+  ];
+
+  stderr-prog = writeExecline "stderr-prog" {} [
+    "foreground" [ bins.echo "$@" ]
+    "$@"
+  ];
+
+  http-request = writeExecline "http-request-for-url" { } [
+    "importas" "-i" "protocol" "protocol"
+    "ifelse" [ bins.s6-test "$protocol" "=" "http" ] [ (http-https-request false) ]
+    "ifelse" [ bins.s6-test "$protocol" "=" "https" ] [ (http-https-request true) ]
+    eprintf "protocol \${protocol} not supported"
+  ];
+
+  http-https-request = isHttps: writeExecline "http-https-request" { } ([
+    "multisubstitute" [
+      "importas" "-ui" "port" "port"
+      "importas" "-ui" "host" "host"
+      "importas" "-ui" "path" "path"
+    ]
+    "pipeline" [
+      bins.printf (lib.concatStringsSep "\r\n" [
+      ''HEAD %s HTTP/1.1''
+      ''Host: %s''
+      ''User-Agent: lol''
+      ''Accept: */*''
+      ""
+      ""
+      ]) "$path" "$host"
+    ]
+    bins.nc
+  ] ++ lib.optional isHttps "-c" ++ [
+      "-N" "$host" "$port"
+  ]);
+
+  printenv = writeRustSimple "printenv" {}
+    (pkgs.writeText "printenv.rs" ''
+      use std::io::Write;
+      use std::os::unix::ffi::OsStrExt;
+      fn main() -> std::io::Result<()> {
+        let usage = || {
+          eprintln!("usage: printenv VAR");
+          std::process::exit(1)
+        };
+        let mut args = std::env::args_os();
+        let _ = args.next().unwrap_or_else(usage);
+        let var = args.next().unwrap_or_else(usage);
+        match std::env::var_os(&var) {
+          None => {
+            let mut err = std::io::stderr();
+            err.write_all("env variable ".as_bytes())?;
+            err.write_all(var.as_bytes())?;
+            err.write_all(" does not exist\n".as_bytes())?;
+          },
+          Some(stuff) => std::io::stdout().write_all(stuff.as_bytes())?
+        }
+        Ok(())
+      }
+    '');
+
+  assert-printf = writeExecline "assert-printf" { argMode = "env"; } [
+    "ifelse" [ "runblock" "2" ]
+    [ "runblock" "-r" "2" ]
+    "fdmove" "-c" "1" "2"
+    "runblock" "1" bins.printf
+  ];
+
+  as-stdin = writeExecline "as-stdin" { readNArgs = 1; } [
+    "pipeline" [ printenv "$1" ] "$@"
+  ];
+
+  read-headers-and-follow-redirect = writeExecline "read-headers-and-follow-redirect" { readNArgs = 1; }
+    (let go = writeExecline "go" {} [
+      "pipeline" [ http-request ]
+      "pipeline" [ read-http ]
+      record-get [ "status" "status-text" "headers" ]
+      "importas" "-ui" "status" "status"
+      # TODO: a test util for netencode values
+      "ifelse" [ bins.s6-test "$status" "=" "n6:301," ]
+      # retry the redirection location
+      [ as-stdin "headers"
+        record-get [ "Location" ]
+        "importas" "-ui" "Location" "Location"
+        "export" "host" "$Location"
+        "if" [ "echo" "redirected to \${Location}" ]
+        # save path, which would be overwritten by mini-url
+        "importas" "old-path" "path"
+        mini-url "$Location"
+        "export" "path" "$old-path"
+        "$0"
+      ]
+      printenv "headers"
+    ];
+    in [
+      mini-url "$1"
+      go
+    ]);
+
+
+  read-http = writeRustSimple "read-http" {
+    dependencies = [ httparse netencode-rs ];
+    buildInputs = [ pkgs.skalibs ];
+  } ./read-http.rs;
+
   mini-url = writeRustSimple "mini-url" {
     dependencies = [ el-exec ];
     buildInputs = [ pkgs.skalibs ];
@@ -130,10 +259,18 @@ let
     verbose = true;
   } ./mini-url.rs;
 
+  eprintf = writeExecline "eprintf" {} [
+    "fdmove" "-c" "1" "2" bins.printf "%s" "$@"
+  ];
+
 in {
   inherit
     xdg-open
     Prelude
+    read-headers-and-follow-redirect
     mini-url
+    assert-printf
+    as-stdin
+    printenv
     ;
 }