Re: Inconsistency with dhandlers

David Wheeler <[email protected]>
Newsgroups gmane.comp.web.mason.devel
Message-ID <[email protected]>
Okay, here is my contribution to the FAQ to address this issue. Let me 
know if you need any more information.

Regards,

David

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

=question

I'm using HTML::Mason::ApacheHandler and I have C<decline_dirs> 
disabled and
am using a dhandler to handle directory requests. But when a request 
comes
in without the final slash after the directory name, relative links are
broken. What gives?

=answer

Normally, Apache directory requests are handled by C<mod_dir>. One of 
the
primary functions of this core Apache module is to check the requested 
URI,
and if it is for a directory and there is no slash after the directory 
name,
C<mod_dir> appends the slash and redirects the browser to the new URL. 
This
ensures that relative URLs always work correctly.

However, C<mod_perl>, when it is compiled into Apache, sets itself up 
to get
the first stab at handling the response phase of requests. This is 
normally
what you want, but the upshot is that, unless C<mod_perl> declines the
request, neither C<mod_dir> nor any other response phase module ever 
gets a
chance to run. So Mason handles the request, but unfortunately it does 
not
decline requests for a directory when the final slash is missing. This 
will
be fixed in Mason 1.3, but not before then, as doing so breaks 
compatibility
with the existing behavior.

But there are a few approaches to changing this behavior without too 
much
trouble:

=over 4

=item *

You can add these lines to the top of your dhandler to handle the 
redirect
yourself:

   <%init>;
   use Apache::Constants qw(DIR_MAGIC_TYPE DECLINED);
   $m->abort(DECLINED)
     if $r->content_type eq DIR_MAGIC_TYPE && $r->uri !~ m{/$};
   </%init>

Here Mason declines the request, and therefore so does C<mod_perl>. This
allows C<mod_dir> to handle the request, and C<mod_dir> will trigger the
appropriate redirection.

=item *

You can use David Wheeler's Apache::Dir module from CPAN to replicate 
the
directory redirection behavior of C<mod_dir> in C<mod_perl>. Using it is
simple; just add it as a fixup handler wherever you're using
HTML::Mason::ApacheHandler to handle directory requests:

   <Location /foo>
     PerlSetVar       MasonDeclineDirs 0
     PerlModule       Apache::Dir
     PerlModule       HTML::Mason::ApacheHandler
     SetHandler       perl-script
     PerlFixupHandler Apache::Dir
     PerlHandler      HTML::Mason::ApacheHandler
   </Location>

=item *

Recompile Apache to allow C<mod_dir> to handle requests before 
C<mod_perl>
does. This is simple to do thanks to Apache's C<--permute-module> 
configure
option. You can either give it the names of two modules to swap, e.g.:

    --permute-module=dir:perl

or you can use special names "BEGIN" and "END" to move a module to the
beginning or end of the list, which might be what you want for 
C<mod_dir>,
e.g.:

    --permute-module=dir:END

In this case, you might also need to change the value of the
C<DirectoryIndex> directive to F<dhandler> to prevent Apache from 
internally
redirecting to an existing F<index.html> file.

=item *

If you're running Apache 1.3, you can use the C<ClearModuleList> and
C<AddModule> directives to reorder the response phase handlers at server
startup time. The C<AddModule> directive can load either static or 
dynamic
modules; C<ClearModuleList> removes all loaded modules, so you'll need 
to
load them all again in the appropriate order; see the output of C<httpd 
-l>
for the complete list of loaded modules. The highest priority module 
loads
last, so you could do something like this:

   ClearModuleList
   AddModule mod_so.c
   AddModule mod_perl.c
   AddModule mod_dir.c

Here again, you might also need to change the value of the 
C<DirectoryIndex>
directive to F<dhandler> to prevent Apache from internally redirecting 
to an
existing F<index.html> file.

=back

=begin comment

It's unlikely that this problem doesn't exist in mod_perl 2, because 
unlike
in mod_perl 1, mod_perl 2 is not configured to handle C<DIR_MAGIC_TYPE>
requests. But since Mason likes to handle directory requests when
C<decline_dirs> is disabled, it seems likely that Mason will need to 
install
a fixup handler to set itself up to handle such requests. To do so,
HTML::Mason::ApacheHandler will need to call C<< $s->add_config >> to 
add a
PerlFixupHandler, which would likely look something like this:

  sub fixup_handler {
      my $r = shift;
      $r->handler('perl_script') # or $r->handler('modperl')
        if $r->content_type ne DIR_MAGIC_TYPE || $r->uri =~ m{/$};
      return HTTP_OK;
  }

So none of the above solutions should be necessary in mod_perl 2, but 
as of
this writing, I doubt that Mason handles directories with mod_perl 2 at 
all.

=end comment

=cut



-------------------------------------------------------
This SF.Net email is sponsored by: Oracle 10g
Get certified on the hottest thing ever to hit the market... Oracle 10g. 
Take an Oracle 10g class now, and we'll give you the exam FREE.
http://ads.osdn.com/?ad_id=3149&alloc_id=8166&op=click
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.