Hi.
It is quite certain that the basic reason for my troubles is my own lack of expertise, but
I suppose that others may stumble into the same issue at some point, and this may help
them avoid the loss of time involved.
Basically, I had an Apache (2.2) configuration section as follows :
<Location /login>
PerlAccessHandler my::module->access
PerlFixupHandler my::module->fixup
SetHandler modperl
PerlResponseHandler my::module->login
PerlSetVar my_login_form "/login.html"
</Location>
As you can probably guess, this is part of a self-written authentication mechanism derived
from Apache::AuthCookie, and the login form that is used is the document at
(DocumentRoot)/login.html.
Now this has worked fine on dozens of servers so far, for several years.
But then unexpectedly on this new similar webserver that I just set up, it didn't work
anymore, in a quite peculiar way :
- the above PerlAccessHandler was run fine, and logged everything as normally
- but neither the PerlFixupHandler nor the PerlResponseHandler were being run, without any
error or trace at all in the logs.
Instead, all I got was the login document in the browser, but in a way that showed that it
was delivered straight from the disk, without going through the response-handler at all
(which it normally does).
It was also quite puzzling because how could it respond with "/login.html" when I
requested "/login", and how could it nevertheless show a POST to "/login", with a response
code 200 OK in the access log.
Did Apache somehow start behaving like hateful end-user software, divining what was good
for me, instead of what I explicitly said I wanted ?
To make a long story shorter (by 2 days), I finally realised that it was because in this
particular server, there was a unique coincidence of two elements :
- the DocumentRoot directory of the server had a "Options MultiViews" added to
it
- my login document was "/login.html"
And why the problem happened was this stanza in the Apache on-line documentation of the
Options directive (and/or mod_negociation) :
quote
MultiViews
A MultiViews search is enabled by the MultiViews Options. If the server receives a request
for /some/dir/foo and /some/dir/foo does not exist, then the server reads the directory
looking for all files named foo.*, and effectively fakes up a type map which names all
those files, assigning them the same media types and content-encodings it would have if
the client had asked for one of them by name. It then chooses the best match to the client's..
unquote
So what happened here was :
- the PerlAccessHandler was run normally, as it happens quite early in the Apache cycle,
before Apache even starts to map the URL to a file on disk
- then somewhere mod_negociation takes over.
It looks at the requested URL (/login), and does not find a corresponding directory
"(DocumentRoot)/login".
So then, it looks in the directory "/", trying to find anything that looks like
"login.*".
In this case, it finds "/login.html".
So it sets things up to return "/login.html" as the response. Predictable and fair enough,
one could say.
Except that in the process it *disables* the other configuration lines which should have
invoked the fixup handler and mod_perl as the response handler, and these are never run.
Instead, it seemingly runs the Apache default handler, which just returns the
file.
Removing the MultiViews option made things get back to normal.
Changing the name of the login form to something not matching "/login" so closely also
does the trick.
But it took me close to two days to figure this out, mainly because I have dozens of other
servers which have exactly the same <Location> section and are doing fine, and I just
never realised that this MultiViews Option, inherited from way back up there in the
configuration, could have such a drastic effect.
HTH someone some day.