[Web-SIG] WSGI Lite

PJ Eby pje at telecommunity.com
Tue Mar 19 18:47:03 CET 2013


On Mon, Mar 18, 2013 at 1:08 PM, Simon Yarde <simonyarde at me.com> wrote:
> If I understand correctly, one of the goals of WSGI Lite is to keep the environ out of middleware and app code to prevent modification.

No.  You are *allowed* to modify the environment, that's part of the
WSGI spec.  What you *can't* do is trust that nobody *else* will
modify it.  Which is why you can't use the environment to communicate
with middleware, only objects passed along in the environment.

For example, if middleware does env['foobar']=[], it's okay for a
called app to modify that list, as long as the middleware saves a
reference to it and doesn't try to pull it out of the environ later,
e.g.:

     def middleware(...):
          my_list = []
          env['foobar'] = my_list
          app(env)
          if my_list: ....blah

But you must NEVER do this:

     def middleware(...):
          app(env)
          if env['foobar']: ....blah

Even if you were the one who put 'foobar' into the env.

WSGI Lite's argument binding protocol addresses a different problem,
which is that after you call app(env), it's too late for you to get
anything you need out of the original environment, because app() was
within its rights to clear env or change its contents in any way.  (It
also makes it easier to create application-specific or
framework-specific calling conventions, like if you want your
controller functions to be called with a user and a cart as
parameters, as long as you can define how to get a user and a cart
from a WSGI environment.)


> Could this particular goal be achieved by the middleware creating references to the environ values it depends upon prior to calling the app?

Yes, you can use that to communicate up the middleware chain, as I
showed above.  But the problem WSGI Lite bindings solve is not really
related to that.


> Regarding my own scenario..
>
> I have been working on my own small framework, partly as a learning exercise and partly out of frustrations with existing frameworks.
>
> I return 3-tuple responses as per WSGI Lite, and my middleware generates minimal error responses rather than raise exceptions, e.g. ('404 Not Found', ['Content-Length': '0'], []).
>
> I use status-handler decorators to customise these basic responses; these operate at the level of the individual apps or across a dispatch app to provide global response customising.
>
> I use a 'final' flag in the environ to indicate to any outer status-handlers that the response is intended as definitive, i.e. environ[my_framework.status_handler.final] = True, and should not be altered again.

Don't do that.  You need to put a callback in the environ, or a
mutable object that you keep a reference to.  The environ dictionary
itself is strictly passed down to child handlers, and it's perfectly
valid for a piece of middleware to clear the environ entirely before
returning to its caller.  So you can't use raw values in the environ
to communicate up the chain, only down.

Of course, even if you use another method to communicate this "final"
flag, that doesn't necessarily mean that your "final" flag makes any
sense in a WSGI context.  It might actually be that you need to use a
custom header like 'X-MyFramework-Final', that your boundary
middleware strips.  That is probably actually the right way to do it
in WSGI, because there's no guarantee a "final" response returned from
one app is actually going to be the same response as one returned from
another piece of middleware wrapping that.  So really, since this is
information about the response, you should put it in a response
header.

(Perhaps in a future version of WSGI Lite, I could extend the response
protocol to support stripping out some special response headers at the
protocol boundary between WSGI 1 and WSGI Lite.)


> Under WSGI Lite, would I still be able to add flags to the environ? Or is there some other way I should be signalling to outer middleware?

Callbacks and mutable objects are the only way authorized by the WSGI
spec to communicate from an app to an outer server or middleware
(aside from response headers, bodies, or special response iterators),
and WSGI Lite doesn't change this.  It just makes it easier to work
with values obtained from the environment.


More information about the Web-SIG mailing list