Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
c5ac761
Make compile.
Tim-ats-d May 7, 2025
0e861fe
Improve CGI compatibility.
Tim-ats-d May 7, 2025
de5de9f
Code formatting
Tim-ats-d May 7, 2025
de15b99
Update doc.
Tim-ats-d May 8, 2025
e428b07
Impose Ipaddr.t instead of polymorphic type.
Tim-ats-d May 8, 2025
91f220e
Apply ocamlformat.
Tim-ats-d May 8, 2025
42f65d8
Fix a bug in CGI stdout reading and improve CGI support.
Tim-ats-d May 9, 2025
e0a57fc
Fix: allow only a single client certificate.
Tim-ats-d May 9, 2025
e40c287
Add `Mehari.tls_version`.
Tim-ats-d May 9, 2025
1a8a785
Introduce more .mli.
Tim-ats-d May 9, 2025
57f1025
Rename "Types" module to "Signatures"
Tim-ats-d May 9, 2025
0b62f71
Improve request and protocol private API.
Tim-ats-d May 9, 2025
29a214b
Remove Mehari.sni of public API and improves protocol API.
Tim-ats-d May 10, 2025
6740c18
Reject empty host in client reques validation.
Tim-ats-d May 10, 2025
34f52c3
Better conformity with CGI spec.
Tim-ats-d May 10, 2025
cf8778d
Clean code.
Tim-ats-d May 10, 2025
25fcf21
Add request and CGI tests.
Tim-ats-d May 11, 2025
bc793a7
Big API changes.
Tim-ats-d May 11, 2025
267afd8
Make support of < TLS 1.2 versions explicit.
Tim-ats-d May 11, 2025
7e772f2
Fix doc.
Tim-ats-d May 11, 2025
6761f37
Improve code.
Tim-ats-d May 11, 2025
7a26078
Internal API change.
Tim-ats-d May 11, 2025
ce47bfe
Update tutorial.
Tim-ats-d May 11, 2025
cd2369e
Repair CGI.
Tim-ats-d May 11, 2025
76e317b
Make raw response builder private.
Tim-ats-d May 12, 2025
c7cb550
Add tests for MIME type.
Tim-ats-d May 12, 2025
9305e8f
Improve code quality of backends.
Tim-ats-d May 12, 2025
94346cd
Move core module type.
Tim-ats-d May 12, 2025
559e936
Improve CGI doc.
Tim-ats-d May 12, 2025
43d3f83
Clean readme.
Tim-ats-d May 12, 2025
324f99a
Implement reader monad to get rid of eio capabalities.
Tim-ats-d May 13, 2025
2d5072b
Remove config parameter from Mehari_*.run.
Tim-ats-d May 13, 2025
09eeb56
bugfix: real client address is now returned by Request.ip.
Tim-ats-d May 13, 2025
3d6a5b0
Improve API for TLS certchains providing.
Tim-ats-d May 13, 2025
0ae0850
Add .mli everywhere in core library and factorize module types.
Tim-ats-d May 14, 2025
f781d6d
Add a warning.
Tim-ats-d May 14, 2025
cb2ddfe
Improve servers implementation.
Tim-ats-d May 14, 2025
c0fa793
Unify mehari-eio and mehari-lwt-unix under a same module type SERVER.
Tim-ats-d May 16, 2025
06eb4d0
Improvement to mehari-mirage.
Tim-ats-d May 16, 2025
b46535d
Improve mehari-lwt-unix.
Tim-ats-d May 16, 2025
25e670c
Improve mehari-eio.
Tim-ats-d May 16, 2025
af77062
Make SNI not mandatory and authorize IP address as domain name.
Tim-ats-d May 16, 2025
42c92f2
Add an advice concering certificate selection in doc.
Tim-ats-d May 16, 2025
5986017
Reply 62 status if client cert provided is invalid.
Tim-ats-d May 16, 2025
d2070e3
Test Gemtext features.
Tim-ats-d May 17, 2025
c5b092f
Defunctorize mehari-eio.
Tim-ats-d May 17, 2025
5e22cdb
Server configuration API change.
Tim-ats-d May 18, 2025
7e90fa9
Try to repair mirage unikernel.
Tim-ats-d May 18, 2025
be2c0ee
Hide Config.default in mehari backends.
Tim-ats-d May 18, 2025
dd70b7f
Miou backend.
Tim-ats-d May 18, 2025
af8fb0a
Improve backends.
Tim-ats-d May 19, 2025
dbe0a72
Provide client port in REMOTE_ADDR CGI variable.
Tim-ats-d May 19, 2025
c114c97
Move CGI features in its own module.
Tim-ats-d May 24, 2025
8c8c5ca
Improve doc.
Tim-ats-d May 24, 2025
532e0f7
Fix Cgi.make signature.
Tim-ats-d May 24, 2025
1669508
Move Mehari_lwt_unix CGI implem in its own file.
Tim-ats-d May 24, 2025
939fcda
CGI support for Mehario_eio.
Tim-ats-d May 24, 2025
bb670ea
Expose monad used by Mehari_eio.
Tim-ats-d May 24, 2025
27e4699
Update dependancies.
Tim-ats-d May 24, 2025
2067a58
Rename path type in Mehari.FS.
Tim-ats-d May 24, 2025
b52bee4
More simple implementation of Mehari_lwt_unix.respond_document.
Tim-ats-d May 24, 2025
c640d2b
Improve filesystem implementation for IO backend.
Tim-ats-d May 25, 2025
3aa7d6d
Repair Mehari_miou_unix.run.
Tim-ats-d May 25, 2025
39ef5db
Filesystem implementation for Mehari_miou_unix.
Tim-ats-d May 25, 2025
e47a8af
More robust implementation for static file serving.
Tim-ats-d May 25, 2025
2540cb7
Remove labeled parameter meth of function virtual_hosts.
Tim-ats-d May 25, 2025
7298e42
Fix examples dependances.
Tim-ats-d May 25, 2025
a226b2d
Use typesafe route.
Tim-ats-d May 30, 2025
307d8f7
Use typesafe route.
Tim-ats-d May 30, 2025
5f27ddd
Update doc.
Tim-ats-d May 30, 2025
1d2ebb4
Improve packaging.
Tim-ats-d May 30, 2025
aa653f1
In progress Miou backend CGI support.
Tim-ats-d Jun 2, 2025
c613ef6
Improve virtual hosting support.
Tim-ats-d Jun 8, 2025
aaacadf
Better logs handling.
Tim-ats-d Jun 8, 2025
2ef9a12
Improve virtual hosting example.
Tim-ats-d Jun 8, 2025
aeba847
Simplify functor logic.
Tim-ats-d Jun 8, 2025
678a17b
Try to repair mirage unikernel.
Tim-ats-d Jun 9, 2025
f1715c4
Fix mehari-eio pckagking.
Tim-ats-d Jun 20, 2025
c34fe1d
Fix packaging.
Tim-ats-d Jun 20, 2025
dba5e90
Mehari 0.5.
Tim-ats-d May 27, 2026
a7f586f
Add maintenance intent.
Tim-ats-d May 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 5 additions & 33 deletions .gitignore
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,38 +1,10 @@
*.annot
*.cmo
*.cma
*.cmi
*.a
*.o
*.cmx
*.cmxs
*.cmxa

# ocamlbuild working directory
_build/
_opam

# ocamlbuild targets
*.byte
*.native

# oasis generated files
setup.data
setup.log

# Merlin configuring file for Vim and Emacs
.merlin
compile_commands.json
dune
dune-workspace
vendors/

# Dune generated files
*.install

# Local OPAM switch
_opam/
.DS_Store

# Certificates
*.key
*.pem

# Sublime Text
*.sublime-project
*.sublime-workspace
2 changes: 2 additions & 0 deletions .ocamlformat
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
profile = default
version = 0.29.0

Empty file modified LICENSE
100644 → 100755
Empty file.
2 changes: 1 addition & 1 deletion Makefile
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ fmt:
dune build @fmt --auto-promote

deps:
opam install --deps-only .
opam install . --deps-only --with-test --with-dev
65 changes: 56 additions & 9 deletions README.md
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Mehari

Mehari is a cross-platform library for building Gemini servers. It fully
Mehari is a library for building Gemini servers. It fully
implements the
[Gemini protocol specification](https://geminiprotocol.net/docs/protocol-specification.gmi).

It takes heavy inspiration from [Dream](https://github.com/aantron/dream), a
tidy, feature-complete Web framework.
It takes inspiration from [Dream](https://github.com/aantron/dream), a
tidy feature-complete Web framework, and from [Nightmare](https://github.com/funkywork/nightmare), a powerful typesafe layer compatible with Dream.

<p align="center">
<img src="https://user-images.githubusercontent.com/59396366/211079934-44f65ed1-8cf7-4193-a815-8da94a85be5d.png" alt="banner"/>
Expand All @@ -23,23 +23,70 @@ opam install mehari
## Features

- Mirage OS friendly
- Type safe route API
- Static files serving
- MIME type inference from file content (using experimental [Conan](https://github.com/mirage/conan/) support)
- Rate limit
- Virtual hosting using SNI
- CGI
- Virtual hosting using TLS SNI
- CGI support
- Long-running TCP connection

## Feedback

Since Mehari is in its early stages, any feedback and contributions regarding the API or security are appreciated.

## Important links

- API documentation: https://docs.heyplzlookat.me/mehari/
- Tutorial: https://docs.heyplzlookat.me/mehari/index.html#tutorial
- Issues: https://github.com/Psi-Prod/Mehari/issues


## Building the unikernel

Setup dev environment:
```bash
$ opam install mehari-mirage solo5 ocaml-solo5
$ opam pin vif.dev git+https://github.com/robur-coop/vif.git#3fb86c53bc56d3af78ce5df76b285a2b476e39ad
$ opam pin vifu.dev git+https://github.com/robur-coop/vif.git#3fb86c53bc56d3af78ce5df76b285a2b476e39ad
$ opam pin zarith.dev git+https://github.com/mirage/Zarith.git#df8969d9bb95cffca13e31a615189ab27ada0684
```

Vendor dependencies:
```bash
$ ./unikernel/vendor.sh
```

Setup network bridge:
```bash
$ ip link add name service type bridge
$ ip addr add 10.0.0.1/24 dev service
$ ip tuntap add name tap0 mode tap
$ ip link set tap0 master service
$ ip link set service up
$ ip link set tap0 up
```

Create `dune` and `dune-workspace` files at the root of the repo:

``` bash
$ cat >dune<<EOF
(vendored_dirs vendors)
EOF
$ cat >dune-workspace<<EOF
(lang dune 3.23)
(context (default))
(context (default
(name solo5)
(host default)
(toolchain solo5)
(disable_dynamically_linked_foreign_archives true)))
EOF
```

Compile and run the unikernel:

```bash
$ dune build --profile=release
$ solo5-hvt --net:service=tap0 -- ./_build/solo5/unikernel/unikernel.exe --ipv4=10.0.0.2/24
```

## License

Distributed under the **LGPL-3.0 License**. See [license](LICENSE) for more information.
95 changes: 34 additions & 61 deletions dune-project
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
(lang dune 3.0)
(lang dune 3.23)

(version 0.4)
(version 0.5)

(name mehari)

Expand All @@ -15,84 +15,57 @@

(homepage "https://github.com/Psi-Prod/Mehari")

(maintenance_intent "(latest)")

(generate_opam_files true)

(package
(name mehari)
(synopsis "A cross-platform library for building Gemini servers")
(synopsis "A library for building Gemini servers.")
(description
"Mehari is a cross-platform library for building Gemini servers.\nIt fully implements the Gemini protocol specification.\nIt takes heavy inspiration from Dream, a tidy, feature-complete Web framework.")
"Mehari is a library for building Gemini servers.\nIt fully implements the Gemini protocol specification.\nIt takes heavy inspiration from Dream, a tidy, feature-complete Web framework.")
(depends
(ocaml
(>= 4.14))
(>= 5.4))
(conan
(>= 0.0.5))
(>= 0.0.7))
(conan-database
(>= 0.0.5))
(>= 0.0.7))
(ipaddr
(>= 5.6.2))
(logs
(>= 0.7.0))
(re
(>= 1.10.4))
(>= 0.10.0))
(mirage-ptime
(>= 5.2.0))
(tls
(>= 0.16.0))
(>= 2.0.4))
(uri
(>= 4.2.0))
(x509
(>= 0.16.2))))

(package
(name mehari-mirage)
(synopsis "Mehari IO implementation for MirageOS")
(depends
(mehari
(= :version))
(ipaddr
(>= 5.3.1))
(lwt
(>= 5.6.1))
(mirage-channel
(>= 4.1.0))
(mirage-time
(>= 3.0.0))
(tcpip
(>= 7.1.2))
(tls-mirage
(>= 0.15.4))
(tls-lwt
(>= 0.16.0))))
(>= 4.4.0))
(alcotest :with-test)
(utop :with-dev-setup)
(ocamlformat :with-dev-setup)
(ocp-indent :with-dev-setup)
(merlin :with-dev-setup)
(ocaml-lsp-server :with-dev-setup)))

(package
(name mehari-lwt-unix)
(synopsis "Mehari IO implementation using Lwt and Unix bindings")
(name mehari-miou)
(synopsis "Mehari server implementation using Miou.")
(depends
(mehari
(= :version))
(mehari-mirage
(= :version))
(lwt
(>= 5.6.1))
(mirage-clock-unix
(>= 4.2.0))
(mirage-flow-unix
(>= 3.0.0))
(mirage-time-unix
(>= 3.0.0))
(tcpip
(>= 7.1.2))))
(tls-miou-unix
(>= 2.0.4))))

(package
(name mehari-eio)
(synopsis "Mehari IO implementation using Eio")
(name mehari-mirage)
(synopsis "Mehari server implementation for Mirage.")
(depends
(ocaml
(>= 5.0.0))
(mehari
(= :version))
(eio
(>= 1.0))
(logs
(>= 0.7.0))
(tls
(>= 0.15.4))
(tls-eio
(>= 0.15.5))))
(mkernel
(>= 0.0.2))
(mnet
(>= 0.0.2))
(mnet-tls
(>= 0.0.2))))
16 changes: 1 addition & 15 deletions examples/README.md
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,6 @@ openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 3
- [guestbook](guestbook.ml) — a more complex application.
- [rate_limt](rate_limit.ml) — rate limits a route.
- [client_cert](client_cert.ml) — demonstrates how to deal with client certificate.
- [eio_backend](eio_backend.ml) — a minimalistic app which shows the rudiments of `Mehari_eio`.
- [stream](stream.ml) — take advantage of Eio's direct style to setup a request handler to stream a response body instead of plain text.
- [stream](stream.ml) — setup a request handler to stream a response body instead of plain text.
- [cgi](cgi.ml) — demonstrates CGI support. Don't forget to make `cgi_script.py` executable.
- [vhost](vhost.ml) — demonstrates the virtual hosting support.

## Unikernel

[unikernel/](unikernel/) is a simple unikernel which serves files located in [unikernel/gemtext/](unikernel/gemtext/).
Copy your private key in [unikernel/tls/server.key](unikernel/tls/server.key) and your certificate in [unikernel/tls/server.pem](unikernel/tls/server.pem) and run the following:

```bash
$ cd unikernel/
$ mirage configure -t unix # initial setup for UNIX backend
$ make depend # install dependencies
$ make # build the program
$ dist/gemini-srv # run the program
```
20 changes: 12 additions & 8 deletions examples/cgi.ml
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
module M = Mehari_lwt_unix
open Lwt.Syntax
open Mehari

let main () =
let* certchains = Common.Lwt.load_certchains () in
M.router
[ M.route "/cgi" (fun req -> M.run_cgi "./examples/cgi_script.py" req) ]
|> M.run_lwt ~certchains
let router =
let open Router in
router
[ route Path.(~/"cgi") (Mehari_miou.run_cgi "./examples/cgi_script.py") ]

let () = Lwt_main.run (main ())
let () =
Miou_unix.run @@ fun () ->
Mirage_crypto_rng_unix.use_default ();
let certs = Common.load_certs ~cert:"cert.pem" ~priv_key:"key.pem" in
Mehari_miou.run ~certs
Ipaddr.(V4 (V4.Prefix.make 8 V4.localhost))
(Logger.logger router)
8 changes: 6 additions & 2 deletions examples/cgi_script.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
#!/usr/bin/env python3

print("20 text/gemtext\r\n")
print("Hello from a CGI script!")
import os

server = os.getenv("SERVER_SOFTWARE")

print("20 text/gemtext\r")
print(f"Hello from a CGI script served by {server}!")
37 changes: 23 additions & 14 deletions examples/client_cert.ml
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,18 +1,27 @@
open Mehari

let router =
Mehari_eio.router
Router.router
[
Mehari_eio.route "/" (fun req ->
match Mehari.client_cert req with
| [] -> Mehari.(response client_cert_req) "Certificate plz"
| hd :: _ ->
X509.Certificate.encode_pem hd
|> Cstruct.to_string
|> Printf.sprintf "Client certificate ~nyoron\n%s"
|> Mehari.response_text);
Router.route Path.root (fun req ->
match Request.client_cert req with
| None -> Response.respond Status.client_cert_req "Certificate plz"
| Some cert ->
let pem = X509.Certificate.encode_pem cert in
let common_name =
X509.Certificate.subject cert
|> X509.Distinguished_name.common_name
|> Option.value ~default:"None"
in
Printf.sprintf "Ur client certificate ~nyoron\n%sCommon name: %s"
pem common_name
|> Response.text);
]

let main ~net ~cwd =
let certchains = Common.Eio.load_certchains cwd in
Mehari_eio.run net ~certchains router

let () = Common.Eio.run_server main
let () =
Miou_unix.run @@ fun () ->
Mirage_crypto_rng_unix.use_default ();
let certs = Common.load_certs ~cert:"cert.pem" ~priv_key:"key.pem" in
Mehari_miou.run ~certs
Ipaddr.(V4 (V4.Prefix.make 8 V4.localhost))
(Logger.logger router)
Loading