August 22, 2010

HTTP Server

In my previous post, I mentioned the goal of separating protocols from the client object. As an experiment, I started writing a HTTP service using the new code. This would let me run a light web server as a service in conjunction with something like WebSockets on the same, single-threaded server.

You definitely don't want to waste time serving big files in a single threaded application because it blocks but for little things like a login page it could be handy. Plus, I've written web based apps for years but never fully understood what was happening under the hood and here was a chance to find out.

The actual HTTP protocol is pretty simple. It only has eleven commands (or methods); HEAD, GET, POST, PUT, DELETE, TRACE, OPTIONS, CONNECT, and PATCH. Currently, I only support one, GET (which is easily 99.9% of the web). All other methods are responded to with a status code 501 Not Implemented.

Here's my index.html rendered on Chromium:

This actually represents three separate HTTP GET requests; the index.html file, the skull image, and the tiny skull favicon shown on the tab.

The skull is a compressed SVG, to get Chromium to display it I had to add Content-encoding parameter to my HTTP Response;


I've started the total re-write of my asynchronous network library Miniboa. The new code, in addition to being cleaner, is different in several ways.

What's New
  • No longer Telnet-centric; my aim is to keep connections generic and wrap them in protocol handlers.
  • Services; you can now run multiple services under a single server. Each service listens on a different port and can have unique protocols and events.
  • Added hooks for coroutine-based, character-at-a-time protocol handlers.
  • No longer line-based; the new API has get_ch() to get one character or get_input() to retrieve the entire input buffer. This is support users that want to write features like text editors and command completion.
  • New event; on_input() that is called when the data is received from the client.
  • When run under Linux, it uses the Epoll API introduced in Linux kernel 2.5.44. All other platforms user Select().
I kept the server polled from within the user's game loop. I know that event and callback driven designs are more efficient, but I really like the approachability of that pattern. It can be hard to think in terms of callbacks.