Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 9 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,13 @@ jobs:
if: ${{ matrix.atomic_arc }}
- run: nim c -r -d:useMalloc tests/test_http2.nim
- run: nim c -r -d:useMalloc tests/test_websockets.nim
- run: nim c -r -d:useMalloc -d:ssl tests/test_http.nim
if: ${{ runner.os == 'Linux' }}
- run: nim c -r -d:useMalloc -d:ssl tests/test_tls.nim
if: ${{ runner.os == 'Linux' }}
# The fuzzer creates a few thousand servers in seconds. On Windows every
# SelectEvent is a loopback socket pair, so the dynamic port range runs
# out part-way through and newServer raises (upstream's Windows job flakes
# the same way); Linux is where the fuzzer is meaningful.
- run: nim c -r -d:useMalloc -d:mummyNoWorkers tests/fuzz_recv.nim
if: ${{ runner.os == 'Linux' }}
40 changes: 39 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,40 @@
# Mummy
# Mummy (FrameOS fork)

This is [FrameOS](https://github.com/FrameOS/frameos)'s fork of
[guzba/mummy](https://github.com/guzba/mummy). It adds what FrameOS needs to
serve its on-device API over HTTPS without a separate proxy process:

- **TLS listeners.** Compile with `-d:ssl` and pass a `TlsConfig` to
`addListener`; the handshake, reads and writes run inside the same epoll
loop as plain sockets (OpenSSL via Nim's `std/openssl`, no extra bindings).
The certificate chain and private key are loaded from memory with
`newTlsConfig(certificateChainPem, privateKeyPem)`, so the key never has to
be written to disk. TLS 1.2 is the minimum version.
- **Several listeners per server**, plain and TLS side by side, added with
`addListener(port, address, tls)` and removed with `removeListener` — from
any thread, before or while serving. `serve()` with no arguments serves on
all of them; `serve(port, address)` still works as before.
- **`Request.secure`**, true for requests that arrived over a TLS listener.

Everything else is upstream mummy. Pin it by commit from a nimble file:
`requires "https://github.com/FrameOS/mummy#<commit>"`.

```nim
import mummy

proc handler(request: Request) =
request.respond(200, emptyHttpHeaders(), "secure: " & $request.secure)

let server = newServer(handler)
discard server.addListener(Port(8080), "0.0.0.0")
let tls = newTlsConfig(readFile("cert.pem"), readFile("key.pem"))
discard server.addListener(Port(8443), "0.0.0.0", tls)
server.serve()
```

`nim c --threads:on --mm:orc -d:ssl -r tls_server.nim`

---

`nimble install mummy`

Expand Down Expand Up @@ -225,4 +261,6 @@ Requests/sec: 9,171.55

## Testing

The TLS listeners are covered by `nim c -r -d:ssl tests/test_tls.nim` (plain and TLS side by side, `Request.secure`, a multi-megabyte response, WebSocket over TLS, a client stalled mid-handshake, listeners added and removed while serving).

A fuzzer has been run against Mummy's socket reading and parsing code to ensure Mummy does not crash or otherwise misbehave on bad data from sockets. You can run the fuzzer any time by running `nim c -r tests/fuzz_recv.nim`.
Loading
Loading