I can succinctly describe Apache’s mod_negotiate in the words of Homer Simpson: “It can’t be turned off… Though it does break easily.”

I’ve spent longer than I care to contemplate wrestling with a mod_rewrite directive that was acting up on the about and /projects/ sections of this site. I’ll record the resolution here for posterity.

The directive was a simple one:

RewriteRule ^projects/(.+) /projects/?project=$1

This should take a URL such as /projects/make-link and map it onto /projects/?project=make-link. As mod_rewrite goes, this is a simple one. It gave me a 404 response every time.

After much poking and prodding I discovered that it would do the correct redirect for the url /projects/foo. (This took a lot of fiddling to discover, because the script that serves that part of the site will return a 404 response for projects that don’t exist, making that indistinguishable from a failed redirect. I had to edit that script to discover that the redirect was working for /projects/foo but not for /projects/make-link.) This turned out to be the work of mod_speling (sic). It will “fix” a single typo in any url you request (a missing character, an extra character or a transposition), so it was rewriting “make-link” to “makelink”, which happens to be the name of a directory in that section.

Having turned off mod_speling, I still had trouble. I narrowed the bug down to three simple conditions. Usually /projects/foo would redirect properly to /projects/?project=foo. If there was a file in the /projects/ directory called foo.html then /projects/foo would redirect to /projects/?project=foo.html. Finally, if there was a file called in that directory (and there was), it would crap out and give a 404 response.

This was caused by the aforementioned mod_negotiate, which basically guesses what file to serve if it’s asked for a URL with no file extension. The default is to serve whatever file it can that it recognises the extension for. Thus it will serve foo.html because it knows the .html extension, but it doesn’t play well with because .inc is just something I made up for my own convenience.

The problem is that this module can’t be turned off! Ridiculous. The only thing I could do to stop it from breaking my site was to set it to be as promiscuous as it can be, to try to serve up any file with any extension that seems to match. This got me to the stage that /projects/foo would redirect to /projects/? A small change to the relevant scripts now strips the unwanted “” from the parameter it’s given.

Why is there no off switch on that module?