On 11/19/06, Graham Dumpleton <[EMAIL PROTECTED]> wrote:
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
Graham,
Is this based on your Vampire work? If so, does it handle extra path
info like vampire? Also, does it handle web services like vampire
too? I've used vampire before and I like it.
I'm updating my repos now.
Thanks,
Jeff
p.s.
+1 on the new handler