**Wibble web server** [AMG]: Wibble is a small, [pure-Tcl] web server inspired by [Wub], [DustMote], [Coronet], and [Templates and subst]. One fine day I wanted to put together a site using Wub, but I needed help and couldn't find [CMcC] or [JDC] in the [Tcl chatroom]. The need to hack would not be denied! So I wrote this. This code is intended to be customized for your application. Start by changing the zone handlers and root directory. Feel free to create your own zone handlers; it's very easy to do so. Just make another [proc]. ***Name*** Regarding the name: "Wibble" is similar in sound to "Wub", and http://en.wikipedia.org/wiki/Wibble%|%according to Wikipedia%|%, it is one possible pronunciation of "[www]". ***Zone handlers*** Zones are analogous to domains in Wub and [TclHttpd]. Zones are matched against the [URI] by prefix, with an important exception for directory names. I use the name "zone" instead of "domain" because I don't want any confusion with [DNS] domain names. Someday I may add support for virtual hosts via the Host: header, which means that DNS domain/host names will be included in zone names. Handlers can be stacked, so many zones are defined by a combination of handlers which are executed in sequence. Each handler receives a request [dict]ionary as its last argument, augmented with configuration options and a few extra parameters. The request dictionary is derived from the HTTP request. The configuration options are defined in the '''$::zones''' variable. The extra parameters indicate the match prefix and suffix, plus the (possible) filesystem path of the requested object. The handler then uses the [[operation]] command to return an opcode and operand. The opcode specifies which operation should be performed to continue or finish processing. Zones also stack. For example, if no handlers for zone /foo return a response, then the handlers for / are tried. Just as the handlers within a zone must be specified in the order they are to be executed, the zones themselves must be specified in order of decreasing specificity. To inhibit this stacking behavior, be sure that a default handler is defined for the zone, e.g. '''notfound'''. There is a list of requests, initialized to contain only the request received from the client. Requests can be added, modified, or deleted by zone handlers. Each request is tried in turn against each handler in the zone. ***Request dictionary*** * '''socket''': The name of the Tcl [channel] that is connected to the client. * '''peerhost''': Network address of the client. * '''peerport''': TCP port number of the client. * '''method''': HTTP method (GET, PUT, POST, HEAD, etc.). * '''uri''': HTTP URI, including query string. * '''path''': Path of client-requested object, excluding query string. * '''protocol''': HTTP/1.0 or HTTP/1.1, whatever the client sent. * '''header''': Dictionary of HTTP header fields from the client. * '''query''': Dictionary of query string elements. * '''querytext''': Query string in text form. ***Extra parameters*** * '''prefix''': Zone prefix name. * '''suffix''': Client-requested object path, sans prefix and query string. * '''fspath''': Object path with '''root''' option prepended. Only defined if '''root''' option is defined. ***Configuration options*** * '''root''': Filesystem directory corresponding to zone root directory. * '''indexfile''': Name of "index.html" file to append to directory requests. Support for configuration options varies between zone handlers. ***Supported zone handler return opcodes*** * '''prependrequest''': Merge operand with request dictionary and insert into list of requests with high priority. * '''replacerequest''': Merge operand with request dictionary, replacing current request. * '''deleterequest''': Remove current request from request list. * '''sendresponse''': Send operand to client as response dictionary. * '''pass''': Fall through to next request or next handler. ***Predefined zone handlers*** * '''vars''': Echo request dictionary plus any extra or optional arguments. * '''dirslash''': Redirect directory requests lacking a trailing slash. * '''indexfile''': Add '''indexfile''' to directory requests. * '''static''': Serve static files (not directories). * '''template''': Serve data generated from .tmpl files. * '''dirlist''': Serve directory listings. * '''notfound''': Send 404. ---- **Sample index.html.tmpl** ====== % dict set response header Content-Type "text/html; charset=utf-8" $uri % set rand [expr {rand()}] % if {$rand > 0.5} { random=[format %.3f $rand] > 0.5
% } else { random=[format %.3f $rand] <= 0.5
% } time/date=[clock format [clock seconds]]
milliseconds=[clock milliseconds]
clicks=[clock clicks]
% if {![dict exists $query noiframe]} {