Gemini server for CGI
This repository has been archived on 2024-08-20. You can view files and clone it, but cannot push or open issues or pull requests.
Go to file
2021-11-24 18:17:53 +01:00
examples/cgi init 2021-11-23 12:53:37 +01:00
src get_response: print process stderr as warnings 2021-11-24 18:17:53 +01:00
.gitignore init 2021-11-23 12:53:37 +01:00
Cargo.lock use OpenSSL bindings instead of Rustls 2021-11-24 12:15:08 +01:00
Cargo.toml use OpenSSL bindings instead of Rustls 2021-11-24 12:15:08 +01:00
README.md use OpenSSL bindings instead of Rustls 2021-11-24 12:15:08 +01:00

Opal

Opal is a Gemini server written in Rust. It is meant to serve dynamic content through CGI and does not serve static files. In a way, it is a companion project to the Agate Gemini server which only serves static files, trying to focus on a smaller set of features but do them correctly.

Opal uses the openssl Rust bindings, which work with OpenSSL and LibreSSL, so it should work properly on those platforms. I only support Linux systems but feel free to patch stuff!

Usage

Use opal -h to get a list of options. There is no config file.

CGI support

Opal tries to implement RFC 3875 (CGI 1.1) and provides all the required environment variables to processes. It also add a bunch of Gemini specific variables, like a lot of other servers (Gemserv, Gmid, Gmnisrv, …). The environment for the subprocess is cleaned and should only contain those variables.

Presence Variable Description
always GATEWAY_INTERFACE "CGI/1.1"
always REMOTE_ADDR Peer IP address and port
always REMOTE_HOST Same as REMOTE_ADDR
always REQUEST_METHOD Empty string for compatibility
always SCRIPT_NAME Script name part of the URL path
always SERVER_NAME Hostname used for SNI
always SERVER_PORT Port where the request has been received
always SERVER_PROTOCOL "GEMINI"
always SERVER_SOFTWARE "opal/version", e.g. "opal/0.1.0"
always GEMINI_DOCUMENT_ROOT CGI root
always GEMINI_SCRIPT_FILENAME CGI script that matched the URL path
always GEMINI_URL Full URL, normalized
always GEMINI_URL_PATH URL path, normalized
always TLS_VERSION TLS version, e.g. "TLSv1.3"
always TLS_CIPHER TLS cipher suite, e.g. "TLS_AES_256_GCM_SHA384"
optional PATH_INFO Path passed to the CGI process after the script name
optional QUERY_STRING Query string if provided, still URL-encoded
client cert AUTH_TYPE "CERTIFICATE" if one is provided
client cert REMOTE_USER Subject common name (empty if unavailable)
client cert TLS_CLIENT_ISSUER Issuer common name (empty if unavailable)
client cert TLS_CLIENT_HASH Digest of the DER reprensetation of the cert
client cert TLS_CLIENT_NOT_AFTER Validity end date, RFC 3339 format
client cert TLS_CLIENT_NOT_BEFORE Validity start date, RFC 3339 format

Opal does not provide CONTENT_LENGTH, CONTENT_TYPE, REMOTE_IDENT because they do not make much sense in Gemini. PATH_TRANSLATED is also not implemented by pure laziness.

The TLS_CLIENT_HASH is a string that starts with "SHA256:" followed by the SHA256 digest of the DER representation of the client certificate, as an uppercase hex-string.

It can be a bit confusing which variable represent what data, especially those related to the URL and the path. Take the following request as example: gemini://localhost/env/sub1/sub2?search=élément. Suppose our CGI root, in /cgi, contains the executable script named env. The variables will be:

GEMINI_DOCUMENT_ROOT=/cgi
GEMINI_SCRIPT_FILENAME=/cgi/env
GEMINI_URL=gemini://localhost/env/sub1/sub2?search=%C3%A9l%C3%A9ment
GEMINI_URL_PATH=/env/sub1/sub2
SCRIPT_NAME=/env
PATH_INFO=/sub1/sub2
QUERY_STRING=search=%C3%A9l%C3%A9ment