[Web-SIG] Standardized configuration

ChunWei Ho fuzzybr80 at gmail.com
Tue Jul 19 20:08:41 CEST 2005


Hi, I have been looking at WSGI for only a few weeks, but had some
ideas similar (I hope) to what is being discussed that I'll put down
here. I'm new to this so I beg your indulgence if this is heading down
the wrong track or wildly offtopic :)

It seems to me that a major drawback of WSGI middleware that is
preventing flexible configuration/chain paths is that the application
to be run has to be determined at init time. It is much flexible if we
were able to specify what application to run and configuration
information at call time - the middleware would be able to approximate
a service of sorts.

An example:
I have an WSGI application simulating a file-server, and I wish to
authenticate users and gzip served files where application. In a
middleware chain it would probably work out to be:
application = authmiddleware(gzipmiddleware(fileserverapp))

For example, a simplified gzipping middleware consists of:
class gzipmiddleware:
  def __init__(self, application, configparam):
     self._application = application
     ....
  def __call__(self, environ, start_response):
     do start_response
     call self._application(environ, start_response) as iterable    
     get each iterator output and zip and yield it.

and the fileserverapp, with doGET, doPUT, doPOST subapplications that
do the actual processing:
def fileserverapp(environ, start_response):
   if(GET): return doGET(environ, start_response)
   if(POST): return doPOST(environ, start_response)
   if(PUT): return doPUT(environ, start_response)

Now, the application-server is specific on what it wishes to gzip
(usually only on GET or POST entity responses and only if the mimetype
allows it). But this level of logic is not to be placed in the
gzipping middleware, since its configurable on the webserver. So in
order to tell the gzipmiddleware whether to gzip or not:

(a) Add a key in environ, say environ[gzip.do_gzip] = True or False to
inform the gzipmiddleware to do gzip or not. This does mean that
gzipmiddleware remains in the chain, irregardless of whether it is
needed or not.

(b) 
Have chain application = authmiddleware(fileserverapp)
Use Handlers, as Ian suggested, and in the fileserverapp's init:
Handlers(
  IfTest(method=GET,MimeOkForGzip=True, RunApp=gzipmiddleware(doGET)), 
  IfTest(method=GET,MimeOkForGzip=False, RunApp=doGET), 
  IfTest(method=POST,MimeOkForGzip=True, RunApp=gzipmiddleware(doPOST)), 
  IfTest(method=POST,MimeOkForGzip=False, RunApp=doPOST), 
  IfTest(method=PUT, RunApp=doPOST) 
) 

(c)
Make gzipmiddleware a service in the following form:
class gzipmiddleware:
  def __init__(self, application=None, configparam=None):
     self._application = application
     ....
  def __call__(self, environ, start_response, application=None,
configparam=None):
     if application and configparam is specified, use them instead of
the init values
         do start_response
         call self._application(environ, start_response) as iterable    
         get each iterator output and zip and yield it.

This "middleware" is still compatible with PEP-333, but can also be used as:
#on main application initialization, create a gzipservice and put it
in environ without
#specifying application or configparams for init():
environ['service.gzip'] = gzipmiddleware()

Modify fileserverapp to:
def fileserverapp(environ, start_response):
   if(GET): 
       if(mimetype ok for gzip):
           gzipservice = environ['service.gzip']
           return gzipservice(environ, start_response, doGET, gzipconfigparams) 
       else: return doGET(environ, start_response)
   if(POST): 
       if(mimetype ok for gzip):
           gzipservice = environ['service.gzip']
           return gzipservice(environ, start_response, doPOST,
gzipconfigparams)
       else: return doPOST(environ, start_response)
   if(PUT): doPUT(environ, start_response)

The main difference here is that you don't have to initialize full
application chains for each possible middleware-path for the request.
This would be very useful if you had many middleware in the chain with
many permutations as to which middleware are needed

You could also instead put a service factory object into environ, it
will return the gzipmiddleware object as a service if already exist,
otherwise it will create it and then return it.


More information about the Web-SIG mailing list