App::Rakus
App::Rakus
rakus ā a static HTTP file server for the command line. Point it at a
directory and it serves what is inside over HTTP/1.1, on nothing but
IO::Socket::INET.
Status: v0.0.2 ā implemented and tested on both engines. 37 assertions in
t/, no dependencies.
rakus # serve . on http://127.0.0.1:8080/
rakus 9000 # choose the port
rakus 9000 ~/site # choose the port and the directory
rakus --quiet 9000 ~/site # without the request logWhat it does
Correct
Content-Typeby extension ā text and binary. Files are read and written as bytes, so images arrive intact andContent-Lengthis always the true byte count. An unknown extension isapplication/octet-streamrather than a guess.index.htmlwhen a directory has one, otherwise a generated directory listing with sizes and links. Dotfiles are left out of it.GETandHEAD; anything else gets405.301to add a missing trailing slash on a directory, so relative links inside it resolve;403for a..segment, which is refused rather than resolved;404for anything missing.One thread per connection, and a request log on stderr:
200 GET /style.css.
As a library
The routing ā handle ā is a pure function of (method, target, root): it
returns the whole response and touches no socket, so what the server answers
can be used, and tested, with no port and no network:
use App::Rakus;
my ($status, $type, $body, $extra) = handle('GET', '/index.html', '/var/www');
say mime-for('logo.svg'); # image/svg+xmlThe rest of the module is the server around that function ā these do open sockets, in stages, so a caller can choose where to take over:
my $listener = listen-on(8080); # bind, and keep the socket
accept-loop($listener, '/var/www'); # serve on it until it closes
run(:port(8080), :root('/var/www')); # bind, announce, serve ā the whole thingScope
In v0.0.2: the above, and nothing else. No configuration file, no TLS, no
range requests, no compression, no caching headers, no keep-alive ā every
response says Connection: close. It is a development and local-network
server, in the same spirit as python3 -m http.server, and it says so rather
than implying otherwise.
Compatibility
It is released only once its tests pass under Rakudo and under Raku++.
| engine | version | t/ |
|---|---|---|
| Rakudo | v2026.08 (MoarVM 2026.08, Raku v6.d) | 37/37 |
| Raku++ | v3.7.0 (the released binary, which is what CI installs) | 37/37 |
v1.8.0 is the minimum Raku++ version.
Licence
Artistic-2.0.
Design notes ā why it is shaped this way, and what running it on two engines turned up ā are kept out of the distribution, in notes/App-Rakus.md.