Following on from yesterday's post, I decided to try implement proper
content negotiation. After a fair amount of time spent getting to grips with
Lua, I got a script which works very nicely. It implements server driven
content negotiation for media types.
The basic idea of content negotiation is that a resource (e.g., this graph)
exists in multiple formats (in this case, SVG, PNG and
GIF). When a user agent requests the resource, it indicates which
formats it understands by listing them in the Accept header. The server
compares these to the available formats and sends the best one. So a browser
which can display SVG will receive the diagram in SVG format, while a
browser which can't will receive it in PNG (or GIF) format.
(The following description assumes knowledge of the Accept header format.)
The script works by searching the directory for files with the requested name
but with an additional extension (each of which is a variant). The media
type is inferred from the extension using /etc/mime.types, and the
quality of the type is set by a hardcoded table in the script. Each variant is
checked against the acceptable types sent by the user agent, and the overall
quality calculated by multiplying the quality with the q parameter in the
Accept header. The variant with the highest overall quality is then chosen.
Some browsers include wildcard entries such as image/* and */* in the
Accept header without specifying a q parameter. This parameter defaults to 1
(the highest value), which means that no preference is actually
indicated. The script implements the same hack that Apache does in order
to compensate for this. It also handles directory index files by defaulting to
files named "index".
To install the script, download and save it somewhere (such as
/etc/lighttpd/). Then add the following to the site definition.
magnet.attract-physical-path-to = ("/etc/lighttpd/negotiate.lua")