Graham Dumpleton
grahamd at dscpl.com.au
Sat Oct 7 22:37:39 EDT 2006
On 07/10/2006, at 9:55 PM, Norman Tindall wrote: > GD> Using AddHandler and other Apache directives is still the better > GD> way. In mod_python 3.3 it will be easier to do things like above, > GD> but it shouldn't be done in the response handler phase but an > GD> earlier phase such as the fixup handler phase. I'll be writing an > GD> article about this specific ability of mod_python 3.3 some time in > GD> the near future hopefully. > > GD> Graham > > The reason why i am using this is that i am using mod_python 3.1 > by now. I will upgrade to 3.3 as soon as possible. > > > I have a question according to you last reply to my letter. > Suppose i want to process thing as this: > > +-------------------+ > | start of req | > +-------------------+ > / \ > / \ > +-----------------------+ +------------------------+ > | extension is: | | All other extension | > | ['py','html','css'] | | | > | and without extension | +------------------------+ > | but there are no real | | > | files at all, they | | > | all redirected to say | | > | engine.py | | > | so i don`t want apache| | > | to check for exsistance | > | of file | | > +-----------------------+ | > | Apache standard > Python handler Handler > | | > ------------------------ ------------------------ > In some cases script Apache generates all > generates error pages error pages > like 404,403,500 > But in other cases > i want apache standard > error pages. > > > What is the best,simple and fastest way? > Can i do this with just apache directives or i have to parse, uri > and extension by myself in fixuphandler as you said? > > 1 import posixpath > 2 from mod_python import apache, psp > 3 > 4 def fixuphandler(req): > 5 extension = posixpath.splitext(req.filename)[1] > 6 if extension in ['py','html','css']: > 7 req.add_handler('PythonHandler', my_handler) > 8 req.handler = 'mod_python' > 9 return apache.OK For mod_python 3.2 and earlier use Apache configuration of: # Files which have no extension. <Files ~ '^[^.]*$'> SetHandler mod_python </Files> # Files with extension of interest. <Files ~ '^.*\.(css|py|html)$> SetHandler mod_python </Files> PythonHandler _handlers::handler PythonHandler _handlers::handler_css | .css PythonHandler _handlers::handler_py | .py PythonHandler _handlers::handler_html | .html Note this is for .htaccess file, but can also be inside Directory directive. If using mod_python 3.3 I might have made it more constrained by using: <Files ~ '^[^.]*$'> SetHandler mod_python PythonHandler _handlers::handler </Files> <Files ~ '^.*\.(css|py|html)$> SetHandler mod_python PythonHandler _handlers::handler_css | .css PythonHandler _handlers::handler_py | .py PythonHandler _handlers::handler_html | .html </Files> Ie., stick the PythonHandler inside the Files directive. This will not work on mod_python 3.2 and earlier though if the Python handler module resides in the document tree. If the Python handler module is elsewhere on sys.path, then can do this for 3.2 and earlier. The reasons for the problems are documented at: http://issues.apache.org/jira/browse/MODPYTHON-126 This is fixed in 3.3 though. With a Python handler module of: from mod_python import apache def _dump(req, extension): req.content_type = 'text/plain' print >> req, 'uri = %s' % req.uri print >> req, 'filename = %s' % req.filename print >> req, 'path_info = %s' % req.path_info print >> req, 'extension = %s' % extension return apache.OK def handler(req): return _dump(req, '') def handler_css(req): return _dump(req, '.css') def handler_py(req): return _dump(req, '.py') def handler_html(req): return _dump(req, '.html') If this directory is accessed as '/~grahamd/handlers/' and I use that as the URL I get: uri = /~grahamd/handlers/ filename = /Users/grahamd/public_html/handlers/ path_info = extension = Thus handler() was called. Similarly if I use '/~grahamd/handlers/page'. uri = /~grahamd/handlers/page filename = /Users/grahamd/public_html/handlers/page path_info = extension = If I use any of the extensions of interest, I get something like: uri = /~grahamd/handlers/page.css filename = /Users/grahamd/public_html/handlers/page.css path_info = extension = .css uri = /~grahamd/handlers/page.py filename = /Users/grahamd/public_html/handlers/page.py path_info = extension = .py uri = /~grahamd/handlers/page.html filename = /Users/grahamd/public_html/handlers/page.html path_info = extension = .html Thus different handler gets called for each extension type. If I use any other extension, I get a 404 not found, unless the file did actually exist as a static file in which case it would be returned. Now, there is one issue with doing it as above. That is that the Files directive only matches the first component of the path in req.filename appearing after the actual physical directory. Thus, if I use a URL of '/~grahamd/handlers/subdir/page.html', I will get: uri = /~grahamd/handlers/subdir/page.html filename = /Users/grahamd/public_html/handlers/subdir path_info = /page.html extension = and the handler for the '.html' extension will not be called as you might expect. This is all to do with how Apache matches URLs against the physical directory hierarchy and how it determines what actually constitutes the path info for a request. At some point you would have to deal with this yourself if you were to take total control of mapping the URL to some target. Anyway, to ensure that Apache does what is required in this case, all that is required is to create the physical directories in the file system which correspond to those directories which you want to notionally hold what appear to be static files. Thus: mkdir /Users/grahamd/public_html/handlers/subdir Now I get: uri = /~grahamd/handlers/subdir/page.html filename = /Users/grahamd/public_html/handlers/subdir/page.html path_info = extension = .html A benefit of still relying on Apache for doing this mapping and creating the subdirectories, is you could use a modified handler of: def handler_html(req): if os.path.exists(req.filename): return apache.DECLINED return _dump(req, '.html') That is, because req.filename is valid, can simply check for the existence of the file and if it exists return apache.DECLINED so that Apache serves it up as a static file instead. Thus can mix static and dynamic files with the static taking precedence. Note that using os.path.exists() here results in an extra stat() call, but have to do this with mod_python 3.2 and earlier as some information missing with req.finfo. In mod_python 3.3, would instead use: def handler_html(req): if req.finfo.filetype == apache.APR_REG: return apache.DECLINED return _dump(req, '.html') BTW, rather than modify the handler, I could have had a separate handler whose only purpose was to check for static files: def check_exists(req): if req.finfo.filetype == apache.APR_REG: return apache.DECLINED return apache.OK Then in the Apache configuration, use: PythonHandler _handlers::check_exists _handlers::handler_html | .html or: PythonHandler _handlers::check_exists |.html PythonHandler _handlers::handler_html | .html Both are equivalent. Ie., use a stacked handler. That the first returns apache.DECLINED causes the latter not to be invoked. This way you have little handlers doing specific jobs and aren't creating one huge handler that tries to do everything. Hope this is interesting. Graham
|