= rust-cgi Easily create CGIfootnote:[Retro!]footnote:[Common Gateway Interface 1.1, RFC 3875] programmesfootnote:[Yes, I'm spelling it programme, the correct way.] in Rust based on link:https://github.com/hyperium/http[`http` types]. image::https://img.shields.io/crates/v/cgi2.svg?style=flat[crates.io released version badge] image::https://img.shields.io/crates/l/cgi2.svg?style=flat[crates.io released licencegpl] :toc: = Installation & Usage `Cargo.toml`: [code,toml] ---- [dependencies] cgi2 = "0.7" ---- Use the `cgi::main` macro on your `main` function, taking in a `Request` and returning a `Response`. [code,rust] ---- #[cgi::main] fn main(request: cgi::Request) -> cgi::Response { cgi::text_response(200, "Hello World") } ---- This also works if you return a `Result`. If your function returns a `Result` the error is printed to `stderr` and an HTTP 500 error is returned. [code,rust] ---- #[cgi::main] fn main(request: cgi::Request) -> Result { let greeting = std::fs::read_to_string("greeting.txt").map_err(|_| "Couldn't open file")?; Ok(cgi::text_response(200, greeting)) } ---- It will parse & extract the CGI environmental variables, and the HTTP request body to create `Request`, call your function to create a response, and convert your `Response` into the correct format and print to stdout. If this programme is not called as CGI (e.g. missing required environmental variables), it will panic. It is also possible to call the `cgi::handle` function directly inside your `main` function: [code,rust] ---- fn main() { cgi::handle(|request: cgi::Request| -> cgi::Response { cgi::html_response(200, "

Hello World!

") }) } ---- == Response Shortcuts Several shortcuts create shortcuts easily: `cgi:empty_response(status_code)`:: A HTTP Reponse with no body and that HTTP status code, e.g. `return cgi::empty_response(404);` to return a link:https://en.wikipedia.org/wiki/HTTP_404[HTTP 404 Not Found]. `cgi::html_response(status_code, text)`:: Converts `text` to bytes (UTF8) and sends that as the body with that `status_code` and HTML `Content-Type` header. `cgi::string_response(status_code, text)`:: Converts `text` to bytes (UTF8), and sends that as the body with that `status_code`, e.g. `return `cgi::string_response(200, "Hello World!")`:: returns a simple plain text response. `cgi::binary_response(status_code, blob)`:: Sends `blob` with that status code. == Re-exports `http` is re-exported, (as `cgi::http`). `cgi::Response`/`Request` are `http::Response>`/`Request>`. = Running locally Python provides a simple CGI webserver you can use to run your scripts. The binaries must be in a `cgi-bin` directory, so you'll need to create that directory and copy your binary into it. Given a project named `example`, run this in your project root directory (i.e. where `Cargo.toml` is): ---- mkdir cgi-bin cargo build --example hello_world cp target/debug/examples/hello_world cgi-bin/hello_world python3 -m http.server --cgi ---- and then open link:http://localhost:8000/cgi-bin/hello_world[]. = See also == Things using this * link:https://fnordig.de/cgi-bin/hello-world.rs[] * link:https://fnordig.de/cgi-bin/counter.rs[] == Resources * link:https://github.com/hyperium/http[hyper's http]. * link:https://docs.rs/http/0.1.5/http/[`http` API documentation] * link:https://tools.ietf.org/html/rfc3875[RFC 3875 - The Common Gateway Interface (CGI) v1.1] = Why? CGI is old, and easy to deploy. Just drop a binary in the right place, and Apache (or whatever) will serve it up. Rust is fast, so for simple things, there should be less downsides to spinning up a custom HTTP server. = Copyright Copyright link:https://www.gnu.org/licenses/agpl-3.0.en.html[GNU Affero GPL v3 (or later)]. See the file link:LICENCE[]