You are viewing a plain text version of this content. The canonical link for it is here.
Posted to modperl@perl.apache.org by Steve Hay <st...@uk.radan.com> on 2003/09/08 17:51:55 UTC

Help wanted with locations / configuration

Hi,

I'm having trouble deciding what the best plan is for the arrangement of 
the components of a new project that I'm starting.

The project is going to be written as a series of mod_perl handlers - 
one for the main "home page", and others for various sub-components.  
Each handler is implemented by a separate module (all sub-classes of a 
common base class).  I don't want to have to configure a separate 
Location for each sub-component.

It also needs to have access to various static resources (images, 
stylesheets, JavaScript libraries etc.).

Thus, I want to have something like this:

/myproject                 [mp1]
/myproject/component1   [mp1]
/myproject/component2   [mp1]
...
/myproject/images       [static]
/myproject/javascript   [static]
/myproject/stylesheets  [static]

The question is: What is the best way to configure this?

So far I've come up with two options:

OPTION 1. Specify a /myproject Location with "dispatcher" method as the 
mod_perl handler; then specify a LocationMatch for the images, 
javascript and stylesheets that overrides the /myproject Location:

<Location /myproject>
    SetHandler perl-script
    PerlHandler MyProject->dispatcher
</Location>

<LocationMatch "^/myproject/(images|javascript|stylesheets)">
    SetHandler default-handler
</LocationMatch>

The "dispatcher" method there looks at the URI requested and either 
returns DECLINED (or 404?) if it doesn't recognise it, or else loads the 
appropriate MyProject sub-class and then runs the real content 
generation routine in that (i.e. a routine like I would have specified 
as the handler for that URI if I had configured a separate Location for 
each component).

This seems to have a minor problem in practice -- if I request a 
directory, rather than a file, in one of the "static" locations (e.g. 
"/myproject/images" or "/myproject/images/") then the dispatcher method 
gets called!  The LocationMatch override only seems to work if I request 
a file (e.g. "/myproject/images/piccy1.jpg").  Thus, I need to put some 
extra code into the dispatcher to repeat the pattern match for the 
"static" locations, and change the handler to the default-handler and 
return DECLINED if it has received such a URI.

OPTION 2. Specify a /myproject Location with a PerlFixupHandler that 
behaves very much like the dispatcher above, except that it actually 
sets the handler to PerlHandler and assigns the appropriate callback 
method (i.e. the content generation routine in the component sub-class) 
when it spots a recognised component URI; otherwise it just returns 
DECLINED, leaving the request to be handled by the default-handler:

<Location /myproject>
    PerlFixupHandler MyProject->fixup
</Location>

(Am I correct in thinking that I don't need to specify "SetHandler: 
perl-script" for a PerlFixupHandler?  That's only for the main 
PerlHandler response handler, isn't it?)

Does either of these options have any benefit over the other?  Are there 
other better ways to do it?

Thanks in advance,
- Steve


Re: Help wanted with locations / configuration

Posted by petersm <pe...@venzia.com>.
Steve Hay <st...@uk.radan.com> wrote
> 
> Thanks for the idea, though.  If I manage to overcome my 
> inexplicable aversion to file extensions then it certainly looks 
> like the simplest solution.

I understand the argument that it's better for the user to not know the
extension of the file they are running.... but, if it really bothers you then
you could do something like

<Location /myproject>
    AddHandler perl-script .steve
</Location>

and then put a '.steve' extension onto your scripts and that way it's a little
more personalized... :)

Michael Peters
Venzia


Re: Help wanted with locations / configuration

Posted by Steve Hay <st...@uk.radan.com>.
petersm wrote:

>Steve Hay <st...@uk.radan.com> wrote
>  
>
>><Location /myproject>
>>    SetHandler perl-script
>>    PerlHandler MyProject->dispatcher
>></Location>
>>
>><LocationMatch "^/myproject/(images|javascript|stylesheets)">
>>    SetHandler default-handler
>></LocationMatch>
>>    
>>
>
>Correct me if I'm wrong, but can't you just say> <Location /myproject>
>
> <Location /myproject>
>     AddHandler perl-script .cgi
>     PerlHandler MyProject->dispatcher
> </Location>
>
>using AddHandler instead of SetHandler. This will not override the default
>handler for things like images/stylesheets/static html. This way you don't
>need the  <LocationMatch "^/myproject/(images|javascript|stylesheets)"> ... tags.
>  
>
I prefer for reasons that I can't really explain to have the Perl 
handler locations having no extension - e.g. things like 
"/myproject/component1" rather than "/myproject/component1.cgi".

I can't see how to achieve that with an AddHandler.  (And even if I did 
get that working somehow, then the Perl handler would have to hand 
control back to the Apache core when it receives a request for 
"/myproject/images".)

Thanks for the idea, though.  If I manage to overcome my inexplicable 
aversion to file extensions then it certainly looks like the simplest 
solution.

- Steve


Re: Help wanted with locations / configuration

Posted by petersm <pe...@venzia.com>.
Steve Hay <st...@uk.radan.com> wrote
> It also needs to have access to various static resources (images, 
> stylesheets, JavaScript libraries etc.).
> 
> Thus, I want to have something like this:
> 
> /myproject                 [mp1]
> /myproject/component1   [mp1]
> /myproject/component2   [mp1]
> ...
> /myproject/images       [static]
> /myproject/javascript   [static]
> /myproject/stylesheets  [static]
> <Location /myproject>
>     SetHandler perl-script
>     PerlHandler MyProject->dispatcher
> </Location>
> 
> <LocationMatch "^/myproject/(images|javascript|stylesheets)">
>     SetHandler default-handler
> </LocationMatch>

Correct me if I'm wrong, but can't you just say> <Location /myproject>

 <Location /myproject>
     AddHandler perl-script .cgi
     PerlHandler MyProject->dispatcher
 </Location>

using AddHandler instead of SetHandler. This will not override the default
handler for things like images/stylesheets/static html. This way you don't
need the  <LocationMatch "^/myproject/(images|javascript|stylesheets)"> ... tags.

Michael Peters 
Venzia

Re: Help wanted with locations / configuration

Posted by Xavier Noria <fx...@hashref.com>.
On Tuesday 09 September 2003 11:16, Steve Hay wrote:

> Those were actually my very frist ideas, but I decided that I prefer
> to have all the URL's to begin with /myproject.  I don't necessarily
> require that URL to be related to the filesystem structure, but I
> just want all the URL's (dynamic and static) to begin the same.

I have achieved that using the configuration Perrin suggested. The prefix
(/myproject) is a parameter of the configuration of the application called
"apache_location_root", and the config script fills a mod_perl.conf.tt2
like this:

Alias [% apache_location_root %]/views   [% prj_root %]/www/htdocs/views
Alias [% apache_location_root %]/images  [% prj_root %]/www/htdocs/images
Alias [% apache_location_root %]/scripts [% prj_root %]/www/htdocs/scripts
Alias [% apache_location_root %]/styles  [% prj_root %]/www/htdocs/styles

<Location [% apache_location_root %]>
   # Nothing to do with the filesystem, just handlers available in @INC.
</Location>

In our case the motivation for that is that we don't know whether our
application will run in its own Apache server, so you can hard-code that
stuff, or will need to be added to an already functioning Apache.

-- fxn


Re: Help wanted with locations / configuration

Posted by Steve Hay <st...@uk.radan.com>.
Perrin Harkins wrote:

>On Mon, 2003-09-08 at 11:51, Steve Hay wrote:
>  
>
>>Thus, I want to have something like this:
>>
>>/myproject                 [mp1]
>>/myproject/component1   [mp1]
>>/myproject/component2   [mp1]
>>...
>>/myproject/images       [static]
>>/myproject/javascript   [static]
>>/myproject/stylesheets  [static]
>>
>>The question is: What is the best way to configure this?
>>    
>>
>
>Others have already given good advice,
>
They have, indeed.  Thanks, everyone!

>but I would add that your URLs
>and your filesystem don't need to be tied tightly together.  You could
>just alias the static files to somewhere else:
>
>[snip]
>
>Alternatively, you could use a Location setting for your dispatcher that
>has nothing to do with your files:
>  
>
Those were actually my very frist ideas, but I decided that I prefer to 
have all the URL's to begin with /myproject.  I don't necessarily 
require that URL to be related to the filesystem structure, but I just 
want all the URL's (dynamic and static) to begin the same.

- Steve


Re: Help wanted with locations / configuration

Posted by Perrin Harkins <pe...@elem.com>.
On Mon, 2003-09-08 at 11:51, Steve Hay wrote:
> Thus, I want to have something like this:
> 
> /myproject                 [mp1]
> /myproject/component1   [mp1]
> /myproject/component2   [mp1]
> ...
> /myproject/images       [static]
> /myproject/javascript   [static]
> /myproject/stylesheets  [static]
> 
> The question is: What is the best way to configure this?

Others have already given good advice, but I would add that your URLs
and your filesystem don't need to be tied tightly together.  You could
just alias the static files to somewhere else:

Alias /static/images /myproject/images

Then you can simply refer to them in URLs as /static/images/foo.jpg.

Alternatively, you could use a Location setting for your dispatcher that
has nothing to do with your files:

<Location /wild/and/crazy/path/for/handlers>
   SetHandler perl-script
   PerlHandler MyProject->dispatcher
</Location>

Then you can call /wild/and/crazy/path/for/handlers/component1 and it
will work as long as your dispatcher is smart enough to ignore the
beginning path.  (Apache::Dispatch is.)

- Perrin

Re: Help wanted with locations / configuration

Posted by Thomas Klausner <do...@zsi.at>.
Hi!

On Tue, Sep 09, 2003 at 10:05:43AM +0100, Steve Hay wrote:

> ><Location /myproject/css>
> >  SetHandler default
> ></Location>
> ><Location /myproject/img>
> >  SetHandler default
> ></Location>
> >
> >This is working as expected, i.e. request for /css/foo.css or /img/bar.png
> >are not handled by Apache::Dispatch
> > 
> >
> What about requests for /css or /img ?  Are they handled by 
> Apache::Dispatch?  The problem I found with my LocationMatch override is 
> that requests for files were caught, but requests for directories 
> slipped through to the Perl handler.

Unfourtunatly, request for /css are handled by Apache::Dispatch. At least it
seems so, but I'm enterly sure if it's the actual request that's beeing
served, or an internal redirect (or some other funky Apache internal thing,
like ErrorDocument or index generation)

It does seem like a feature/problem of Apache. I tried various config
options (and modifications to Apache::Dispatch), but no matter what I did,
request for /img/ allways get passed to PerHandler instead of default
handler

Request for anything inside /img/ work as expected.

No, wait a minute...

If I request /foo/bar/ (another dir) than it doesn't work either.

I still do not know if this a bug in
Apache / mod_perl / Apache::Dispatch / YourHandler, and/or internal redirect.
Or if this is expected behaviour.

-- 
#!/usr/bin/perl                               http://domm.zsi.at
for(ref bless{},just'another'perl'hacker){s-:+-$"-g&&print$_.$/}

Re: Help wanted with locations / configuration

Posted by Steve Hay <st...@uk.radan.com>.
Steve Hay wrote:

> Thomas Klausner wrote:
>
>> Hi!
>>
>> On Mon, Sep 08, 2003 at 04:51:55PM +0100, Steve Hay wrote:
>>
>>  
>>
>>> The project is going to be written as a series of mod_perl handlers 
>>> - one for the main "home page", and others for various 
>>> sub-components.  Each handler is implemented by a separate module 
>>> (all sub-classes of a common base class).  I don't want to have to 
>>> configure a separate Location for each sub-component.
>>>   
>>
>>
>> You might want to take a look at Apache::Dispatch, which does exactly 
>> this.
>>
> Will do!  I've grabbed it off CPAN and will take a good look at it.  
> It does indeed look like exactly what I'm after. 

Does anybody have Apache::Dispatch working on Windows?

I'm trying to build it on Windows XP (MSVC++ 6) with Perl 5.8.0 / Apache 
1.3.27 / mod_perl 1.28, but I get these errors:

[...]
        link -out:blib\arch\auto\Apache\Dispatch\Dispatch.dll -dll 
-nologo -node
faultlib -release  -libpath:"C:\perl5\lib\CORE"  -machine:x86 
Dispatch.obj   C:\
perl5\lib\CORE\perl58.lib libeay32.lib  oldnames.lib kernel32.lib 
user32.lib gdi
32.lib winspool.lib  comdlg32.lib advapi32.lib shell32.lib ole32.lib 
oleaut32.li
b  netapi32.lib uuid.lib wsock32.lib mpr.lib winmm.lib  version.lib 
odbc32.lib o
dbccp32.lib msvcrt.lib -def:Dispatch.def
   Creating library blib\arch\auto\Apache\Dispatch\Dispatch.lib and 
object blib\
arch\auto\Apache\Dispatch\Dispatch.exp
Dispatch.obj : error LNK2001: unresolved external symbol 
_perl_perl_merge_dir_co
nfig
Dispatch.obj : error LNK2001: unresolved external symbol 
_perl_cmd_perl_TAKE1
Dispatch.obj : error LNK2001: unresolved external symbol 
__imp__ap_register_clea
nup@16
Dispatch.obj : error LNK2001: unresolved external symbol 
_perl_perl_cmd_cleanup
Dispatch.obj : error LNK2001: unresolved external symbol 
__imp__ap_null_cleanup
Dispatch.obj : error LNK2001: unresolved external symbol __imp__ap_palloc@8
Dispatch.obj : error LNK2001: unresolved external symbol _perl_clear_symtab
Dispatch.obj : error LNK2001: unresolved external symbol 
__imp__ap_remove_module
@4
Dispatch.obj : error LNK2001: unresolved external symbol 
__imp__ap_find_linked_m
odule@4
Dispatch.obj : error LNK2001: unresolved external symbol 
_perl_get_startup_pool
Dispatch.obj : error LNK2001: unresolved external symbol 
__imp__ap_add_module@4
blib\arch\auto\Apache\Dispatch\Dispatch.dll : fatal error LNK1120: 11 
unresolved
 externals
NMAKE : fatal error U1077: 'link' : return code '0x460'
Stop.

Any ideas?

- Steve


Re: Help wanted with locations / configuration

Posted by Steve Hay <st...@uk.radan.com>.
Thomas Klausner wrote:

>Hi!
>
>On Mon, Sep 08, 2003 at 04:51:55PM +0100, Steve Hay wrote:
>
>  
>
>>The project is going to be written as a series of mod_perl handlers - 
>>one for the main "home page", and others for various sub-components.  
>>Each handler is implemented by a separate module (all sub-classes of a 
>>common base class).  I don't want to have to configure a separate 
>>Location for each sub-component.
>>    
>>
>
>You might want to take a look at Apache::Dispatch, which does exactly this.
>
Will do!  I've grabbed it off CPAN and will take a good look at it.  It 
does indeed look like exactly what I'm after.

>I'm using something like this with Apache::Dispatch
>
>PerlModule Apache::Dispatch
>DispatchUpperCase On	   # this is /not/ in Apache::Dispatch, 
>                           # only in my patched version
>DispatchPrefix Oe1
>DispatchExtras Error
>
><Location /myproject>
>   SetHandler perl-script
>   PerlHandler Apache::Dispatch
></Location>
>			   
><Location /myproject/css>
>   SetHandler default
></Location>
><Location /myproject/img>
>   SetHandler default
></Location>
>
>This is working as expected, i.e. request for /css/foo.css or /img/bar.png
>are not handled by Apache::Dispatch
>  
>
What about requests for /css or /img ?  Are they handled by 
Apache::Dispatch?  The problem I found with my LocationMatch override is 
that requests for files were caught, but requests for directories 
slipped through to the Perl handler.

- Steve


Re: Help wanted with locations / configuration

Posted by Thomas Klausner <do...@zsi.at>.
Hi!

On Mon, Sep 08, 2003 at 04:51:55PM +0100, Steve Hay wrote:

> The project is going to be written as a series of mod_perl handlers - 
> one for the main "home page", and others for various sub-components.  
> Each handler is implemented by a separate module (all sub-classes of a 
> common base class).  I don't want to have to configure a separate 
> Location for each sub-component.

You might want to take a look at Apache::Dispatch, which does exactly this.

> <Location /myproject>
>    SetHandler perl-script
>    PerlHandler MyProject->dispatcher
> </Location>
> 
> <LocationMatch "^/myproject/(images|javascript|stylesheets)">
>    SetHandler default-handler
> </LocationMatch>

I'm using something like this with Apache::Dispatch

PerlModule Apache::Dispatch
DispatchUpperCase On	   # this is /not/ in Apache::Dispatch, 
                           # only in my patched version
DispatchPrefix Oe1
DispatchExtras Error

<Location /myproject>
   SetHandler perl-script
   PerlHandler Apache::Dispatch
</Location>
			   
<Location /myproject/css>
   SetHandler default
</Location>
<Location /myproject/img>
   SetHandler default
</Location>

This is working as expected, i.e. request for /css/foo.css or /img/bar.png
are not handled by Apache::Dispatch



-- 
#!/usr/bin/perl                               http://domm.zsi.at
for(ref bless{},just'another'perl'hacker){s-:+-$"-g&&print$_.$/}

Re: Help wanted with locations / configuration

Posted by Marc Slagle <ma...@whapps.com>.
On Tue, 2003-09-09 at 05:00, Steve Hay wrote:
> As in a PerlTransHandler, yes?

Yup.

> Is there a performance penalty with this?  You're using Perl code to 
> inspect the URI, and then handing control back to the Apache core if it 
> is a static file.  I wanted to avoid requests for static files wasting 
> time by going to a Perl handler only to be returned to the Apache core 
> to serve the file, hence my LocationMatch override that catches requests 
> for static files.

Static File:

Devel::Timer Report -- Total time: 0.0006 secs
Interval  Time    Percent
----------------------------------------------
00 -> 01  0.0003  48.49%  INIT -> Entering translation handler
01 -> 02  0.0002  36.91%  Entering translation handler -> Checking to
see if we are asking for a static file
02 -> 03  0.0001  14.60%  Checking to see if we are asking for a static
file -> This is a request for a static file, telling apache where it is

Request we want to pass on to our handler:

Devel::Timer Report -- Total time: 0.0005 secs
Interval  Time    Percent
----------------------------------------------
01 -> 02  0.0002  40.90%  Entering translation handler -> Checking to
see if we are asking for a static file
00 -> 01  0.0001  31.48%  INIT -> Entering translation handler
02 -> 03  0.0001  27.62%  Checking to see if we are asking for a static
file -> This is not a request for a static file, returning DENIED


We decided to do it this way because we are also doing some other things
in the translation handler that I didn't pass along in the snippet.
Since we were already putting a translation handler in place to do our
trickery there, it seemed to make the most sense to us to add the code
to handle static requests there.  By no means am I suggesting that this
is the "best" way, but we're pretty happy with it.

Marc Slagle


Re: Help wanted with locations / configuration

Posted by Steve Hay <st...@uk.radan.com>.
Marc Slagle wrote:

>On Mon, 2003-09-08 at 11:51, Steve Hay wrote:
>  
>
>>It also needs to have access to various static resources (images, 
>>stylesheets, JavaScript libraries etc.).
>>
>>Thus, I want to have something like this:
>>
>>/myproject                 [mp1]
>>/myproject/component1   [mp1]
>>/myproject/component2   [mp1]
>>...
>>/myproject/images       [static]
>>/myproject/javascript   [static]
>>/myproject/stylesheets  [static]
>>    
>>
>
>You might want to look at having a translation handler.
>
As in a PerlTransHandler, yes?

>
>We're doing something similar to this, where images and javascripts live
>under the same directory structure as the handler is managing.  Instead
>of trying to configure this via that httpd.conf file, we chose to have a
>translation handler look at the incoming uri and determine whether the
>request is for a static file or for the code.
>
Is there a performance penalty with this?  You're using Perl code to 
inspect the URI, and then handing control back to the Apache core if it 
is a static file.  I wanted to avoid requests for static files wasting 
time by going to a Perl handler only to be returned to the Apache core 
to serve the file, hence my LocationMatch override that catches requests 
for static files.

Thanks for the code snippet, though - it looks pretty good to me aside 
from that concern.

- Steve


Re: Help wanted with locations / configuration

Posted by Marc Slagle <ma...@whapps.com>.
On Mon, 2003-09-08 at 11:51, Steve Hay wrote:
> 
> It also needs to have access to various static resources (images, 
> stylesheets, JavaScript libraries etc.).
> 
> Thus, I want to have something like this:
> 
> /myproject                 [mp1]
> /myproject/component1   [mp1]
> /myproject/component2   [mp1]
> ...
> /myproject/images       [static]
> /myproject/javascript   [static]
> /myproject/stylesheets  [static]

You might want to look at having a translation handler.

We're doing something similar to this, where images and javascripts live
under the same directory structure as the handler is managing.  Instead
of trying to configure this via that httpd.conf file, we chose to have a
translation handler look at the incoming uri and determine whether the
request is for a static file or for the code.

Inside of our transhandler we're doing this:

sub handler
{
        my $r=shift;
        my $uri=$r->uri;
        my $Tmplpath="/our/static/files/rootdir/";

        if (($uri !~ /jpg$/) && ($uri !~ /css$/) && ($uri !~ /js$/))
        {
                $r->notes('host' => "$Host");
                $r->notes('olduri' => "$uri");
                $r->uri("/");
                return DECLINED;
        }
        else
        {
                my $File=$Tmplpath . $uri;
                $r->filename("$File");
                return OK;
        }
}

If a request is made for anything ending in .jpg, .js or .css, we tell
apache where to find the file by appending the uri (/images/the.jpg for
example) to a path.  The handler then returns OK, which tells apache not
to try to figure out where the file lives on its own, and returns the
file to the browser.

Any other request is passed to the handler, along with a field in
notes() that shows what we were asking for in the first place.  Our
request handler uses this to dispatch the request to the correct object
needed to fulfill the request.  (Our handler is configured at /, so we
override the uri passed from the browser to /).

Any other types you want can be added to this, I just threw the ones
that seemed relevant to you.  I hope this helps.

Marc Slagle
Whapps LLC