quetz-mod_python-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Graham Dumpleton <grah...@dscpl.com.au>
Subject Proposal for new handler to be added to mod_python 3.3.
Date Sun, 19 Nov 2006 11:37:40 GMT
I know that we are very close to getting mod_python 3.3 out the door,
and I know that it is me holding it up purely through the documentation
not yet being updated to at least give some basic details on new bits
in the rewritten module importer, but even at this late stage I have  
been
thinking if we aren't with 3.3 missing a great opportunity to add a new
basic mod_python dispatch handler. After all, it may well be some time
before we get around to releasing the next version.

On that basis, I have quickly thrown together a new dispatch handler
which I think could be included with mod_python. After seeing so many
people going off and writing their own dispatchers with varied success I
could see that including this would save a lot of mucking around for
people.

I have attached the actual code for the handler module, but I'll explain
a few things about it as well.

First off, intended that this would exist as 'mod_python.dispatcher'. In
the simplest case, if you wanted to put all requests which fall within a
directory through it, you would use:

   SetHandler mod_python
   PythonHandler mod_python.dispatcher

The basic premise of the dispatcher is then that it will attempt to  
match
any request against a resource against a handler found in a .py file
corresponding to that specific resource.

Thus, if a request is made against '/index', the dispatcher would  
look for
a .py file called 'index.py' in that directory and execute the  
'handler()'
function within it. If the request was made against '/index.html', the
dispatcher would instead try and execute the 'handler_html()' function.

   from mod_python import apache

   def handler_html(req):
     req.content_type = 'text/html'
     req.write('<html><body><p>index</p></body></html>')
     return apache.OK

So, an important aspect of the dispatcher is that it doesn't just  
push all
requests for a resource through the one handler function. Instead, it  
will
call different handlers within the one resource code file for the  
different
extensions.

The benefit of this is that it becomes really easy to control what  
extension
you want a resource accessed under. Further, it is easy to provide  
different
views of a resource where the format of the result is different based on
the extension.

   def handler_csv(req):
     ...

   def handler_xml(req):
     ...

Because of the way that Apache matches files, this will all work  
within any
subdirectories as well. Thus if the request is against '/subdir/ 
index.html',
the dispatcher will try and execute 'handler_html()' in 'subdir/ 
index.py'.

If the directory is shared with static files which one wants to be  
served
up as is, one can use the Files directive to indicate which files  
should be
still served up as static files and not processed by mod_python.

   SetHandler mod_python
   PythonHandler mod_python.dispatcher

   <Files *.jpg>
   SetHandler None
   </Files>

Instead of starting with SetHandler, one could instead start with  
AddHandler.

   AddHandler mod_python .html
   PythonHandler mod_python.dispatcher

   # Must block access to static .py files.

   <Files *.py>
   deny from all
   </Files>

In this way, only things with a .html extension will be handled by  
the dispatcher.
If there are individual .html files that you want served as static  
files or in some
other way, can again use Files directive to mark specifically how  
they should
be dealt with.

   <Files index.html>
   SetHandler default-handler
   </Files>

For the next tricky bit of this dispatcher, it can be used for other  
phases besides
that for just the response handler phase. For example, if I want to  
be able to
specify fixup handlers for individual resources, then I could use:

   SetHandler mod_python
   PythonFixupHandler mod_python.dispatcher
   PythonHandler mod_python.dispatcher

This would then allow me to say something like:

   from mod_python import apache

   def fixuphandler(req):
     req.used_path_info = apache.AP_REQ_ACCEPT_PATH_INFO
     return apache.OK

   def handler(req):
     ...

What is happening here is that the default behaviour of the  
dispatcher is to
prohibit additional path information to be provided for a request  
against
a resource. This could be enabled on a per resource basis from the  
Apache
configuration file:

   <Files resource>
   AcceptPathInfo On
   </Files>

or, as shown, a fixuphandler() function specific to that resource  
could be
provided within the same resource code file and set req.used_path_info
as appropriate instead.

Thus, any of the prior phases could be enabled on a case by case basis
if they needed to be overridden by specific resources at some point.

Alternatively, one could setup the handler so it checks resource code  
files
for the existence of a handler for any of the prior phases by using:

   SetHandler mod_python
   PythonHandlerModule mod_python.dispatcher

That way, with one directive, would allow other phases such as the
headerparserhandler, accesshandler phases etc, to also be overridden
on a per resource basis.

Although the dispatcher is targeted at allowing handlers to be  
specified on
a per resource basis, it is still possible to mixin other handlers  
which apply
across all requests.

For example:

   PythonHeaderParserHandler moddir::directoryindex

   SetHandler mod_python
   PythonHandlerModule mod_python.dispatcher

   from mod_python import apache

   # moddir.py

   def directoryindex(req):
     if req.content_type == 'httpd/unix-directory:
       req.filename = req.filename + 'index.html'
       req.finfo = apache.stat(req.filename)
       req.content_type = 'text/html'
     return apache.OK

Thus one can emulate the DirectoryIndex directive, which otherwise would
not work with this dispatcher and causes mod_python other problems  
anyway
because of bugs with internal fast redirects in Apache.

One final example with this. One need not even have an actual  
response handler
defined for a resource, but still define a fixup handler. For  
example, if one wanted
to use SSI for a specific resource which existed as a static .html  
file. One could
do this with:

   def fixuphandler_html(req):
     req.handler = 'default-handler'
     req.add_output_filter('INCLUDES')
     req.ssi_globals = { ... }
     return apache.OK

All up, although the actual code for this new dispatch handler is  
quite little, it
allows for a great deal of flexibility and would probably give users  
more to work
with than what most people come up with for a simple dispatcher.

For those who have been trying mod_python 3.3, would be great to see  
you give
this new handler a go and see what you think. Any comments most welcome,
especially whether or not it is something people feel would be  
worthwhile to
include in mod_python 3.3. Note that for people not using mod_python  
3.3, this
will not work with older versions.

BTW, to test this, just throw it a directory in your document tree  
and setup the
.htaccess file to contain:

   SetHandler mod_python
   PythonHandlerModule _handlers
   PythonDebug On

   <Files *.py>
   deny from all
   </Files>

Just don't make requests against '/_handlers' as it will loop back on  
itself given
that it isn't meant to be in the document tree itself.

Have fun.

Graham



Mime
View raw message