This week I built the other major component of my game's user interface: my own HTTP 1.1 server. The server is now built into the client to serve up web pages to my Chrome UI. At some point I might also put it into my servers so remote monitoring tools can check for server status via a simple web page request (a server I worked on previously dumped an XML file of status variables any time a browser did an HTTP GET request to it.)
Building an HTTP server isn't as complicated as I thought it would be, particularly since I only have one web browser I have to test the server against. Initially I tested with both Firefox and Chrome, and I was surprised at the differences in their behavior.
The bulk of my understanding of HTTP comes from HTTP Made Really Easy which is exactly what it says it is. Add to that a quick look at Tiny HTTPd to build my confidence (it is an HTTP server in one C file) and RFC 2616 to look up some of the more obscure details, and I had everything I needed.
The first component I built was a generic Stream Socket Server which uses blocking sockets and threads to provides a simple interface I can plug any TCP server into. Blocking sockets might be a bit controversial, but the server doesn't need to be high performance, and blocking sockets are really simple to implement and cross-platform. It opens the socket, listens, then spins off threads for each connection.
Those connection threads are implemented as a HTTP Protocol Plugin which reads from the socket, splits out the request, header lines and the message body and parses out the parameters for GET/POST forms. It also figures out what type of content the client is asking for, writes out the response headers and even does compression of the response data using zlib. Compression was foisted on me by Chrome which doesn't always seem to accept plain text. One big item required by the HTTP 1.1 spec that I didn't implement is data chunking. The main reason is that Chrome has never used it in any of its requests. Maybe if I ever need to have the server support a wider range of clients I'll look into adding that.
Each time a page is requested, the HTTP Protocol Plugin calls the Page Data Source which is the only game-specific part of the system. It interfaces with my resource system so it can pull UI pages out of the resource bundle files. The other big thing the page data source does is do parameter replacement on any text assets it processes. Any time it sees something like [[$GameName]] it replaces that with the GameName string from the locale database. It also maintains a search tree of name-value pairs of a variety of in-game data structures such as the User Info record, game settings, version information and more. One big benefit of the string replacement system is that each screen is localized via my locale database so I don't need to have multiple versions of the UI html files. Timesaver.
The other thing the Page Data Source does is hold a registry of Ui Page Handlers. Each page handler is a class which is matched to a UI html file. It processes input from forms such as the Login page. The Login page handler takes the username and password, updates the settings, then kicks off the connection and logs the player into the game server. The page handlers are stored in a search tree so they can be looked up quickly by URL.
We were unable to retrieve our session cookie from your web browser. If pressing F5 once to reload this page does not get rid of this message, please read this to learn more.
You will not be able to post until you resolve this problem.