http-cmd 1.0.0

Run a command over HTTP
# 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
- 💻️ Demonstration of CLIs
- 🖨️ [Embedding the output of code blocks for multiple languages]zola_examples/embedding_code_evaluation
- 📊 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`).