Golfing httpd
I’m building a internet radio player and wanted both a curses and web interface to switch stations. Looking at the various modules in the ecosystem provided lots of options that do lots of things. I had a bug hunt in those field a while ago and didn’t like it. The amount of httpd
I need is fairly small and I thought to myself: „Somebody should golf that!“. And so I did.
The objective is to have as little http as I can get away with. I want to display the names of available stations and receive a station-id to switch stations. And maybe a stop, play and record button. That can be done with with lines of text. So text/plain
it is.
I can stuff channel-ids and button names into URLs. What means implementing only GET will do. Caching or other fancy stuff wont be needed, what makes the HTTP-header static. The most complex thing to do would be taking the URL apart.
That’s what I came up with:
my sub term:<now>() { DateTime.now.Instant but role :: { method Str { self.DateTime.hh-mm-ss } } }; my &BOLD = $*OUT.t ?? sub (*@s) { "\e[1m{@s.join('')}\e[0m" } !! sub (|c) { c }; constant HTTP-HEADER = "HTTP/1.1 200 OK", "Content-Type: text/plain; charset=UTF-8", "Content-Encoding: UTF-8", ""; constant term:<HTTP-HEADER-404> = "HTTP/1.1 404 Not Found", "Content-Type: text/plain; charset=UTF-8", "Content-Encoding: UTF-8", ""; react { whenever IO::Socket::Async.listen('0.0.0.0', 8080) -> $conn { note „{now} incomming connection from {$conn.peer-host}:{$conn.peer-port}“; my @msg = HTTP-HEADER; whenever $conn.Supply.lines { if /^GET (<[\w„/“]>+) [„HTTP“ \d „/“ \d]? / { note „{now} GET $0“; given $0.Str { @msg.push: „running since {BEGIN now} UTC“ when „/status“; @msg.push: „Hello World!“ when „/“; done when „/exit“ default { @msg = HTTP-HEADER-404; @msg.push: „Resource {.Str} not found.“; } } } if /^$/ { for { once note .Str; $conn.print(.Str ~ "\n") } $conn.close; } } CLOSE { note „{now} connection closed“; } CATCH { default { warn BOLD .^name, ': ', .Str; warn BOLD "handled in $?LINE"; } } } }
The whole thing waits for a connection. Then takes the URL apart and fills an Array
with lines of text. That Array
is then send back to the client. A few lines of logging and error handling.
The less code there is the less ground a bug hunter has to cover. Luckily Perl 6 is very friendly to golfers.
UPDATE: Add proper handling of the http header terminator, what leads to less error handling. Also, add some more log output.
-
September 11, 2017 at 23:182017.37 Collating Sorted | Weekly changes in and around Perl 6