about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--pkgs/profpatsch/default.nix9
-rw-r--r--pkgs/profpatsch/xdg-open/default.nix139
-rw-r--r--pkgs/profpatsch/xdg-open/read-http.rs56
-rw-r--r--pkgs/profpatsch/xdg-open/xdg-open.dhall4
4 files changed, 206 insertions, 2 deletions
diff --git a/pkgs/profpatsch/default.nix b/pkgs/profpatsch/default.nix
index c3f0d7e2..999382c0 100644
--- a/pkgs/profpatsch/default.nix
+++ b/pkgs/profpatsch/default.nix
@@ -220,10 +220,17 @@ in rec {
 
   rust-deps = (import ./rust-deps.nix { inherit (pkgs) buildRustCrate; });
 
-  inherit (import ./xdg-open { inherit pkgs getBins importDhall2 writeExecline dhall buildDhallPackage writeRustSimple el-exec; })
+  inherit (import ./xdg-open { inherit pkgs getBins importDhall2 writeExecline dhall buildDhallPackage runExeclineLocal netencode-rs writeRustSimple record-get el-exec; })
     xdg-open
+    config
     Prelude
+    httparse
+    get-http-content-type
+    read-headers-and-follow-redirect
     mini-url
+    assert-printf
+    as-stdin
+    printenv
     ;
 
   inherit (import ./netencode { inherit pkgs writeRustSimpleLib writeRustSimple el-semicolon el-exec; })
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
     ;
 }
diff --git a/pkgs/profpatsch/xdg-open/read-http.rs b/pkgs/profpatsch/xdg-open/read-http.rs
new file mode 100644
index 00000000..9fe8d6a9
--- /dev/null
+++ b/pkgs/profpatsch/xdg-open/read-http.rs
@@ -0,0 +1,56 @@
+extern crate httparse;
+extern crate netencode;
+
+use std::os::unix::io::FromRawFd;
+use std::io::Read;
+use std::io::Write;
+
+use netencode::{encode, U};
+
+fn main() -> std::io::Result<()> {
+
+    fn die<T: std::fmt::Display>(msg: T) {
+        eprintln!("{}", msg);
+        std::process::exit(1);
+    }
+
+    // max header size chosen arbitrarily
+    let mut headers = [httparse::EMPTY_HEADER; 128];
+    let mut resp = httparse::Response::new(&mut headers);
+    let mut buf = vec![];
+    std::io::stdin().read_to_end(&mut buf)?;
+    let res = resp.parse(&mut buf);
+    match res {
+        Err(err) => die(format!("http response error: {:?}", err)),
+        Ok(_start_of_body) => {
+            match resp.code {
+                Some(code) => write_dict(code, resp.reason, resp.headers)?,
+                None => die(format!("no http status"))
+            }
+        }
+    };
+    Ok(())
+}
+
+fn write_dict<'buf>(code: u16, reason: Option<&'buf str>, headers: &mut [httparse::Header<'buf>]) -> std::io::Result<()> {
+    let mut http = vec![
+        ("status", Box::new(U::N6(code as u64))),
+    ];
+
+    if let Some(t) = reason {
+        http.push(("status-text", Box::new(U::Text(t.as_bytes()))))
+    };
+
+    http.push(("headers", Box::new(U::Record(
+        headers.iter_mut().map(
+            |httparse::Header { name, value }|
+            (*name,
+             Box::new(U::Binary(value)))
+        ).collect::<Vec<_>>()
+    ))));
+
+    encode(
+        &mut std::io::stdout(),
+        U::Record(http)
+    )
+}
diff --git a/pkgs/profpatsch/xdg-open/xdg-open.dhall b/pkgs/profpatsch/xdg-open/xdg-open.dhall
index a7daebe3..03f168c3 100644
--- a/pkgs/profpatsch/xdg-open/xdg-open.dhall
+++ b/pkgs/profpatsch/xdg-open/xdg-open.dhall
@@ -91,6 +91,10 @@ let xdg-open =
 
                     set -e
                     file="$1"
+                    mime=
+
+                    # match on protocols
+                    # if you want to match files reliably, start with file://
                     case "$file" in
                     ${prettyLines
                         { indent = 2