Author: lukeplant
Date: 2011-03-28 09:11:40 -0700 (Mon, 28 Mar 2011)
New Revision: 15938

Modified:
   django/trunk/django/http/__init__.py
   django/trunk/tests/regressiontests/requests/tests.py
Log:
Fixed #15679 - regression in HttpRequest.POST and raw_post_data access.

Thanks to vkryachko for the report.

This also fixes a slight inconsistency with raw_post_data after parsing of a
multipart request, and adds a test for that.  (Previously accessing
raw_post_data would have returned the empty string rather than raising an
Exception).

Modified: django/trunk/django/http/__init__.py
===================================================================
--- django/trunk/django/http/__init__.py        2011-03-28 14:22:48 UTC (rev 
15937)
+++ django/trunk/django/http/__init__.py        2011-03-28 16:11:40 UTC (rev 
15938)
@@ -262,14 +262,18 @@
         if self.method != 'POST':
             self._post, self._files = QueryDict('', encoding=self._encoding), 
MultiValueDict()
             return
-        if self._read_started:
+        if self._read_started and not hasattr(self, '_raw_post_data'):
             self._mark_post_parse_error()
             return
 
         if self.META.get('CONTENT_TYPE', '').startswith('multipart'):
-            self._raw_post_data = ''
+            if hasattr(self, '_raw_post_data'):
+                # Use already read data
+                data = StringIO(self._raw_post_data)
+            else:
+                data = self
             try:
-                self._post, self._files = self.parse_file_upload(self.META, 
self)
+                self._post, self._files = self.parse_file_upload(self.META, 
data)
             except:
                 # An error occured while parsing POST data.  Since when
                 # formatting the error the request handler might access

Modified: django/trunk/tests/regressiontests/requests/tests.py
===================================================================
--- django/trunk/tests/regressiontests/requests/tests.py        2011-03-28 
14:22:48 UTC (rev 15937)
+++ django/trunk/tests/regressiontests/requests/tests.py        2011-03-28 
16:11:40 UTC (rev 15938)
@@ -179,6 +179,66 @@
         self.assertRaises(Exception, lambda: request.raw_post_data)
         self.assertEqual(request.POST, {})
 
+    def test_raw_post_data_after_POST_multipart(self):
+        """
+        Reading raw_post_data after parsing multipart is not allowed
+        """
+        # Because multipart is used for large amounts fo data i.e. file 
uploads,
+        # we don't want the data held in memory twice, and we don't want to
+        # silence the error by setting raw_post_data = '' either.
+        payload = "\r\n".join([
+                '--boundary',
+                'Content-Disposition: form-data; name="name"',
+                '',
+                'value',
+                '--boundary--'
+                ''])
+        request = WSGIRequest({'REQUEST_METHOD': 'POST',
+                               'CONTENT_TYPE': 'multipart/form-data; 
boundary=boundary',
+                               'CONTENT_LENGTH': len(payload),
+                               'wsgi.input': StringIO(payload)})
+        self.assertEqual(request.POST, {u'name': [u'value']})
+        self.assertRaises(Exception, lambda: request.raw_post_data)
+
     def test_read_by_lines(self):
         request = WSGIRequest({'REQUEST_METHOD': 'POST', 'wsgi.input': 
StringIO('name=value')})
         self.assertEqual(list(request), ['name=value'])
+
+    def test_POST_after_raw_post_data_read(self):
+        """
+        POST should be populated even if raw_post_data is read first
+        """
+        request = WSGIRequest({'REQUEST_METHOD': 'POST', 'wsgi.input': 
StringIO('name=value')})
+        raw_data = request.raw_post_data
+        self.assertEqual(request.POST, {u'name': [u'value']})
+
+    def test_POST_after_raw_post_data_read_and_stream_read(self):
+        """
+        POST should be populated even if raw_post_data is read first, and then
+        the stream is read second.
+        """
+        request = WSGIRequest({'REQUEST_METHOD': 'POST', 'wsgi.input': 
StringIO('name=value')})
+        raw_data = request.raw_post_data
+        self.assertEqual(request.read(1), u'n')
+        self.assertEqual(request.POST, {u'name': [u'value']})
+
+    def test_POST_after_raw_post_data_read_and_stream_read_multipart(self):
+        """
+        POST should be populated even if raw_post_data is read first, and then
+        the stream is read second. Using multipart/form-data instead of 
urlencoded.
+        """
+        payload = "\r\n".join([
+                '--boundary',
+                'Content-Disposition: form-data; name="name"',
+                '',
+                'value',
+                '--boundary--'
+                ''])
+        request = WSGIRequest({'REQUEST_METHOD': 'POST',
+                               'CONTENT_TYPE': 'multipart/form-data; 
boundary=boundary',
+                               'CONTENT_LENGTH': len(payload),
+                               'wsgi.input': StringIO(payload)})
+        raw_data = request.raw_post_data
+        # Consume enough data to mess up the parsing:
+        self.assertEqual(request.read(13), u'--boundary\r\nC')
+        self.assertEqual(request.POST, {u'name': [u'value']})

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.

Reply via email to