Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

[1.3.X] Fixed #15679 - regression in HttpRequest.POST and raw_post_da…

…ta 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).

Backport of [15938] from trunk.

git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.3.X@15939 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit ce9b216882ea11bf351f222513458bc503556a91 1 parent 9b0f1de
Luke Plant authored March 28, 2011
10  django/http/__init__.py
@@ -262,14 +262,18 @@ def _load_post_and_files(self):
262 262
         if self.method != 'POST':
263 263
             self._post, self._files = QueryDict('', encoding=self._encoding), MultiValueDict()
264 264
             return
265  
-        if self._read_started:
  265
+        if self._read_started and not hasattr(self, '_raw_post_data'):
266 266
             self._mark_post_parse_error()
267 267
             return
268 268
 
269 269
         if self.META.get('CONTENT_TYPE', '').startswith('multipart'):
270  
-            self._raw_post_data = ''
  270
+            if hasattr(self, '_raw_post_data'):
  271
+                # Use already read data
  272
+                data = StringIO(self._raw_post_data)
  273
+            else:
  274
+                data = self
271 275
             try:
272  
-                self._post, self._files = self.parse_file_upload(self.META, self)
  276
+                self._post, self._files = self.parse_file_upload(self.META, data)
273 277
             except:
274 278
                 # An error occured while parsing POST data.  Since when
275 279
                 # formatting the error the request handler might access
60  tests/regressiontests/requests/tests.py
@@ -179,6 +179,66 @@ def test_value_after_read(self):
179 179
         self.assertRaises(Exception, lambda: request.raw_post_data)
180 180
         self.assertEqual(request.POST, {})
181 181
 
  182
+    def test_raw_post_data_after_POST_multipart(self):
  183
+        """
  184
+        Reading raw_post_data after parsing multipart is not allowed
  185
+        """
  186
+        # Because multipart is used for large amounts fo data i.e. file uploads,
  187
+        # we don't want the data held in memory twice, and we don't want to
  188
+        # silence the error by setting raw_post_data = '' either.
  189
+        payload = "\r\n".join([
  190
+                '--boundary',
  191
+                'Content-Disposition: form-data; name="name"',
  192
+                '',
  193
+                'value',
  194
+                '--boundary--'
  195
+                ''])
  196
+        request = WSGIRequest({'REQUEST_METHOD': 'POST',
  197
+                               'CONTENT_TYPE': 'multipart/form-data; boundary=boundary',
  198
+                               'CONTENT_LENGTH': len(payload),
  199
+                               'wsgi.input': StringIO(payload)})
  200
+        self.assertEqual(request.POST, {u'name': [u'value']})
  201
+        self.assertRaises(Exception, lambda: request.raw_post_data)
  202
+
182 203
     def test_read_by_lines(self):
183 204
         request = WSGIRequest({'REQUEST_METHOD': 'POST', 'wsgi.input': StringIO('name=value')})
184 205
         self.assertEqual(list(request), ['name=value'])
  206
+
  207
+    def test_POST_after_raw_post_data_read(self):
  208
+        """
  209
+        POST should be populated even if raw_post_data is read first
  210
+        """
  211
+        request = WSGIRequest({'REQUEST_METHOD': 'POST', 'wsgi.input': StringIO('name=value')})
  212
+        raw_data = request.raw_post_data
  213
+        self.assertEqual(request.POST, {u'name': [u'value']})
  214
+
  215
+    def test_POST_after_raw_post_data_read_and_stream_read(self):
  216
+        """
  217
+        POST should be populated even if raw_post_data is read first, and then
  218
+        the stream is read second.
  219
+        """
  220
+        request = WSGIRequest({'REQUEST_METHOD': 'POST', 'wsgi.input': StringIO('name=value')})
  221
+        raw_data = request.raw_post_data
  222
+        self.assertEqual(request.read(1), u'n')
  223
+        self.assertEqual(request.POST, {u'name': [u'value']})
  224
+
  225
+    def test_POST_after_raw_post_data_read_and_stream_read_multipart(self):
  226
+        """
  227
+        POST should be populated even if raw_post_data is read first, and then
  228
+        the stream is read second. Using multipart/form-data instead of urlencoded.
  229
+        """
  230
+        payload = "\r\n".join([
  231
+                '--boundary',
  232
+                'Content-Disposition: form-data; name="name"',
  233
+                '',
  234
+                'value',
  235
+                '--boundary--'
  236
+                ''])
  237
+        request = WSGIRequest({'REQUEST_METHOD': 'POST',
  238
+                               'CONTENT_TYPE': 'multipart/form-data; boundary=boundary',
  239
+                               'CONTENT_LENGTH': len(payload),
  240
+                               'wsgi.input': StringIO(payload)})
  241
+        raw_data = request.raw_post_data
  242
+        # Consume enough data to mess up the parsing:
  243
+        self.assertEqual(request.read(13), u'--boundary\r\nC')
  244
+        self.assertEqual(request.POST, {u'name': [u'value']})

0 notes on commit ce9b216

Please sign in to comment.
Something went wrong with that request. Please try again.