Mon, 26 Jun 2006

Blosxom Static Rending with Lighttpd

To get more familiar with lighttpd, I've switch over the web server on this machine from apache to lighty. The most difficult part has been replicating my apache setup to serve static blosxom files.

My goal is to serve a static html file if 1) a static version exists, 2) the query string is empty, and 3) the request is not a POST. Because I've switched from using the blosxom writeback plugin for comments to Haloscan, I don't have to worry about the third condition, but it would be nice to figure out a way to replicate RewriteCond %{REQUEST_METHOD} !^POST [NC] with lighty.

Here's what I've come up with in my lighttpd.conf:

$HTTP["host"] == "xn.pinkhamster.net" {
        server.document-root       = "/www/xn.pinkhamster.net"

        $HTTP["url"] =~ "^/blog" {
		cml.power-magnet = server.document-root + "/power-magnet.cml"
        }

	# There's no content at http://xn.pinkhamster.net/ so redirect to /blog/
        url.redirect = ("^/$" => "/blog/")

	# I'm not using the writeback plugin anymore so rewrite any
	# requests for writeback pages to the corresponding html page.
        url.rewrite-once = (
                "^/blog/(.+)\.writeback(\?.*|$)" => "/blog/$1.html$2",
        )

	# If there's not a static file served by the power-magnet, have blosxom
	# serve the page.
        alias.url = (
                "/blog" => "/usr/lib/cgi-bin/blosxom",
        )
        cgi.assign = ( "blosxom" => "" )

}

In order to serve the static pages, we have to use the power-magnet feature. The power-magnet is a CML (Cache Meta Language) script which runs for each request. In this case, we only run it for requests that start with "/blog". CML is designed to improve web serving performance by serving cached, static pages when possible.

CML scripts are written in Lua. My check for an empty query string doesn't work yet; I'm hoping to get some help on the lighty mailing list. Update: I've updated the check for an empty query string so it actually works. There was a logical error in my first attempt, but neither get.maxn ~= nil nor get.maxn ~= 0 works. So now I just loop through the query string values and update a counter if there are any. It's not very efficient, but it works. The rest of the script just checks for either a static index.html file if the request was for a directory or the static version of the requested page, and returns it if it exists. Update 2: I've updated the power magnet script to not have to loop through the get array.

-- if query string is empty and static file exists, serve static file
dr = request["DOCUMENT_ROOT"]
-- local f=assert(io.open(dr.."/debug.out","a"))

-- this doesn't work how i think it should
-- if get.maxn ~= nil then return 1 end

i = 0
for k,v in pairs(get) do
        i = i+1
end
-- f:write("i = ",i,"\n")
if i ~= 0 then return 1 end

sn = request["SCRIPT_NAME"]

static = string.gsub(sn, '^/blog/(.*)$', '/static/%1')

if (file_isdir(dr .. static) and file_isreg(dr .. static .. "/index.html")) then
--      f:write("cache hit on directory\n")
        output_include = { dr .. static .. "/index.html" }
        return 0
elseif file_isreg(dr .. static) then
--      f:write("cache hit on file\n")
        output_include = { dr .. static }
        return 0
end

-- f:write("no cache hit\n")
return 1

tech | Permanent Link

The state is that great fiction by which everyone tries to live at the expense of everyone else. - Frederic Bastiat