/'su.la/ for the suffix of capsule successful Spanish, Cápsula.

Git
A Gemini protocol server written in Scryer Prolog.
Requirements
sula depends connected a patched Scryer Prolog which tin beryllium found here (branch js/fixes). The required patches are:
- A autochthonal '$copy_stream'/2 builtin utilized for streaming binary record bodies to TLS clients without materialising the contents connected the Prolog heap.
- A hole to library(pio)’s buffer_prepare_for_n/5 truthful that lazy sounds from process pipes (and different streams whose at_end_of_stream/1 ne'er reports true) terminate connected EOF alternatively of spinning.
- A non-blocking canvass loop successful socket_server_accept/4 that checks Scryer’s INTERRUPT flag, truthful SIGINT becomes a catchable '$interrupt_thrown' exception alternatively of being trapped down a blocking syscall.
- A larboard to rustls.
- A modification of tls_server_negotiate to see the optional client certificate.
Build and instal the patched Scryer:
git clone https://git.sagredo.dev/scryer-prolog -b js/fixes cd scryer-prolog cargo instal --path .openssl(1) must besides beryllium connected PATH — it’s invoked astatine startup to publication the CN from the configured personality certificate and verify it matches the configured hostname.
Running
./sula.pl --addr HOST:PORT --hostname NAME --content DIR --certs DIRsula.pl is simply a polyglot script: bash detects scryer-prolog connected PATH and execs it pinch sula:run, halt arsenic the introduction goal.
Example:
./sula.pl \ --addr 127.0.0.1:1965 \ --hostname gmi.example.dev \ --content ./site \ --certs .CLI options
All options judge immoderate order. Anything unrecognised is silently dropped.
| --addr HOST:PORT | Bind reside and larboard for the listening socket | 127.0.0.1:1965 |
| --hostname NAME | Expected CN of the certificate. Startup aborts connected mismatch | localhost |
| --content DIR | Root directory for served files | ./site |
| --certs DIR | Directory containing cert.pem and key.pem | . |
Stopping the server
Ctrl+C triggers a cleanable shutdown: the listening socket is closed, the top-level drawback logs Shutting down, and the process exits 0.
Features
- TLS via rustls, PKCS#12 personality files.
- Hostname verification: astatine startup, cert_is_for_hostname/2 shells retired to openssl x509 and asserts the cert’s CN matches --hostname.
- Content speech by hold via mime/2, populated astatine startup from /etc/mime.types (parsed by a DCG successful mime.pl). text/gemini is added for .gmi.
- Text responses sent via format/3; binary responses streamed successful native code done copy_stream/2 (file → TLS socket, nary Prolog heap traffic).
- Per-connection correction handling: TLS handshake failures and mid-stream client disconnects are logged and the loop continues. Other errors re-throw and aboveground astatine the apical level.
- Graceful shutdown connected SIGINT via the patched Scryer socket_server_accept/4.
Layout
sula.pl Polyglot launcher + main sula module (run/0, petition loop). config.pl CLI parsing (DCG) and config accessors (cert/1, addr/1, ...). cert.pl Certificate loading + hostname-vs-CN check. mime.pl /etc/mime.types parser (DCG) and mime/2 facts. request.pl Request statement reader. gemini_uri.pl Gemini URI DCG (gemini://host[:port]/path[?query]). ip.pl IP reside nickname (rejected arsenic Gemini hosts). response.pl Response position codification DCG. log.pl Tagged log_msg/3. banner.pl Reads banner.txt and emits it line-by-line via display_banner/1.Planned features
- Use cardinal and cert alternatively of identity.p12
- Client certificates
- Load configuration from a configuration file
- Save and load users
- Run CGI scripts
- All position codes
- Rate limiting
- Virtual hosting
- File logging
- Multi-threading aliases benignant of?
- Hot reload?
English (US) ·
Indonesian (ID) ·