You are viewing a plain text version of this content. The canonical link for it is here.
Posted to modperl@perl.apache.org by Torsten Foertsch <to...@gmx.net> on 2003/08/14 12:16:08 UTC

unsetting PerlTransHandler

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

I have a

<VirtualHost ...>

PerlTransHandler Handler

<Location ...>
</Location>

</VirtualHost>

and want to unset the TransHandler inside the <Location>.

How to do that?

Thanks
Torsten
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.7 (GNU/Linux)

iD8DBQE/O2FrwicyCTir8T4RAsXlAKCr0SfbKsG/9iNbv4pjxv1rOodV1wCggKOQ
zQ/hRg4aSVwUDr3brnJY+I8=
=oKyR
-----END PGP SIGNATURE-----

Re: unsetting PerlTransHandler

Posted by Torsten Foertsch <to...@gmx.net>.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On Thursday 14 August 2003 18:20, Geoffrey Young wrote:
> Frank Maas wrote:
> > Ehm... considering both solutions worked and the quoted paragraph,
> > shouldn't we read it as 'the results of this sequence can be used during
> > the translation phase, but are thrown away after the translation has
> > completed'. This would mean that the results are not discarded prior to
> > translation, but after translation and that would also explain why the
> > two solutions work...
>
> well, they can only be used during translation if the URI is unaltered. 
> for instance, given the example we've seen already
>
> PerlTransHandler MyPackage::transhandler
> <Location ...>
> PerlHandler MyPackage::handler
> </Location>
>
> checking get_handlers() in transhandler() only works because the initial
> merge (which is thrown away) ends up being the same merge as after
> translation.  if any (other) trans handlers meddle with $r->uri (which is
> perfectly valid) then the initial get_handlers() call will report settings
> completely different than the end <Location> that is finally applied to the
> URL.

well, if a transhandler alters the Uri than maybe MyPackage::handler will not 
be called at all, yes. But from the point of view at start of the request it 
would be called.

> so, I guess <Location>-specific settings can be used during translation,
> much in the same way that you can break encapsulation in Perl by simply
> accessing the object via its underlying hash - the "feature" works
> currently due to the way things are implemented, but using it is not
> guaranteed to work in the future (apache 2.0?), and may have unintended
> consequences in the present.  in other words, it's a bad idea and people
> who know better certainly don't rely on it.

I'm wondering then for what reason that initial merge is done at all if not to 
be used during name translation?

well, a translation handler cannot be sure that the $r->dir_config it gets was 
really caused by the $r->uri it sees. Further, other handlers in later phases 
can get completely different settings.

I've searched the standard modules for /r->uri\s*=/ and found only one 
occurence in mod_rewrite with the [PT] flag. I assume the right solution 
would be to do another merge based on the new uri if someone alters the uri 
during name translation and plans to return DECLINED.

And as for apache 2, there I have found these lines:

        if ((access_status = ap_location_walk(r))) {
            return access_status;
        }

        if ((access_status = ap_run_translate_name(r))) {
            return decl_die(access_status, "translate", r);
        }

Torsten
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.7 (GNU/Linux)

iD8DBQE/O+VtwicyCTir8T4RAiiEAJ4rtu6tMCVrkho5eP3L3+Yz8NGQ9QCguIUb
oxm9P4ttWWeO0g7/BRb4raQ=
=iiYV
-----END PGP SIGNATURE-----

Re: unsetting PerlTransHandler

Posted by Geoffrey Young <ge...@modperlcookbook.org>.

Frank Maas wrote:
> On Thu, Aug 14, 2003 at 11:07:13AM -0400, Geoffrey Young wrote:
> 
>>"There is actually a <Location>/<LocationMatch>  sequence performed just 
>>before the name translation phase (where Aliases and DocumentRoots  are 
>>used to map URLs to filenames). The results of this sequence are completely 
>>thrown away after the translation has completed."
>>
>>which is what you found in the code - note the "completely thrown away" 
>>part.  in essence, this means that the results of the <Location> config 
>>merging are discarded prior to translation, after which <Location> merging 
>>is done again.
> 
> 
> Ehm... considering both solutions worked and the quoted paragraph, 
> shouldn't we read it as 'the results of this sequence can be used during
> the translation phase, but are thrown away after the translation has
> completed'. This would mean that the results are not discarded prior to 
> translation, but after translation and that would also explain why the two 
> solutions work...

well, they can only be used during translation if the URI is unaltered.  for 
instance, given the example we've seen already

PerlTransHandler MyPackage::transhandler
<Location ...>
PerlHandler MyPackage::handler
</Location>

checking get_handlers() in transhandler() only works because the initial 
merge (which is thrown away) ends up being the same merge as after 
translation.  if any (other) trans handlers meddle with $r->uri (which is 
perfectly valid) then the initial get_handlers() call will report settings 
completely different than the end <Location> that is finally applied to the 
URL.

so, I guess <Location>-specific settings can be used during translation, 
much in the same way that you can break encapsulation in Perl by simply 
accessing the object via its underlying hash - the "feature" works currently 
due to the way things are implemented, but using it is not guaranteed to 
work in the future (apache 2.0?), and may have unintended consequences in 
the present.  in other words, it's a bad idea and people who know better 
certainly don't rely on it.

--Geoff


Re: unsetting PerlTransHandler

Posted by Frank Maas <fr...@cheiron-it.nl>.
On Thu, Aug 14, 2003 at 11:07:13AM -0400, Geoffrey Young wrote:
> 
> "There is actually a <Location>/<LocationMatch>  sequence performed just 
> before the name translation phase (where Aliases and DocumentRoots  are 
> used to map URLs to filenames). The results of this sequence are completely 
> thrown away after the translation has completed."
> 
> which is what you found in the code - note the "completely thrown away" 
> part.  in essence, this means that the results of the <Location> config 
> merging are discarded prior to translation, after which <Location> merging 
> is done again.

Ehm... considering both solutions worked and the quoted paragraph, 
shouldn't we read it as 'the results of this sequence can be used during
the translation phase, but are thrown away after the translation has
completed'. This would mean that the results are not discarded prior to 
translation, but after translation and that would also explain why the two 
solutions work...

--Frank

Re: unsetting PerlTransHandler

Posted by Geoffrey Young <ge...@modperlcookbook.org>.
> I understand translation handlers cannot be <Directory>-specific. But 
> <Location> directives apply before any translation handler is called (see 
> below). 

yes they do, but not really.  to really understand this, see

http://httpd.apache.org/docs/sections.html

specifically,

"There is actually a <Location>/<LocationMatch>  sequence performed just 
before the name translation phase (where Aliases and DocumentRoots  are used 
to map URLs to filenames). The results of this sequence are completely 
thrown away after the translation has completed."

which is what you found in the code - note the "completely thrown away" 
part.  in essence, this means that the results of the <Location> config 
merging are discarded prior to translation, after which <Location> merging 
is done again.

regardless, officially apache translation (which includes the 
PerlTransHandler) cannot be <Location> specific - directives must appear 
outside of <Directory>, <Location>, and <Files> (and their regex 
counterparts).  if you look at other modules that implement translation 
handlers (mod_rewrite, for instance), you'll see that their translation 
directives all have RSRC_CONF prototypes, which prohibits their placement 
inside of these containers.

--Geoff


Re: unsetting PerlTransHandler

Posted by Torsten Foertsch <to...@gmx.net>.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On Thursday 14 August 2003 14:49, Geoffrey Young wrote:
> trans handlers are used to map the URI to a filename, the result of which
> lets Apache know to which <Directory> the URI belongs to.  it can also
> affect which <Location> the URI belongs to if that <Location> is paired
> with an Alias directive.   trying to make a trans handler <Location>
> specific doesn't really make sense - if you are already in a <Location>
> section then you should already know which file (or lack thereof) you want
> to serve. that's just how Apache works.

Thanks for the explanation. But...

I understand translation handlers cannot be <Directory>-specific. But 
<Location> directives apply before any translation handler is called (see 
below). Even more I found a note in Apache docs on mod_alias:

"Aliasing occurs before <Directory> sections are checked, so only the 
destination of aliases are affected. (Note however <Location>  sections are 
run through once before aliases are performed, so they will apply.)"

I admit there can be confusion if a translation handler changes r->uri since 
<Location> directives are applied again after <Directory> and <File> sections 
after the translation handler has returned. But mod_alias doesn't do that. It 
sets r->filename and returns OK (and finishs the translation phase).

> > return DECLINED
> >   if(grep {$_ eq __PACKAGE__.'::handler'}
> > @{$r->get_handlers('PerlHandler')}); ...
> > }
>
> I don't think that will work the way you desire - the PerlHandler directive
> should not be merged into the current configuration for the request until
> after the trans handler runs, so I wouldn't expect it to be present in
> get_handlers() yet.

But it actually does work, as does Frank's variant (PerlSetVar 
SkipTransHandler 1). I've read a little source 
(apache_1.3.26/src/main/http_request.c: process_request_internal()):

    if ((access_status = location_walk(r))) {
        ap_die(access_status, r);
        return;
    }

    if ((access_status = ap_translate_name(r))) {
        decl_die(access_status, "translate", r);
        return;
    }

...

    /*
     * NB: directory_walk() clears the per_dir_config, so we don't inherit
     * from location_walk() above
     */

    if ((access_status = directory_walk(r))) {
        ap_die(access_status, r);
        return;
    }

    if ((access_status = file_walk(r))) {
        ap_die(access_status, r);
        return;
    }

    if ((access_status = location_walk(r))) {
        ap_die(access_status, r);
        return;
    }

as I understand location_walk() applies <Location> sections. It is called just 
before the translation handlers (ap_translate_name()). Later on they are 
applied again because directory_walk() clears that data. That means it can 
lead to confusion if a translation handler changes r->uri a different 
<Location> section gets applied.

BTW, the same steps are also performed for subrequests.

Torsten
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.7 (GNU/Linux)

iD8DBQE/O51+wicyCTir8T4RAnJmAJ96c1oepdttLD/NsD0RVIfblXfT3ACfepf9
l6APcLfK6u/Mp3un7t5GYYg=
=akE9
-----END PGP SIGNATURE-----

Re: unsetting PerlTransHandler

Posted by Geoffrey Young <ge...@modperlcookbook.org>.
> Yes, I've implemented it also that way. But I thought <Location> acts on the 
> URI and in principle there can be a <Location>-specific transhandler. I'm 
> wondering why it is impossible?

trans handlers are used to map the URI to a filename, the result of which 
lets Apache know to which <Directory> the URI belongs to.  it can also 
affect which <Location> the URI belongs to if that <Location> is paired with 
an Alias directive.   trying to make a trans handler <Location> specific 
doesn't really make sense - if you are already in a <Location> section then 
you should already know which file (or lack thereof) you want to serve. 
that's just how Apache works.

> 
> For now I have implemented that particular case by
> 
> PerlTransHandler MyPackage::transhandler
> <Location ...>
> PerlHandler MyPackage::handler
> </Location>
> 
> package MyPackage;
> 
> sub transhandler {
> ... 
> return DECLINED
>   if(grep {$_ eq __PACKAGE__.'::handler'} @{$r->get_handlers('PerlHandler')});
> ...
> }
> 
> i.e. if my handler is installed return DECLINED.

I don't think that will work the way you desire - the PerlHandler directive 
should not be merged into the current configuration for the request until 
after the trans handler runs, so I wouldn't expect it to be present in 
get_handlers() yet.

a better way is probably to let your PerlTransHandler run always.  then, for 
requests to <Location> use a PerlHeaderParserHandler to unset $r->filename.

HTH

--Geoff



Re: unsetting PerlTransHandler

Posted by Torsten Foertsch <to...@gmx.net>.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On Thursday 14 August 2003 13:48, Frank Maas wrote:
> |<Location ...>
> |  PerlSetVar SkipTransHandler 1
> |</Location>

I don't want to make it configurable.

Torsten
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.7 (GNU/Linux)

iD8DBQE/O54ywicyCTir8T4RAss0AJ4rNMkqyKC0Tlh8tPZF5XbGc4GSeQCgjwto
CvsUie4PVYy1QQ/MfsywCtI=
=npMM
-----END PGP SIGNATURE-----

RE: unsetting PerlTransHandler

Posted by Frank Maas <fr...@cheiron-it.nl>.
> I'm wondering why it is impossible?

I am not exactly sure here, but I think this is because a TransHandler
is definitely not allowed inside a <Directory> or <File> container. And
since Apache does not make the distinction between containers (it uses
the constant RSRC_CONF to disallow a directive from being in (all) 
containers) <Location> is the innocent victim here.

> For now I have implemented that particular case by

Wouldn't this be simpler?

|PerlTransHandler MyPackage::transhandler
|<Location ...>
|  PerlSetVar SkipTransHandler 1
|</Location>
|
|package MyPackage;
|
|sub transhandler {
|...
|return DECLINED if $r->dir_config('SkipTransHandler');
|...
|}

--Frank

Re: unsetting PerlTransHandler

Posted by Torsten Foertsch <to...@gmx.net>.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On Thursday 14 August 2003 12:34, Frank Maas wrote:
> > and want to unset the TransHandler inside the <Location>.
> > How to do that?
>
> AFAIK: not. The TransHandler is the first to be called and cannot appear
> inside a container (ref. ModPerl cookbook). The only thing I can think of,
> and in fact implemented this, to make the TransHandler URI-aware and
> return immediately if the uri is something you do not want to be touched
> by the TransHandler.

Yes, I've implemented it also that way. But I thought <Location> acts on the 
URI and in principle there can be a <Location>-specific transhandler. I'm 
wondering why it is impossible?

For now I have implemented that particular case by

PerlTransHandler MyPackage::transhandler
<Location ...>
PerlHandler MyPackage::handler
</Location>

package MyPackage;

sub transhandler {
... 
return DECLINED
  if(grep {$_ eq __PACKAGE__.'::handler'} @{$r->get_handlers('PerlHandler')});
...
}

i.e. if my handler is installed return DECLINED.

Torsten
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.7 (GNU/Linux)

iD8DBQE/O2e0wicyCTir8T4RAjpXAKC8qRHIrQXxIA3O1RP3BnC40LcVqgCgy+eS
c+edNr0sMUM+tq0jmICq39Q=
=PnAk
-----END PGP SIGNATURE-----

RE: unsetting PerlTransHandler

Posted by Frank Maas <fr...@cheiron-it.nl>.
> and want to unset the TransHandler inside the <Location>.
> How to do that?

AFAIK: not. The TransHandler is the first to be called and cannot appear
inside a container (ref. ModPerl cookbook). The only thing I can think of,
and in fact implemented this, to make the TransHandler URI-aware and 
return immediately if the uri is something you do not want to be touched
by the TransHandler.

Hope this helps

--Frank