mod_python exception catching, other repetitious per-page actions

Jacek Trzmiel sc0rp at hot.pl
Fri Mar 26 13:25:40 EST 2004


"Karl A. Krueger" wrote:
> I'm in the middle of refactoring a small mod_python Web application,
> which uses the Publisher handler.

I have never used Publisher handler myself.  Yes, I've read about it,
but I've decided to not use it after seeing that I will have to
explicitly tell which modules/functions I DON'T want external user to
be able to run -  completely broken idea from security POV.

> One thing I would like to do is factor all of the top-level database
> connecting, top-level exception handling, and error-page generation into
> a single place.  Whenever an exception occurs not trapped locally --
> including an error connecting to the database -- I want to generate an
> HTML error page instead of throwing the stacktrace at the user.
[...]
> One thing I have considered is to handle _all_ the pages through a
> single function, which would look up the specific pages by name:

If you do this then you may as well drop Publisher handler completely. 
One handle() function will work for you.

> ... but this has the problem that it sacrifices the argument name
> matching which is a major useful feature of mod_python Publisher.

Not so big, as you need to validate arguments format anyway.  With calls
like this:
    pos = self.GetFsInt( 'posId' )
    lastDate = self.GetFsDate( 'lastDate' )
you can get arguments from FieldStorage, ensure that arguments are
present and convert them to usable format (e.g. string=>datetime.date). 
Some examples:

    def RaiseMangled( self ):
        raise apache.SERVER_RETURN, apache.HTTP_BAD_REQUEST

    def RaiseNotFound( self ):
        raise apache.SERVER_RETURN, apache.HTTP_NOT_FOUND

    def GetFsString( self, key, default=None ):
        if(default != None):
            if self.fs.has_key(key):
                value = self.fs[key]
            else:
                value = default
        else:
            value = self.fs[key]
        if not isinstance( value, str ):
            self.RaiseMangled()
        return value

    def GetFsInt( self, key ):
        try:
            return int( self.GetFsString(key,'') )
        except ValueError:
            self.RaiseMangled()

    def GetFsDate( self, key ):
        try:
            return Url2Date( self.GetFsString(key,'') )
        except ValueError:
            self.RaiseMangled()



I've used one method in class to handle db connections, dispatch
requests and handle errors:

    def handler( req ):
        h = Handler()
        return h.Handle( req )

   class Handler:
        [...]
        def Handle(req):
            try:
                db = DbAccess.ConnectDb( dbName, host, user )
                self.fs = util.FieldStorage( self.req, True )
                [...]
                self.req.add_common_vars()
                env = req.subprocess_env
                self.script = env['SCRIPT_NAME']
                self.cmd = self.script[ rfind(self.script,'/')+1: ]

                if   self.cmd == '':
                    self.HandleMenu( db )
                elif self.cmd == 'PosDailyFeed':
                    self.HandlePosDailyFeed( db )
                elif self.cmd == 'PosDailySubmit':
                    self.HandlePosDailySubmit( db )
                [...]
                else:
                    self.RaiseNotFound()
                [...]
            except:
                [...]

        # handler for urls like this:
        # /PosDailyFeed?posId=3&date=2004-03-22
        def HandlePosDailyFeed( self, db ):
            pos = self.GetFsInt( 'posId' )
            date = self.GetFsDate( 'date' )
            pb = self.CreatePageBuilder( db )
            valueDict = db.GetPosWorkerData( date, pos )
            BuildDailyFeedPage( pb, db, date, pos, valueDict,
                                String2Html(db.GetPosName(pos)) )
            self.SendPage( pb )


> I'm not sure if keyword args are exactly the Right Thing either.  It also
> would make the URLs even longer than they already are, though I can
> kludge that with Apache URL rewriting rules.  (Bleah.)

If you use straight handler() function instead of Publisher handler then
you have complete freedom how your URLs will look like.

Best regards,
Jacek.





More information about the Python-list mailing list