How to access wsgi params from a request inside a middleware and a flask request without side effect?

Question:

I need to read some values from the wsgi request before my flask app is loaded. If I read the url from the wsgi request I can access the file without any issues once the flask app is loaded (after the middleware runs).

But if I attempt to access the params it seems to remove the post data once the flask app is loaded. I even went to the extreme of wrapping the wsgi request with a special Webob Request to prevent this “read once” problem.

Does anyone know how to access values from the wsgi request in middleware without doing any sort of side effect harm to the request so you can get post data / file data in a flask app?

from webob import Request

class SomeMiddleware(object):

    def __init__(self, environ):
        self.request = Request(environ)
        self.orig_environ = environ

    def apply_middleware(self):
        print self.request.url #will not do any harm
        print self.request.params #will cause me to lose data

Here is my flask view

    @app.route('/')
    def hello_world():
        from flask import request
        the_file = request.files['file']
        print "and the file is", the_file
Asked By: Toran Billups

||

Answers:

From what I can tell, this is a limitation of the way that WSGI works. The stream needs only be consumable once (PEP 333 and 3333 only require that the stream support read* calls, tell does not need to be supported). Once the stream is exhausted it cannot be re-streamed to other WSGI applications further “inward”. Take a look at these two sections of Werkzeug’s documentation for more information:

  1. http://werkzeug.pocoo.org/docs/request_data/
  2. http://werkzeug.pocoo.org/docs/http/#module-werkzeug.formparser

The way to avoid this issue is to wrap the input stream (wsgi.input) in an object that implements the read and readline methods. Then, only when the final application in the chain actually attempts to exhaust the stream will your methods be run. See Flask’s documentation on generating a request checksum for an example of this pattern.

That being said, are you sure a middleware is the best solution to your problems? If you need to perform some action (dispatch, logging, authentication) based on the content of the body of the request you may be better off making it a part of your application, rather than a stand-alone application of its own.

Answered By: Sean Vieira
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.