Problems with accessing request/session in middleware

62 views
Skip to first unread message

mickolka

unread,
Mar 25, 2008, 5:05:04 PM3/25/08
to pylons-discuss
Hi all

I have created a middleware t track campaigns that do one simple thing
- it get parameter from request and set cookie, code looks like

class CampaignTrackingMiddleware(object):

def __init__(self, app):
self.app = app

def __call__(self, environ, start_response):
source_id = request.params.get('source_id')
if not is_blank(source_id) and
request.cookies.get('source_id') != source_id:
# print "setting source_id cookie to %s " %
request.params.get('source_id')
response.set_cookie('source_id', source_id,
expires=3600000)
session.save()
return self.app(environ, start_response)

After I'm adding it to the chain in middleware.py
I'm getting the error
..................................................................

File "/opt/workspace/uaprom/uaprom/lib/custom_middleware.py", line
27, in __call__
if not is_blank(request.params.get('source_id')):
File "/sw/lib/python2.5/site-packages/Paste-1.4.2-py2.5.egg/paste/
registry.py", line 125, in __getattr__
return getattr(self._current_obj(), attr)
File "/sw/lib/python2.5/site-packages/Paste-1.4.2-py2.5.egg/paste/
registry.py", line 182, in _current_obj
'thread' % self.____name__)
TypeError: No object (name: Request) has been registered for this
thread

As far as I understand request is not registered at that point, I
tried to move my middleware to the top/bottom of the chain and the
error was still the same. After all I moved the logic to the
__before__ method of BaseController

Is there any way to do such things in the middleware or BaseController
is the right place for that?

Thanks in advance for any help
m

Disclaimer: I came from J2EE world (I hope I never come back to that
enterprise nightmare) and think that Middleware is ServletFilter
analog, I might be wrong.

Mike Orr

unread,
Mar 26, 2008, 1:46:39 AM3/26/08
to pylons-...@googlegroups.com

You have three choices.

1) Move the code to the base controller's .__before__ or .__call__ method.

2) Parse the parameters yourself using
cgi.parse_qs(environ['QUERY_STRING"]). If you want to delete
parameters, you can rewrite the query string with urllib.urlencode.
Don't use cgi.FieldStorage because it will use the actual environment
variables and standard input rather than the WSGI environment.

3) Call webob.Request(environ) to get the same type of request object
Pylons uses.

WebOb also contains a middleware class or decorator which makes
writing middleware much easier. You should probably use it.

If the request is POST, you'll have to figure out how to read the
input and then set it back the way it was for the application.

I don't know about J2EE, but middleware is intended for two purposes:

1) Features that are completely optional, that the application doesn't
realize are there. Pylons error handlers are an example of this, as
well as the static application at the bottom of middleware.py.

2) Services for the application, which can be used with a different
application just as easily. The Routes and session middleware are
examples of these. (They're hidden in Pylons 0.9.6, but in
middleware.py in 0.9.7-alpha).

Some would argue that only (1) is true middleware and (2) should be
called something else, but in any case both are useful. But if the
service is really specific to one application and not useful in other
applications, it belongs in the base controller rather than in
middleware.

I have been thinking about a heresy the past week, that instead of
improving WSGI maybe we should just leapfrog it to a WebOb-based chain
of servers, applicaiions, and middleware. Then the protocol could
just create the request/response once a the beginning of the chain and
let the middleware/application modify it rather than each middleware
having to reinvent the wheel and parse obscure environ keys. But
that's too radical to just do in Pylons right now.

--
Mike Orr <slugg...@gmail.com>

mickolka

unread,
Mar 26, 2008, 8:30:20 AM3/26/08
to pylons-discuss
Mike thanks for great post again, For now I use 1) but maybe will
think about webob after my product released.

> I have been thinking about a heresy the past week, that instead of
> improving WSGI maybe we should just leapfrog it to a WebOb-based chain
> of servers, applicaiions, and middleware.  Then the protocol could
> just create the request/response once a the beginning of the chain and
> let the middleware/application modify it rather than each middleware
> having to reinvent the wheel and parse obscure environ keys.  But
> that's too radical to just do in Pylons right now.
>

That is exactly what is done in J2EE ServeltFilter, request/response
get created and passed to the chain of filters, Filters are mapped to
some URLs or Servlets (controllers in Pylons world). I think it worth
considering something similar with Pylons in the future.

Mike Orr

unread,
Mar 26, 2008, 12:21:26 PM3/26/08
to pylons-...@googlegroups.com
On Wed, Mar 26, 2008 at 5:30 AM, mickolka <mpali...@gmail.com> wrote:
> > I have been thinking about a heresy the past week, that instead of
> > improving WSGI maybe we should just leapfrog it to a WebOb-based chain
> > of servers, applicaiions, and middleware. Then the protocol could
> > just create the request/response once a the beginning of the chain and
> > let the middleware/application modify it rather than each middleware
> > having to reinvent the wheel and parse obscure environ keys. But
> > that's too radical to just do in Pylons right now.
> >
>
> That is exactly what is done in J2EE ServeltFilter, request/response
> get created and passed to the chain of filters, Filters are mapped to
> some URLs or Servlets (controllers in Pylons world). I think it worth
> considering something similar with Pylons in the future.

The reason WSGI is as it is, is to depend solely on Python builtin
types and minimize the number of dependencies.

The counterargument is that the designers of WSGI did not anticipate
how difficult it would be to write a middleware that's fully correct
given situations like delayed headers and chunked output and the needs
of asynchronous servers. The 'start_response' callback and 'write'
method double or triple the complexity of middleware, which scares
many developers away from writing it, and means that much of the
middleware that exists is wrong in edge cases, either because the
developer couldn't figure it out, or because they threw up their hands
and refused to code the complicated, little-used part. Thus the
motivation for WSGI 2 which is gaining steam. WSGI will have to
change in Python 3 in any case, because the changing relationship of
string to unicode will make it invalid. (WSGI assumes bytestrings can
be used as 'str' strings unchanged, which is not true in Python 3.)

Replacing WSGI with a WebOb-like system would make things much easier
for server writers, application writers, and framework writers. But
it means the Python community would have to agree on a standard
request/response object, which some would see as too specific, or too
onerous for extremely high-traffic light-footprint low-memory use
cases. Also, WebOb itself depends on an environ dict as currently
spec'd. If you eliminate the environ as its data source, what source
will it use instead?

--
Mike Orr <slugg...@gmail.com>

Reply all
Reply to author
Forward
0 new messages