Fixed #17323 -- Renamed HttpRequest.raw_post_data to request.body. Thanks for the patch, dstufft
git-svn-id: http://code.djangoproject.com/svn/django/trunk@17210 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
61f0aff811
commit
3f003a3c4b
|
@ -4,6 +4,8 @@ import datetime
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
|
import warnings
|
||||||
|
|
||||||
from pprint import pformat
|
from pprint import pformat
|
||||||
from urllib import urlencode, quote
|
from urllib import urlencode, quote
|
||||||
from urlparse import urljoin
|
from urlparse import urljoin
|
||||||
|
@ -315,14 +317,19 @@ class HttpRequest(object):
|
||||||
parser = MultiPartParser(META, post_data, self.upload_handlers, self.encoding)
|
parser = MultiPartParser(META, post_data, self.upload_handlers, self.encoding)
|
||||||
return parser.parse()
|
return parser.parse()
|
||||||
|
|
||||||
def _get_raw_post_data(self):
|
@property
|
||||||
if not hasattr(self, '_raw_post_data'):
|
def body(self):
|
||||||
|
if not hasattr(self, '_body'):
|
||||||
if self._read_started:
|
if self._read_started:
|
||||||
raise Exception("You cannot access raw_post_data after reading from request's data stream")
|
raise Exception("You cannot access body after reading from request's data stream")
|
||||||
self._raw_post_data = self.read()
|
self._body = self.read()
|
||||||
self._stream = StringIO(self._raw_post_data)
|
self._stream = StringIO(self._body)
|
||||||
return self._raw_post_data
|
return self._body
|
||||||
raw_post_data = property(_get_raw_post_data)
|
|
||||||
|
@property
|
||||||
|
def raw_post_data(self):
|
||||||
|
warnings.warn('HttpRequest.raw_post_data has been deprecated. Use HttpRequest.body instead.', PendingDeprecationWarning)
|
||||||
|
return self.body
|
||||||
|
|
||||||
def _mark_post_parse_error(self):
|
def _mark_post_parse_error(self):
|
||||||
self._post = QueryDict('')
|
self._post = QueryDict('')
|
||||||
|
@ -334,14 +341,14 @@ class HttpRequest(object):
|
||||||
if self.method != 'POST':
|
if self.method != 'POST':
|
||||||
self._post, self._files = QueryDict('', encoding=self._encoding), MultiValueDict()
|
self._post, self._files = QueryDict('', encoding=self._encoding), MultiValueDict()
|
||||||
return
|
return
|
||||||
if self._read_started and not hasattr(self, '_raw_post_data'):
|
if self._read_started and not hasattr(self, '_body'):
|
||||||
self._mark_post_parse_error()
|
self._mark_post_parse_error()
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.META.get('CONTENT_TYPE', '').startswith('multipart'):
|
if self.META.get('CONTENT_TYPE', '').startswith('multipart'):
|
||||||
if hasattr(self, '_raw_post_data'):
|
if hasattr(self, '_body'):
|
||||||
# Use already read data
|
# Use already read data
|
||||||
data = StringIO(self._raw_post_data)
|
data = StringIO(self._body)
|
||||||
else:
|
else:
|
||||||
data = self
|
data = self
|
||||||
try:
|
try:
|
||||||
|
@ -357,14 +364,14 @@ class HttpRequest(object):
|
||||||
self._mark_post_parse_error()
|
self._mark_post_parse_error()
|
||||||
raise
|
raise
|
||||||
else:
|
else:
|
||||||
self._post, self._files = QueryDict(self.raw_post_data, encoding=self._encoding), MultiValueDict()
|
self._post, self._files = QueryDict(self.body, encoding=self._encoding), MultiValueDict()
|
||||||
|
|
||||||
## File-like and iterator interface.
|
## File-like and iterator interface.
|
||||||
##
|
##
|
||||||
## Expects self._stream to be set to an appropriate source of bytes by
|
## Expects self._stream to be set to an appropriate source of bytes by
|
||||||
## a corresponding request subclass (WSGIRequest or ModPythonRequest).
|
## a corresponding request subclass (WSGIRequest or ModPythonRequest).
|
||||||
## Also when request data has already been read by request.POST or
|
## Also when request data has already been read by request.POST or
|
||||||
## request.raw_post_data, self._stream points to a StringIO instance
|
## request.body, self._stream points to a StringIO instance
|
||||||
## containing that data.
|
## containing that data.
|
||||||
|
|
||||||
def read(self, *args, **kwargs):
|
def read(self, *args, **kwargs):
|
||||||
|
|
|
@ -257,6 +257,10 @@ these changes.
|
||||||
* Setting the ``is_safe`` and ``needs_autoescape`` flags as attributes of
|
* Setting the ``is_safe`` and ``needs_autoescape`` flags as attributes of
|
||||||
template filter functions will no longer be supported.
|
template filter functions will no longer be supported.
|
||||||
|
|
||||||
|
* The attribute ``HttpRequest.raw_post_data`` was renamed to ``HttpRequest.body``
|
||||||
|
in 1.4. The backward compatibility will be removed --
|
||||||
|
``HttpRequest.raw_post_data`` will no longer work.
|
||||||
|
|
||||||
2.0
|
2.0
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,20 @@ Attributes
|
||||||
|
|
||||||
All attributes except ``session`` should be considered read-only.
|
All attributes except ``session`` should be considered read-only.
|
||||||
|
|
||||||
|
.. attribute:: HttpRequest.body
|
||||||
|
|
||||||
|
.. versionchanged:: 1.4
|
||||||
|
Before Django 1.4, ``HttpRequest.body`` was named ``HttpRequest.raw_post_data``.
|
||||||
|
|
||||||
|
The raw HTTP request body as a byte string. This is useful for processing
|
||||||
|
data in different ways than conventional HTML forms: binary images,
|
||||||
|
XML payload etc. For processing conventional form data, use ``HttpRequest.POST``.
|
||||||
|
|
||||||
|
.. versionadded:: 1.3
|
||||||
|
|
||||||
|
You can also read from an HttpRequest using a file-like interface. See
|
||||||
|
:meth:`HttpRequest.read()`.
|
||||||
|
|
||||||
.. attribute:: HttpRequest.path
|
.. attribute:: HttpRequest.path
|
||||||
|
|
||||||
A string representing the full path to the requested page, not including
|
A string representing the full path to the requested page, not including
|
||||||
|
@ -170,17 +184,6 @@ All attributes except ``session`` should be considered read-only.
|
||||||
support activated. See the :doc:`session documentation
|
support activated. See the :doc:`session documentation
|
||||||
</topics/http/sessions>` for full details.
|
</topics/http/sessions>` for full details.
|
||||||
|
|
||||||
.. attribute:: HttpRequest.raw_post_data
|
|
||||||
|
|
||||||
The raw HTTP POST data as a byte string. This is useful for processing
|
|
||||||
data in different formats than of conventional HTML forms: binary images,
|
|
||||||
XML payload etc. For processing form data use ``HttpRequest.POST``.
|
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
You can also read from an HttpRequest using file-like interface. See
|
|
||||||
:meth:`HttpRequest.read()`.
|
|
||||||
|
|
||||||
.. attribute:: HttpRequest.urlconf
|
.. attribute:: HttpRequest.urlconf
|
||||||
|
|
||||||
Not defined by Django itself, but will be read if other code (e.g., a custom
|
Not defined by Django itself, but will be read if other code (e.g., a custom
|
||||||
|
|
|
@ -995,3 +995,10 @@ useful, it was removed in Django 1.4. If you relied on it, you must edit your
|
||||||
settings file to list all your applications explicitly.
|
settings file to list all your applications explicitly.
|
||||||
|
|
||||||
.. _this can't be done reliably: http://docs.python.org/tutorial/modules.html#importing-from-a-package
|
.. _this can't be done reliably: http://docs.python.org/tutorial/modules.html#importing-from-a-package
|
||||||
|
|
||||||
|
``HttpRequest.raw_post_data`` renamed to ``HttpRequest.body``
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
This attribute was confusingly named ``HttpRequest.raw_post_data``, but it
|
||||||
|
actually provided the body of the HTTP request. It's been renamed to
|
||||||
|
``HttpRequest.body``, and ``HttpRequest.raw_post_data`` has been deprecated.
|
||||||
|
|
|
@ -44,7 +44,7 @@ def raw_post_view(request):
|
||||||
"""A view which expects raw XML to be posted and returns content extracted
|
"""A view which expects raw XML to be posted and returns content extracted
|
||||||
from the XML"""
|
from the XML"""
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
root = parseString(request.raw_post_data)
|
root = parseString(request.body)
|
||||||
first_book = root.firstChild.firstChild
|
first_book = root.firstChild.firstChild
|
||||||
title, author = [n.firstChild.nodeValue for n in first_book.childNodes]
|
title, author = [n.firstChild.nodeValue for n in first_book.childNodes]
|
||||||
t = Template("{{ title }} - {{ author }}", name="Book template")
|
t = Template("{{ title }} - {{ author }}", name="Book template")
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import time
|
import time
|
||||||
|
import warnings
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from StringIO import StringIO
|
from StringIO import StringIO
|
||||||
|
|
||||||
|
@ -6,6 +7,7 @@ from django.conf import settings
|
||||||
from django.core.handlers.modpython import ModPythonRequest
|
from django.core.handlers.modpython import ModPythonRequest
|
||||||
from django.core.handlers.wsgi import WSGIRequest, LimitedStream
|
from django.core.handlers.wsgi import WSGIRequest, LimitedStream
|
||||||
from django.http import HttpRequest, HttpResponse, parse_cookie, build_request_repr
|
from django.http import HttpRequest, HttpResponse, parse_cookie, build_request_repr
|
||||||
|
from django.test.utils import get_warnings_state, restore_warnings_state
|
||||||
from django.utils import unittest
|
from django.utils import unittest
|
||||||
from django.utils.http import cookie_date
|
from django.utils.http import cookie_date
|
||||||
|
|
||||||
|
@ -294,19 +296,19 @@ class RequestsTests(unittest.TestCase):
|
||||||
def test_read_after_value(self):
|
def test_read_after_value(self):
|
||||||
"""
|
"""
|
||||||
Reading from request is allowed after accessing request contents as
|
Reading from request is allowed after accessing request contents as
|
||||||
POST or raw_post_data.
|
POST or body.
|
||||||
"""
|
"""
|
||||||
payload = 'name=value'
|
payload = 'name=value'
|
||||||
request = WSGIRequest({'REQUEST_METHOD': 'POST',
|
request = WSGIRequest({'REQUEST_METHOD': 'POST',
|
||||||
'CONTENT_LENGTH': len(payload),
|
'CONTENT_LENGTH': len(payload),
|
||||||
'wsgi.input': StringIO(payload)})
|
'wsgi.input': StringIO(payload)})
|
||||||
self.assertEqual(request.POST, {u'name': [u'value']})
|
self.assertEqual(request.POST, {u'name': [u'value']})
|
||||||
self.assertEqual(request.raw_post_data, 'name=value')
|
self.assertEqual(request.body, 'name=value')
|
||||||
self.assertEqual(request.read(), 'name=value')
|
self.assertEqual(request.read(), 'name=value')
|
||||||
|
|
||||||
def test_value_after_read(self):
|
def test_value_after_read(self):
|
||||||
"""
|
"""
|
||||||
Construction of POST or raw_post_data is not allowed after reading
|
Construction of POST or body is not allowed after reading
|
||||||
from request.
|
from request.
|
||||||
"""
|
"""
|
||||||
payload = 'name=value'
|
payload = 'name=value'
|
||||||
|
@ -314,16 +316,16 @@ class RequestsTests(unittest.TestCase):
|
||||||
'CONTENT_LENGTH': len(payload),
|
'CONTENT_LENGTH': len(payload),
|
||||||
'wsgi.input': StringIO(payload)})
|
'wsgi.input': StringIO(payload)})
|
||||||
self.assertEqual(request.read(2), 'na')
|
self.assertEqual(request.read(2), 'na')
|
||||||
self.assertRaises(Exception, lambda: request.raw_post_data)
|
self.assertRaises(Exception, lambda: request.body)
|
||||||
self.assertEqual(request.POST, {})
|
self.assertEqual(request.POST, {})
|
||||||
|
|
||||||
def test_raw_post_data_after_POST_multipart(self):
|
def test_body_after_POST_multipart(self):
|
||||||
"""
|
"""
|
||||||
Reading raw_post_data after parsing multipart is not allowed
|
Reading body after parsing multipart is not allowed
|
||||||
"""
|
"""
|
||||||
# Because multipart is used for large amounts fo data i.e. file uploads,
|
# 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
|
# 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.
|
# silence the error by setting body = '' either.
|
||||||
payload = "\r\n".join([
|
payload = "\r\n".join([
|
||||||
'--boundary',
|
'--boundary',
|
||||||
'Content-Disposition: form-data; name="name"',
|
'Content-Disposition: form-data; name="name"',
|
||||||
|
@ -336,7 +338,7 @@ class RequestsTests(unittest.TestCase):
|
||||||
'CONTENT_LENGTH': len(payload),
|
'CONTENT_LENGTH': len(payload),
|
||||||
'wsgi.input': StringIO(payload)})
|
'wsgi.input': StringIO(payload)})
|
||||||
self.assertEqual(request.POST, {u'name': [u'value']})
|
self.assertEqual(request.POST, {u'name': [u'value']})
|
||||||
self.assertRaises(Exception, lambda: request.raw_post_data)
|
self.assertRaises(Exception, lambda: request.body)
|
||||||
|
|
||||||
def test_POST_multipart_with_content_length_zero(self):
|
def test_POST_multipart_with_content_length_zero(self):
|
||||||
"""
|
"""
|
||||||
|
@ -366,33 +368,33 @@ class RequestsTests(unittest.TestCase):
|
||||||
'wsgi.input': StringIO(payload)})
|
'wsgi.input': StringIO(payload)})
|
||||||
self.assertEqual(list(request), ['name=value'])
|
self.assertEqual(list(request), ['name=value'])
|
||||||
|
|
||||||
def test_POST_after_raw_post_data_read(self):
|
def test_POST_after_body_read(self):
|
||||||
"""
|
"""
|
||||||
POST should be populated even if raw_post_data is read first
|
POST should be populated even if body is read first
|
||||||
"""
|
"""
|
||||||
payload = 'name=value'
|
payload = 'name=value'
|
||||||
request = WSGIRequest({'REQUEST_METHOD': 'POST',
|
request = WSGIRequest({'REQUEST_METHOD': 'POST',
|
||||||
'CONTENT_LENGTH': len(payload),
|
'CONTENT_LENGTH': len(payload),
|
||||||
'wsgi.input': StringIO(payload)})
|
'wsgi.input': StringIO(payload)})
|
||||||
raw_data = request.raw_post_data
|
raw_data = request.body
|
||||||
self.assertEqual(request.POST, {u'name': [u'value']})
|
self.assertEqual(request.POST, {u'name': [u'value']})
|
||||||
|
|
||||||
def test_POST_after_raw_post_data_read_and_stream_read(self):
|
def test_POST_after_body_read_and_stream_read(self):
|
||||||
"""
|
"""
|
||||||
POST should be populated even if raw_post_data is read first, and then
|
POST should be populated even if body is read first, and then
|
||||||
the stream is read second.
|
the stream is read second.
|
||||||
"""
|
"""
|
||||||
payload = 'name=value'
|
payload = 'name=value'
|
||||||
request = WSGIRequest({'REQUEST_METHOD': 'POST',
|
request = WSGIRequest({'REQUEST_METHOD': 'POST',
|
||||||
'CONTENT_LENGTH': len(payload),
|
'CONTENT_LENGTH': len(payload),
|
||||||
'wsgi.input': StringIO(payload)})
|
'wsgi.input': StringIO(payload)})
|
||||||
raw_data = request.raw_post_data
|
raw_data = request.body
|
||||||
self.assertEqual(request.read(1), u'n')
|
self.assertEqual(request.read(1), u'n')
|
||||||
self.assertEqual(request.POST, {u'name': [u'value']})
|
self.assertEqual(request.POST, {u'name': [u'value']})
|
||||||
|
|
||||||
def test_POST_after_raw_post_data_read_and_stream_read_multipart(self):
|
def test_POST_after_body_read_and_stream_read_multipart(self):
|
||||||
"""
|
"""
|
||||||
POST should be populated even if raw_post_data is read first, and then
|
POST should be populated even if body is read first, and then
|
||||||
the stream is read second. Using multipart/form-data instead of urlencoded.
|
the stream is read second. Using multipart/form-data instead of urlencoded.
|
||||||
"""
|
"""
|
||||||
payload = "\r\n".join([
|
payload = "\r\n".join([
|
||||||
|
@ -406,7 +408,23 @@ class RequestsTests(unittest.TestCase):
|
||||||
'CONTENT_TYPE': 'multipart/form-data; boundary=boundary',
|
'CONTENT_TYPE': 'multipart/form-data; boundary=boundary',
|
||||||
'CONTENT_LENGTH': len(payload),
|
'CONTENT_LENGTH': len(payload),
|
||||||
'wsgi.input': StringIO(payload)})
|
'wsgi.input': StringIO(payload)})
|
||||||
raw_data = request.raw_post_data
|
raw_data = request.body
|
||||||
# Consume enough data to mess up the parsing:
|
# Consume enough data to mess up the parsing:
|
||||||
self.assertEqual(request.read(13), u'--boundary\r\nC')
|
self.assertEqual(request.read(13), u'--boundary\r\nC')
|
||||||
self.assertEqual(request.POST, {u'name': [u'value']})
|
self.assertEqual(request.POST, {u'name': [u'value']})
|
||||||
|
|
||||||
|
def test_raw_post_data_returns_body(self):
|
||||||
|
"""
|
||||||
|
HttpRequest.raw_post_body should be the same as HttpRequest.body
|
||||||
|
"""
|
||||||
|
payload = 'Hello There!'
|
||||||
|
request = WSGIRequest({
|
||||||
|
'REQUEST_METHOD': 'POST',
|
||||||
|
'CONTENT_LENGTH': len(payload),
|
||||||
|
'wsgi.input': StringIO(payload)
|
||||||
|
})
|
||||||
|
|
||||||
|
warnings_state = get_warnings_state()
|
||||||
|
warnings.filterwarnings('ignore', category=DeprecationWarning, module='django.http')
|
||||||
|
self.assertEqual(request.body, request.raw_post_data)
|
||||||
|
restore_warnings_state(warnings_state)
|
||||||
|
|
|
@ -975,15 +975,16 @@ class ResponseTemplateDeprecationTests(TestCase):
|
||||||
|
|
||||||
class ReadLimitedStreamTest(TestCase):
|
class ReadLimitedStreamTest(TestCase):
|
||||||
"""
|
"""
|
||||||
Tests that ensure that HttpRequest.raw_post_data, HttpRequest.read() and
|
Tests that ensure that HttpRequest.body, HttpRequest.read() and
|
||||||
HttpRequest.read(BUFFER) have proper LimitedStream behaviour.
|
HttpRequest.read(BUFFER) have proper LimitedStream behaviour.
|
||||||
|
|
||||||
Refs #14753, #15785
|
Refs #14753, #15785
|
||||||
"""
|
"""
|
||||||
def test_raw_post_data_from_empty_request(self):
|
|
||||||
"""HttpRequest.raw_post_data on a test client GET request should return
|
def test_body_from_empty_request(self):
|
||||||
|
"""HttpRequest.body on a test client GET request should return
|
||||||
the empty string."""
|
the empty string."""
|
||||||
self.assertEquals(self.client.get("/test_client_regress/raw_post_data/").content, '')
|
self.assertEquals(self.client.get("/test_client_regress/body/").content, '')
|
||||||
|
|
||||||
def test_read_from_empty_request(self):
|
def test_read_from_empty_request(self):
|
||||||
"""HttpRequest.read() on a test client GET request should return the
|
"""HttpRequest.read() on a test client GET request should return the
|
||||||
|
|
|
@ -31,7 +31,7 @@ urlpatterns = patterns('',
|
||||||
(r'^parse_unicode_json/$', views.return_json_file),
|
(r'^parse_unicode_json/$', views.return_json_file),
|
||||||
(r'^check_headers/$', views.check_headers),
|
(r'^check_headers/$', views.check_headers),
|
||||||
(r'^check_headers_redirect/$', RedirectView.as_view(url='/test_client_regress/check_headers/')),
|
(r'^check_headers_redirect/$', RedirectView.as_view(url='/test_client_regress/check_headers/')),
|
||||||
(r'^raw_post_data/$', views.raw_post_data),
|
(r'^body/$', views.body),
|
||||||
(r'^read_all/$', views.read_all),
|
(r'^read_all/$', views.read_all),
|
||||||
(r'^read_buffer/$', views.read_buffer),
|
(r'^read_buffer/$', views.read_buffer),
|
||||||
(r'^request_context_view/$', views.request_context_view),
|
(r'^request_context_view/$', views.request_context_view),
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import warnings
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.http import HttpResponse, HttpResponseRedirect
|
from django.http import HttpResponse, HttpResponseRedirect
|
||||||
|
@ -79,7 +81,7 @@ def return_json_file(request):
|
||||||
charset = settings.DEFAULT_CHARSET
|
charset = settings.DEFAULT_CHARSET
|
||||||
|
|
||||||
# This just checks that the uploaded data is JSON
|
# This just checks that the uploaded data is JSON
|
||||||
obj_dict = simplejson.loads(request.raw_post_data.decode(charset))
|
obj_dict = simplejson.loads(request.body.decode(charset))
|
||||||
obj_json = simplejson.dumps(obj_dict, encoding=charset,
|
obj_json = simplejson.dumps(obj_dict, encoding=charset,
|
||||||
cls=DjangoJSONEncoder,
|
cls=DjangoJSONEncoder,
|
||||||
ensure_ascii=False)
|
ensure_ascii=False)
|
||||||
|
@ -92,9 +94,9 @@ def check_headers(request):
|
||||||
"A view that responds with value of the X-ARG-CHECK header"
|
"A view that responds with value of the X-ARG-CHECK header"
|
||||||
return HttpResponse('HTTP_X_ARG_CHECK: %s' % request.META.get('HTTP_X_ARG_CHECK', 'Undefined'))
|
return HttpResponse('HTTP_X_ARG_CHECK: %s' % request.META.get('HTTP_X_ARG_CHECK', 'Undefined'))
|
||||||
|
|
||||||
def raw_post_data(request):
|
def body(request):
|
||||||
"A view that is requested with GET and accesses request.raw_post_data. Refs #14753."
|
"A view that is requested with GET and accesses request.body. Refs #14753."
|
||||||
return HttpResponse(request.raw_post_data)
|
return HttpResponse(request.body)
|
||||||
|
|
||||||
def read_all(request):
|
def read_all(request):
|
||||||
"A view that is requested with accesses request.read()."
|
"A view that is requested with accesses request.read()."
|
||||||
|
|
Loading…
Reference in New Issue