[Web-SIG] Python Web Modules - Version 0.5.0

Ian Bicking ianb at colorstudy.com
Tue Feb 1 18:15:47 CET 2005


James Gardner wrote:
> Ian Bicking wrote:
> 
>>> Another thing I noticed when writing the error handler is that if an 
>>> application or middleware component doesn't form a header or set the 
>>> status correctly it can be tricky to track down where the error 
>>> occurred. If the application used a special object for headers and 
>>> status in the start_response callable which raised an error when it 
>>> was set with an invalid value that would make life easier.
>>
>>
>> I'm not sure I understand you here.  What's the exact situation where 
>> you encounter this?
> 
> Well, when I was programming the session middleware I appended a tuple 
> of the wrong length to the headers used in start_response. This wasn't 
> picked up until the error handling module by which time I had no idea 
> which piece of middleware had appended the faulty header. If header was 
> an object that behaved like a list but only allowed correctly formed 
> headers to be appended this error would have been picked up where it 
> happened.

That seems like a complicated way to deal with the problem.  If it's 
just for debugging you can add the wsgikit.lint middleware, and it 
checks for most of these issues without actually effecting the server or 
application.  It does specifically check for the headers being a list of 
tuples of length 2.

>>> One other thing I've been meaning to ask.. The WSGI specification 
>>> currently allows no way for an application or middleware components 
>>> to pass custom information back up the middleware chain so that an 
>>> application can ask a middleware component not to perform a certain 
>>> task if it needs to. Communication up the chain can only be provided 
>>> through status, headers, exc_info and content. There could very 
>>> easily also be a response dictionary added as another parameter to 
>>> start_response, similar to environ which sent information up the 
>>> chain. Was this deliberately avoided so that the system wouldn't get 
>>> complicated?
>>
>>
>> I was thinking about this too.  It certainly makes it simpler to make 
>> the response fairly plain and HTTP-like, but I can imagine lots of 
>> useful information that doesn't fit well into headers or response 
>> codes.  E.g., if you are sending a 403 error message, maybe you want 
>> to pass some extra information along about why it happened.  You could 
>> write that out as the HTML response, but then it becomes somewhat 
>> opaque if that gets rewritten.  Something like the extension 
>> information that gets put in the request environment; it's always 
>> purely optional, but there to allow cooperation between components.  
>> There's no escape mechanism like that for the response.
>>
>> Well... there is a way, actually -- you can add callbacks to the 
>> request.  For instance, in my session handler I add a callable to the 
>> request that returns the session object.  If you don't call that at 
>> all then the session isn't even created, and no session ID is assigned 
>> (assuming you didn't already have a session).  If you do call it, then 
>> the middleware modifies the response to add a session ID.  So there's 
>> really some communication from the application that effects the 
>> response, but it isn't being expressed as part of the response stream 
>> (the status, headers, and body).
> 
> 
> That's true and useful in the session case. In fact any middleware that 
> needed the session store could still call the callable, they'd just need 
> to check if it had already been called (or the callable itself could 
> keep track of whether it had been called in fact). 

Yes, it keeps track, and each time you call the session-creator that's 
in the environment it returns the same session object (but that object 
is created lazily).

> It does mean that 
> other middleware components can't get access to the same information 
> though unless they all chain callables down the middleware stack.

Perhaps instead of it being a callable it could be an object, and could 
support methods to check, for instance, if a session had been created 
without actually creating one.

> It doesn't really work for your first example with the error information 
> though since the information should be available to all middleware 
> components. In that example though couldn't the application send error 
> information with exc_info and the auth middleware catch it or am I 
> missing something?

It could work for error information.  E.g.:

def middleware(application):
     def error_app(environ, start_response):
         if not environ.has_key('wsgikit.errorchecker'):
             checker = environ['wsgikit.errorchecker'] = ErrorChecker()
         try:
             return application(environ, start_response)
         except:
             exc_info = sys.exc_info()
             return checker.respond_to_exception(exc_info)
     return error_app

Then ErrorChecker is an instance you could add information to at any 
level of the application.  ErrorChecker, in turn, could add information 
to another component, e.g., the ErrorDocument-like middleware.

> Do you think there is mileage to be gained from adding a response 
> dictionary to start_response as that would be a simple way of sending 
> information back? It would break if existing WSGI apps didn't pass on 
> the response dictionary though.

I think extending the request dictionary like this is sufficient.

-- 
Ian Bicking  /  ianb at colorstudy.com  /  http://blog.ianbicking.org


More information about the Web-SIG mailing list