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][mime].
The basic idea of content negotiation is that a resource (e.g., this [graph])
exists in multiple formats (in this case, [SVG][graph-svg], [PNG][graph-png] and
[GIF][graph-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][mime] 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
*/* 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")