rakus — a static HTTP file server
Point it at a directory and it serves the files inside over HTTP/1.1 — the Raku answer to python3 -m http.server, on nothing but IO::Socket::INET.
This is the showcase copy: one file, runnable straight from a checkout. The installable distribution lives in raku-modules/App-Rakus as
App::Rakus, where the routing is split into a library so it can be tested without a socket. It is published to the zef ecosystem (raku.land), sozef install App::Rakusputs arakuscommand onPATH— one that serves the current directory by default, where this copy serves its bundledpublic/. Edits here do not reach there, or the other way about. Where the
pastebin is a single-purpose app with a hand-wired route table, rakus is a reusable server: give it a folder and it figures out the rest.
Run it
build/rakupp showcase/rakus/rakus.raku # serves ./public on :8080
build/rakupp showcase/rakus/rakus.raku 9000 # choose the port
build/rakupp showcase/rakus/rakus.raku 9000 ~/site # choose port and root
# or compile a standalone binary:
build/rakupp --exe -o rakus showcase/rakus/rakus.raku && ./rakus 8080 ~/site
Then open http://127.0.0.1:8080/. With no root given it serves the bundled public/ folder — a landing page, a stylesheet, an SVG logo, and a files/ directory with no index (so you can see the auto listing).
What it does
- Correct
Content-Typeby extension — text and binary. HTML, CSS, JS, JSON, SVG, PNG, JPEG, … (files are read as raw bytes and streamed back, so images arrive intact). index.htmlwhen a directory has one; otherwise an auto directory listing with sizes and links.GETandHEAD; other methods get405.301to add a missing trailing slash on a directory (so relative links resolve),403on..path traversal,404for anything missing.- Concurrent — one
startthread per connection. - Logs each request to stderr:
200 GET /style.css.
From the command line
$ curl -sI http://127.0.0.1:8080/logo.svg
HTTP/1.1 200 OK
Content-Type: image/svg+xml
Content-Length: 289
Server: rakus
Connection: close
$ curl -s http://127.0.0.1:8080/files/ | grep -o 'Index of[^<]*'
Index of /files/
$ curl -so /dev/null -w '%{http_code}\n' http://127.0.0.1:8080/nope
404
How it works
- No HTTP library. Each connection is read with
recvuntil the header terminator; the request line is split into method and target by hand. - Path handling. The target is URL-decoded and the query stripped; a
..segment is rejected; the rest is joined onto the (absolute) document root. - Serving. A directory resolves to
index.htmlor a generated listing; a file isslurp-ed as aBufand its bytes written straight to the socket with aContent-Length. The headers go out withprint, the body withwrite— so binary files are byte-exact. - Byte-exact bodies. Every response body is a
Buf(generated HTML is.encode-d), soContent-Lengthis always the true byte count.