# http-cmd Run a command over HTTP ## ⚠️ Warning ⚠️ **Don't expose `http-cmd` to the internet, especially with programs that execute code (e.g. `python`) or commands (e.g. `bash`). Otherwise, execution of arbitrary code and programs is possible (aka. you get hacked)!** ## Motivation The motivation for building this tool is that static site generators like [Zola](https://www.getzola.org/) don't allow executing external commands for security reasons. You don't want arbitrary programs to be executed while you try to build a static website! Imagine being hacked by a third-party theme 😱 However, such static site generators support fetching remote data. This leads to the hack of how `http-cmd` works: - 💻️ Run a local HTTP server waiting for POST requests and using their body as standard input or command arguments for the external command - ⬆️ Let the static site generator send a POST request to run the external command - ⬇️ Embed the response body as the output of the external command - 🎉 Profit! You can find examples of using `http-cmd` with Zola in the [`zola_examples`](zola_examples) directory. ## Use cases Here are some possible use cases: - ➗ [Converting LaTeX math to HTML](zola_examples/math) - 🖨️ [Embedding the output of code blocks for multiple languages](zola_examples/embedding_code_evaluation) - 💻️ Demonstration of CLIs - 📊 Embedding a diagram generated from text - 😃 Replacing emoji shortcodes with Unicode emojis - ⚙️ In general, extending the capabilities of static site generators - 💭 Your idea ## Installation You can install `http-cmd` using Cargo by running ```bash cargo install http-cmd ``` You can update it using [`cargo-update`](https://github.com/nabijaczleweli/cargo-update). If you don't want to install Cargo with the Rust toolchain, open an issue and I will publish a container image that you can run with Docker or Podman. ## Config `http-cmd` expects the config file `http-cmd.toml` in the directory where it is executed. But you can also provide a path to the a config file using the `-c` command line option. | Parameter | Description | Default | | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------- | | `ip` | The IPv4/IPv6 address to bind to | "127.0.0.1" | | `port` | The port to listen on | 8080 | | `max_request_body_size` | The maximum request body size in bytes | 1048576 (1 MiB) | | `commands` | A list of command configs | | | `commands.name` | A name for the command. It is used for executing the command under `http://IP:PORT/NAME`. Only the characters `a` to `z` (lowercase), `0` to `9` and `-` are allowed. | | | `commands.stdin` | See the [Modes](#modes) section below | | | `commands.program` | The program to execute when `http://IP:PORT/NAME` is called. It can be an absolute or relative path to the executable. Otherwise, the executable will be searched for equivalently to running the Unix `which` command | | | `commands.args` | A list of the program's arguments | | ### Modes `http-cmd` has two modes for running a program. The mode is chosen using the boolean configuration value `stdin`: - For **`stdin = true`**, the request body is piped to the standard input of the command. - For **`stdin = false`**, the request body is split to arguments which are provided after the configured `args`. See the example below with the `ls` command. ## Demo Here is an example config file: ```toml # The default ip = "127.0.0.1" # The default port = 8080 # 2 KiB instead of the default of 1MiB max_request_body_size = 2048 [[commands]] name = "rev" stdin = true program = "rev" args = [] [[commands]] name = "ls" stdin = false program = "/usr/bin/ls" args = ["-l"] ``` If you save this configuration to the file `http-cmd.toml` and run `http-cmd`, a server is started listening on `http://127.0.0.1:8080/rev` and `http://127.0.0.1:8080/ls`. Now, run ```bash curl http://127.0.0.1:8080/rev -d "Hello World!" ``` This command sends a POST request with the body "Hello World!". The output should be the reversed text: "!dlroW olleH" 🎉 The equivalent of what `http-cmd` does here with `stdin` set to `true` is the following pipe: ```bash echo -n "Hello World!" | rev ``` To test the second command, run ```bash curl http://127.0.0.1:8080/ls -d "src zola_examples" ``` The output depends on the content of the two directories. This command also sends a POST request, but since `stdin` is set to `false` for the `ls` command, the second [mode](#modes) is applied. This means that `http-cmd` executes the command `ls -l src zola_examples`. The arguments `src` and `zola_examples` are placed after the program `ls` and its configured arguments (here only `-l`).