[mod_python] How do you specify the order in which mod_python Handlers are called?

Graham Dumpleton grahamd at dscpl.com.au
Sun Apr 10 03:18:00 EDT 2005


On 10/04/2005, at 12:57 PM, jarrod roberson wrote:

> I need to make sure multiple mod_python handlers are called in a 
> specific order.
> I also need to make sure they are before and/or after other "built in"
> handlers such as mod_dav.
>
> I am using Apache2 and mod_python 3.1.4, I can't find any examples or
> specific details on this, and as I am not an Apache2 expert ( yet )
> reading thru the apache docs is not going very fast.

In terms of specific order of processing, for any type of handler,
the documentation says:

   All request handler directives have the following syntax:

      Python*Handler handler [handler ...] [ | .ext [.ext ...] ]

   Where handler is a callable object that accepts a single argument -
   request object, and .ext is a file extension.

   Multiple handlers can be specified on a single line, in which case
   they will be called sequentially, from left to right. Same handler
   directives can be specified multiple times as well, with the same
   result - all handlers listed will be executed sequentially, from
   first to last. If any handler in the sequence returns a value
   other than apache.OK, then execution of all subsequent handlers
   is aborted.

For each request, there are also different phases of processing. Taken
from the documentation index, these are:

	▪ 	5.1.2 PythonPostReadRequestHandler
	▪ 	5.1.3 PythonTransHandler
	▪ 	5.1.4 PythonHeaderParserHandler
	▪ 	5.1.5 PythonInitHandler
	▪ 	5.1.6 PythonAccessHandler
	▪ 	5.1.7 PythonAuthenHandler
	▪ 	5.1.8 PythonAuthzHandler
	▪ 	5.1.9 PythonTypeHandler
	▪ 	5.1.10 PythonFixupHandler
	▪ 	5.1.11 PythonHandler
	▪ 	5.1.12 PythonLogHandler
	▪ 	5.1.13 PythonCleanupHandler

They are in general supposed to be executed in that order if they are
defined. Noting though that authenhandler and authzhandler are only
executed if there is also appropriate configuration information in the
Apache configuration file which triggers their use. Some of the earlier
phases are also only triggered in certain situations.

Now take as example a .htaccess file which contains:

   SetHandler mod_python

   PythonHeaderParserHandler mptest::headerparser
   PythonAccessHandler mptest::accesshandler
   PythonHandler mptest::handler
   PythonLogHandler mptest::loghandler
   PythonCleanupHandler mptest::cleanuphandler

and "mptest.py" contains:

   from mod_python import apache
   import time

   class _Handler:
     def __init__(self,phase,status=apache.OK,delay=0):
       self.__phase = phase
       self.__status = status
       self.__delay = delay
     def __call__(self,req):
       req.log_error("</%s>"%self.__phase)
       time.sleep(self.__delay)
       req.log_error("<%s>"%self.__phase)
       return self.__status

   postreadrequesthandler = _Handler("postreadrequesthandler")
   transhandler = _Handler("transhandler")
   headerparserhandler = _Handler("headerparserhandler")
   inithandler = _Handler("inithandler")
   accesshandler = _Handler("accesshandler")
   authenhandler = _Handler("authenhandler")
   authzhandler = _Handler("authzhandler")
   typehandler = _Handler("typehandler")
   fixuphandler = _Handler("fixuphandler")
   handler = _Handler("handler",status=apache.DECLINED)
   loghandler = _Handler("loghandler")
   cleanuphandler = _Handler("cleanup")

If I request a plain text file residing in that directory in the log
file I will see:

   [Sun Apr 10 02:56:46 2005] [notice] mod_python: (Re)importing module 
'mptest'
   [Sun Apr 10 02:56:46 2005] [error] [client 128.121.126.33] 
</accesshandler>
   [Sun Apr 10 02:56:46 2005] [error] [client 128.121.126.33] 
<accesshandler>
   [Sun Apr 10 02:56:46 2005] [error] [client 128.121.126.33] </handler>
   [Sun Apr 10 02:56:46 2005] [error] [client 128.121.126.33] <handler>
   [Sun Apr 10 02:56:46 2005] [error] [client 128.121.126.33] 
</loghandler>
   [Sun Apr 10 02:56:46 2005] [error] [client 128.121.126.33] 
<loghandler>
   [Sun Apr 10 02:56:47 2005] [error] [client 128.121.126.33] </cleanup>
   [Sun Apr 10 02:56:47 2005] [error] [client 128.121.126.33] <cleanup>

Note that because apache.DECLINED was returned from handler(), Apache 
will
fall back to using the "default-handler" and will serve up the raw 
contents
of the file.

Unfortunately, if the file requested was a ".php" file, the raw contents
of the file will be returned and not the processed output from running
the PHP module on the raw file.

What to do to still have the ".php" file processed but the other handler
phases still be executed by mod_python isn't obvious though. What you 
need
to know is that the "SetHandler" and "AddHandler" directives only apply 
to
the "PythonHandler" directive and not to all the others.

Thus, if the following .htaccess file is instead used:

   #SetHandler mod_python

   PythonHeaderParserHandler mptest::headerparser
   PythonAccessHandler mptest::accesshandler
   PythonHandler mptest::handler
   PythonLogHandler mptest::loghandler
   PythonCleanupHandler mptest::cleanuphandler

Ie., comment out the "SetHandler", then "PythonHandler" directive 
doesn't
get applied. Make a request against a ".php" file in the directory and 
one
sees in the log file:

   [Sun Apr 10 03:01:18 2005] [notice] mod_python: (Re)importing module 
'mptest'
   [Sun Apr 10 03:01:18 2005] [error] [client 128.121.126.33] 
</accesshandler>
   [Sun Apr 10 03:01:18 2005] [error] [client 128.121.126.33] 
<accesshandler>
   [Sun Apr 10 03:01:18 2005] [error] [client 128.121.126.33] 
</loghandler>
   [Sun Apr 10 03:01:18 2005] [error] [client 128.121.126.33] 
<loghandler>
   [Sun Apr 10 03:01:18 2005] [error] [client 128.121.126.33] </cleanup>
   [Sun Apr 10 03:01:18 2005] [error] [client 128.121.126.33] <cleanup>

Note that "handler()" isn't called, the others still are and I get my 
rendered
PHP output displayed in the browser.

Thus you can see that a non mod_python content handler can be mixed 
with other
handlers which do use mod_python. If you were to add time delays in the 
various
phases to slow things done, you would see that the "PHP" output will 
appear on
your browser at the point where "handler()" would otherwise be called. 
This
therefore indicates that the log handler and later phases only get 
executed
after the PHP module has been executed to return the page content.

In terms of mod_dav, as far as I can see, if you don't set AddHandler or
SetHandler directives, you should be able to define an access handler or
log handler etc and mod_dav will be called where the handler would 
otherwise.

One final thing to try with the above is set the .htaccess file to 
contain
only:

   PythonHandlerModule mptest

When I know request the ".php" file I see:

   [Sun Apr 10 03:08:47 2005] [notice] mod_python: (Re)importing module 
'mptest'
   [Sun Apr 10 03:08:47 2005] [error] [client 128.121.126.33] 
</headerparserhandler>
   [Sun Apr 10 03:08:47 2005] [error] [client 128.121.126.33] 
<headerparserhandler>
   [Sun Apr 10 03:08:47 2005] [error] [client 128.121.126.33] 
</accesshandler>
   [Sun Apr 10 03:08:47 2005] [error] [client 128.121.126.33] 
<accesshandler>
   [Sun Apr 10 03:08:47 2005] [error] [client 128.121.126.33] 
</loghandler>
   [Sun Apr 10 03:08:47 2005] [error] [client 128.121.126.33] 
<loghandler>
   [Sun Apr 10 03:08:47 2005] [error] [client 128.121.126.33] </cleanup>
   [Sun Apr 10 03:08:47 2005] [error] [client 128.121.126.33] <cleanup>

I don't quite understand why the header parser handler is executed when 
the
"PythonHandlerModule" directive is used, but not when 
"PythonHeaderParserHandler"
is used explicitly.

BTW, "PythonHandlerModule" is actually broken. It works here because a 
handler
for every phase is defined. According to the documentation it is meant 
to
ignore the fact that a handler for a phase isn't there and simply just 
call
those which are. It doesn't do this though and raises a 500 error. 
Problem is
logged as:

   http://issues.apache.org/jira/browse/MODPYTHON-46

I inadvertently fixed this in an older version of Vampire in an 
alternate
way I provided of defining non content handlers, but then I broke it 
again
in one of the more recent versions. Have fixed it again for next 
version. :-)

Anyway, the only thing I didn't explain here was when you have:

   PythonHandler a b c

or:

   PythonHandler a
   PythonHandler b
   PythonHandler c

I think the documentation I quote about this at the start was reasonably
clear on that one though.

Hope this explains things. If it doesn't, you should perhaps explain the
specific problem you are having.

Graham




More information about the Mod_python mailing list