[mod_python] How to make a handler for static files?

Scott Chapman scott_list at mischko.com
Tue Feb 28 03:50:46 EST 2006


Deron Meranda wrote:
> Even though Apache mod_rewrite may work better, here's
> just a few comments on your mod_python approach.  If nothing
> else it might be useful as an example....
> 
> On 2/27/06, Scott Chapman <scott_list at mischko.com> wrote:
>>> from mod_python import apache
>>> import os
>>> import psycopg2
>>>
>>> def parse_uri(uri):
>>>     uri_list = uri.split('/')
>>>     uri_list.insert(0,'')
>>>     uri_list=uri_list[-3:]
>>>     return uri_list
> 
> Consider using Python's urlparse module instead.

I'll check into it.  I think this is smaller than importing another module and 
it is very simple and clean, and works great.

>>> def _getInternalName(alias):
>>>         _conn = psycopg2.connect("user=foo dbname=bar host=127.0.0.1 password=barfoo")
>>>         _cursor = _conn.cursor()
>>>         query = "SELECT hostname FROM host_aliases WHERE external_name = %s"
>>>         parms = [alias]
> 
> Should probably use alias.tolower()  (or toupper()).  Hostnames are
> generally case-insensitive (in ASCII).

The table is full of lower case stuff.
The alias is req.hostname, typically which is automatically converted to lower 
case, apparently.  I've never had a problem with this.

>>>         _cursor.execute(query, parms)
>>>         rval = _cursor.fetchone()
>>>         if rval:
>>>             rval = rval[0]
>>>         _conn.rollback()
> 
> Why a rollback?  A commit() is probably better.

A commit is better for a read-only operation (SELECT...)?

>>>         _conn.close()
>>>         return (rval)
>>>
>>> def handler(req):
>>>     def _log(message):
>>>         req.log_error(message)
>>>
>>>     debug = True
>>>
>>>     (subsite, moduleName, methodName)= parse_uri(req.uri)
>>>     internalName = _getInternalName(req.hostname)
>>>     if subsite:
>>>         internalName = _getInternalName(subsite)
>>>
>>>     if not internalName:
>>>         if debug: _log('static_handler - illegal host name')
>>>         raise apache.SERVER_RETURN, apache.HTTP_NOT_FOUND
>>>
>>>     orig_path = req.filename
>>>
>>>     (path, filename) = os.path.split(req.filename)
>>>     new_path = os.path.normpath(path + '/' + internalName + '/' + filename)
> 
> Use os.path.join() instead of a+'/'+b+'/'+c.

Doh. :)

>>>     if os.path.exists(new_path):
>>>         use_path = new_path
>>>     elif os.path.exists(orig_path):
>>>         use_path = orig_path
>>>     else:
>>>         raise apache.SERVER_RETURN, apache.HTTP_NOT_FOUND
>>>
>>>     if debug: _log('static_handler - used path: %s' % use_path)
> 
> You should set up some other headers too.  Mimimally something
> like this:
> 
>     import mimetypes, os, stat, time, sha
> 
>     ct, et = mimetypes.guess_type( use_path )
>     if not ct:
>         ct = 'application/octet-stream'
>     req.content_type = ct
>     if et:
>         req.headers_out['Content-Encoding'] = et
> 
>     mtime = os.stat( use_path )[ stat.ST_MTIME ]
>     lastmod = time.strftime('%a, %d %m %Y %H:%M:%S GMT',
>                            time.gmtime(mtime) )
>     req.headers_out['Last-Modified'] = lastmod
>     req.headers_out['Accept-Ranges'] = 'none'
>     hash = sha.sha()
>     sha.update( open(use_path,'rb').read() )
>     req.headers_out['ETag'] = hash.hexdigest()
> 
>>>     req.sendfile(use_path)
>>>     return apache.OK
> 
> If you really want to get advanced, try handling byte ranges too.

Thanks tons for all the help on this!

Scott


More information about the Mod_python mailing list