Skip to content

Commit

Permalink
[1.3.X] Fixed #15679 - regression in HttpRequest.POST and raw_post_da…
Browse files Browse the repository at this point in the history
…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
spookylukey committed Mar 28, 2011
1 parent 9b0f1de commit ce9b216
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 3 deletions.
10 changes: 7 additions & 3 deletions django/http/__init__.py
Expand Up @@ -262,14 +262,18 @@ def _load_post_and_files(self):
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
Expand Down
60 changes: 60 additions & 0 deletions tests/regressiontests/requests/tests.py
Expand Up @@ -179,6 +179,66 @@ def test_value_after_read(self):
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']})

0 comments on commit ce9b216

Please sign in to comment.