perl-modperl mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Rici Lake <r...@ricilake.net>
Subject Re: perl modules not running after 'minor' change
Date Tue, 07 Sep 2004 04:06:22 GMT
Hi, Ben (and modperl folken)

I've pieced together your config file from the bit's you've sent me and 
posted; I deleted the ip numbers, but here is what I think it basically 
looks like:

# Doesn't work
<Location /server-status>
    SetHandler server-status
    Order deny,allow
    Deny from all
    Allow from xx.xx.xx.xx
    Allow from 127.0.0.1
</Location>

# Doesn't work either
<Location /server-info>
    SetHandler server-info
    Order deny,allow
    Deny from all
    Allow from xx.xx.xx.xx
    Allow from 127.0.0.1
</Location>

# This one also doesn't work
<Location /perl-status>
        SetHandler perl-script
        PerlHandler Apache::Status
</Location>

# But this works fine
<Location />
        SetHandler perl-script
        PerlHandler Apache::putInJava
</Location>

# As does this
<Location /howdy>
        SetHandler perl-script
        PerlHandler Apache::HelloWorld
</Location>

# And this
<Location /secret>
        AuthName  " -- Use your regular name in the User Name field -- "
        AuthType Basic
        PerlAuthenHandler Apache::AuthPwd
        require valid-user
</Location>

-------------------------------

OK, the pattern there is pretty clear: everything start with <Location 
/> works

But what's perhaps confusing is that the access control in the first 
two Location stanzas is actually working, even though the SetHandler 
isn't.

So time for a little Apache-fu:

When Apache tries to figure out what applies to which URL, it does 
something called configuration merging. The basic algorithm is pretty 
well described in the documentation 
(http://httpd.apache.org/docs-2.0/sections.html), but the devil is in 
the details so it's worth looking at this in detail, using the above as 
an example.

For now, we'll leave out <Directory> sections, <Files> sections and all 
the other wonderful stuff; the principles are roughly the same (but see 
below). I'll just note that Location sections happen after all of that. 
Each of these things: <Foo > ... </Foo> is a "container".

The basic idea is that Apache starts with some configuration, and then 
goes through containers one at a time, in some order. For each 
container that applies (i.e. matches the current request), the 
configuration is merged with the configuration in the container, 
producing a new merged configuration. This continues until we get to 
the end of the containers, and the final merged configuration is the 
result.

In pseudo-code (sorry, my perl is rusty):

   config = default
   foreach container in Containers do
     if request matches container then
       config = merge(config, container)
     end
   end

Now, the important thing about the merge function is that it is 
implemented by modules, each
one acting independently of each other one, without any knowledge of 
each other's directives.

In the above example, we have four modules represented:

mod_mime: implements SetHandler
mod_perl: implements PerlHandler
mod_access: implements Allow, Deny and Order
mod_auth_basic: implements AuthType, AuthName and Require

So, let's consider what happens with the request /server-status.
This matches two containers: /server-status and /, in that order

mod_mime gets "SetHandler server-status" from /server-status, and then 
merges it with "SetHandler perl-script" from /. The merge in this case 
is "second one wins" (there is only one handler slot), so the end 
result is "SetHandler perl-script"

mod_perl only sees the / container, because it has no directives in 
/server-status. So it ends up with "PerlHandler Apache::putInJava"

mod_access only sees the /server-status container, because it has no 
directives in /. So it ends up with "Order deny,allow"; "Deny from 
all"; "Allow from xx.xx.xx.xx"; and "Allow from 127.0.0.1"

mod_auth_basic doesn't get involved at all. It has no directives in 
either of these containers.

So the final configuration for /server-status is:

SetHandler perl-script
PerlHandler Apache::putInJava
Order deny,allow
Deny from all
Allow from xx.xx.xx.xx
Allow from 127.0.0.1

As we might expect (having been through this whole exercise), the 
mod_access directives are checked, resulting in FORBIDDEN (403) if not 
accessed from one of the valid ip numbers; if that passes, then the 
request is given to the perl-script handler, which is part of mod_perl; 
it then checks the PerlHandler configuration, and sends the request to 
Apache::PutInJava. This handler wants a file, but 
DOCUMENTROOT/server-status doesn't exist. When it returns DECLINED, 
Apache is left with nothing to do other than to return it's own 
NOT-FOUND; after all, there is no file there.

If we go through this exercise again with the /perl-status container, 
it is easy to see that mod_mime will end up with "SetHandler 
perl-script"; after all, both /perl-status and / have the same 
directive; mod_perl will end up again with "PerlHandler 
Apache::PutInJava". And the same NOT-FOUND error will result, this time 
without any access check.

The /howdy section is after the / section, so the order of merging is 
different. Now, mod_mime is still merging two identical directives, but 
mod_perl sees "PerlHandler Apache::PutInJava" first and "PerlHandler 
Apache::HelloWorld" second. Again, last one wins, so this time we end 
up with:

SetHandler perl-script
PerlHandler Apache::HelloWorld

which was actually the desired outcome (maybe).

This e-mail is long enough without considering the other sections in 
that example, but it is worth trying each of them on paper to see what 
the results are. The most interesting ones are the first two, though, 
because it shows how the Apache configuration merging algorithm can 
take some directives from one container and some other directives from 
a different container.

Obviously, this requires some careful thought to get right, but a good 
rule of thumb is: put your Location sections in order in the file, from 
least-specific to most-specific. Then things will probably work out the 
way you would expect them too.

Interestingly, Apache does a shortest-to-longest sort on <Directory> 
sections (excluding regular expression DirectoryMatch or Directory ~ 
sections.) All other sections are merged in the order they show up in 
the configuration file, so it's your responsibility (or pleasure) to 
get it right.

Hope this treatise helps someone.

Rici

PS: I don't know what putInJava does, but I suppose it modifies the web 
page in some way. This strikes me as more of an output filter than a 
handler; I am led to believe that mod_perl implemented that even in 
mod_perl 1. With Apache 2.0, anyone can write output filters, 
thankfully. Implementing it as a filter rather than a handler would 
side-step the "only one handler" rule, which might help, particularly 
if you want it to apply to proxied content as well. (Probably everyone 
on this list is more qualified than I am to help you put together an 
output filter in mod_perl.)



On 6-Sep-04, at 5:31 PM, Ben Hopkins wrote:

> William McKee wrote:
>
>> On Sat, Sep 04, 2004 at 12:56:26PM -0700, Ben Hopkins wrote:
>>
>>> I got FORBIDDEN errors until I put my IP addr (I'm working on a 
>>> remote server).  Then I got 404s.
>>>
>>
>> The directives look similar to mine. Is there no message in the Apache
>> error logs that gives you a hint of what's wrong with your system?
>>
> Here's the error log entries:
> [Mon Sep  6 15:21:44 2004] [error] [client xx.xx.xx.xx] File does not 
> exist: /usr/local/apache/htdocs/server-status
> [Mon Sep  6 15:22:03 2004] [error] [client xx.xx.xx.xx] File does not 
> exist: /usr/local/apache/htdocs/server-info
>
> and the access log:
> xx.xx.xx.xx - - [06/Sep/2004:15:21:44 -0700] "GET /server-status 
> HTTP/1.1" 404 284
> xx.xx.xx.xx - - [06/Sep/2004:15:22:03 -0700] "GET /server-info 
> HTTP/1.1" 404 282
>
> Notice that the client IP is the same as the one allowed in the 
> httpd.conf snippet in the previous post.
>
> I thought I had it solved when I realized that the PerlHandler for 
> <Location /> was doing this:
>
> unless (-e $f->finfo) {
>    return NOT_FOUND
> }
>
> and I changed NOT_FOUND to DECLINED.
>
> But that didn't work.


-- 
Report problems: http://perl.apache.org/bugs/
Mail list info: http://perl.apache.org/maillist/modperl.html
List etiquette: http://perl.apache.org/maillist/email-etiquette.html


Mime
View raw message