[wsgi] make sure request.content is available for consumption
authorJulien Cristau <julien.cristau@logilab.fr>
Thu, 06 Mar 2014 13:59:24 +0100
changeset 9563 48f0ff3e2a32
parent 9562 0509880fec01
child 9567 b87c09f853d3
[wsgi] make sure request.content is available for consumption The wsgi.input stream is not seekable, so make a copy either to memory or disk so it's still available to the user even after we've parsed it (for POST form processing). Closes #3554996
wsgi/request.py
--- a/wsgi/request.py	Wed Jan 29 10:57:10 2014 +0100
+++ b/wsgi/request.py	Thu Mar 06 13:59:24 2014 +0100
@@ -45,7 +45,17 @@
         self.environ = environ
         self.path = environ['PATH_INFO']
         self.method = environ['REQUEST_METHOD'].upper()
-        self.content = environ['wsgi.input']
+        try:
+            length = int(environ['CONTENT_LENGTH'])
+        except (KeyError, ValueError):
+            length = 0
+        # wsgi.input is not seekable, so copy the request contents to a temporary file
+        if length < 100000:
+            self.content = StringIO()
+        else:
+            self.content = tempfile.TemporaryFile()
+        safe_copyfileobj(environ['wsgi.input'], self.content, size=length)
+        self.content.seek(0, 0)
 
         headers_in = dict((normalize_header(k[5:]), v) for k, v in self.environ.items()
                           if k.startswith('HTTP_'))
@@ -139,15 +149,6 @@
     @property
     @cached
     def raw_post_data(self):
-        buf = StringIO()
-        try:
-            # CONTENT_LENGTH might be absent if POST doesn't have content at all (lighttpd)
-            content_length = int(self.environ.get('CONTENT_LENGTH', 0))
-        except ValueError: # if CONTENT_LENGTH was empty string or not an integer
-            content_length = 0
-        if content_length > 0:
-            safe_copyfileobj(self.environ['wsgi.input'], buf,
-                    size=content_length)
-        postdata = buf.getvalue()
-        buf.close()
+        postdata = self.content.read()
+        self.content.seek(0, 0)
         return postdata