Sula: A Gemini protocol server written in Scryer Prolog
Sula is a Gemini protocol server implemented in Scryer Prolog. The project provides a complete server that can serve files over the Gemini protocol with TLS support, MIME type negotiation, and clean shutdown.
The server depends on a patched branch of Scryer Prolog (branch js/fixes) that includes several specific patches: a native '$copy_stream'/2 builtin for streaming binary files without materializing them on the Prolog heap; a fix to library(pio)'s buffer_prepare_for_n/5 to terminate lazy reads on EOF; a non-blocking poll loop in socket_server_accept/4 that allows SIGINT to be caught as an interrupt exception; a port to rustls; and a modification of tls_server_negotiate to support optional client certificates. The patched compiler is built via git clone and cargo install, and openssl(1) must be on PATH to read the certificate CN at startup.
The launcher (sula.pl) is a polyglot script that accepts command-line options for address (--addr), hostname (--hostname), content root (--content), and certs directory (--certs), with defaults of 127.0.0.1:1965, localhost, ./site, and ./certs respectively. Unrecognized options are silently dropped. The server listens on the socket, performs TLS via rustls with PKCS#12 identity files, and verifies at startup that the certificate's CN matches the configured hostname by shelling out to openssl x509.
Content is served based on file extensions, with mime/2 facts populated from /etc/mime.types via a DCG parser, and text/gemini is added for .gmi files. Text responses are sent using format/3, while binary responses are streamed in native code through copy_stream/2 directly from file to TLS socket without passing through the Prolog heap. Per-connection error handling logs TLS handshake failures and mid-stream disconnects, while other errors surface at the top level. Ctrl+C triggers a clean shutdown, closing the listening socket and exiting with status 0.
The project is structured as modular Prolog files: sula.pl for the main loop, config.pl for CLI parsing, cert.pl for certificate handling, mime.pl for MIME type parsing, request.pl for reading request lines, and gemini_uri.pl for parsing Gemini URIs.