Commits

Anonymous committed 64d1049

Fixed #17323 -- Renamed HttpRequest.raw_post_data to request.body. Thanks for the patch, dstufft

  • Participants
  • Parent commits 181f22f

Comments (0)

Files changed (9)

django/http/__init__.py

 import os
 import re
 import time
+import warnings
+
 from pprint import pformat
 from urllib import urlencode, quote
 from urlparse import urljoin
         parser = MultiPartParser(META, post_data, self.upload_handlers, self.encoding)
         return parser.parse()
 
-    def _get_raw_post_data(self):
-        if not hasattr(self, '_raw_post_data'):
+    @property
+    def body(self):
+        if not hasattr(self, '_body'):
             if self._read_started:
-                raise Exception("You cannot access raw_post_data after reading from request's data stream")
-            self._raw_post_data = self.read()
-            self._stream = StringIO(self._raw_post_data)
-        return self._raw_post_data
-    raw_post_data = property(_get_raw_post_data)
+                raise Exception("You cannot access body after reading from request's data stream")
+            self._body = self.read()
+            self._stream = StringIO(self._body)
+        return self._body
+
+    @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):
         self._post = QueryDict('')
         if self.method != 'POST':
             self._post, self._files = QueryDict('', encoding=self._encoding), MultiValueDict()
             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()
             return
 
         if self.META.get('CONTENT_TYPE', '').startswith('multipart'):
-            if hasattr(self, '_raw_post_data'):
+            if hasattr(self, '_body'):
                 # Use already read data
-                data = StringIO(self._raw_post_data)
+                data = StringIO(self._body)
             else:
                 data = self
             try:
                 self._mark_post_parse_error()
                 raise
         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.
     ##
     ## Expects self._stream to be set to an appropriate source of bytes by
     ## a corresponding request subclass (WSGIRequest or ModPythonRequest).
     ## 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.
 
     def read(self, *args, **kwargs):

docs/internals/deprecation.txt

 * Setting the ``is_safe`` and ``needs_autoescape`` flags as attributes of
   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
 ---
 

docs/ref/request-response.txt

 
 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
 
     A string representing the full path to the requested page, not including
     support activated. See the :doc:`session documentation
     </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
 
     Not defined by Django itself, but will be read if other code (e.g., a custom

docs/releases/1.4.txt

 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
+
+``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.

tests/modeltests/test_client/views.py

     """A view which expects raw XML to be posted and returns content extracted
     from the XML"""
     if request.method == 'POST':
-        root = parseString(request.raw_post_data)
+        root = parseString(request.body)
         first_book = root.firstChild.firstChild
         title, author = [n.firstChild.nodeValue for n in first_book.childNodes]
         t = Template("{{ title }} - {{ author }}", name="Book template")

tests/regressiontests/requests/tests.py

 import time
+import warnings
 from datetime import datetime, timedelta
 from StringIO import StringIO
 
 from django.core.handlers.modpython import ModPythonRequest
 from django.core.handlers.wsgi import WSGIRequest, LimitedStream
 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.http import cookie_date
 
     def test_read_after_value(self):
         """
         Reading from request is allowed after accessing request contents as
-        POST or raw_post_data.
+        POST or body.
         """
         payload = 'name=value'
         request = WSGIRequest({'REQUEST_METHOD': 'POST',
                                'CONTENT_LENGTH': len(payload),
                                'wsgi.input': StringIO(payload)})
         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')
 
     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.
         """
         payload = 'name=value'
                                'CONTENT_LENGTH': len(payload),
                                'wsgi.input': StringIO(payload)})
         self.assertEqual(request.read(2), 'na')
-        self.assertRaises(Exception, lambda: request.raw_post_data)
+        self.assertRaises(Exception, lambda: request.body)
         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,
         # 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([
                 '--boundary',
                 'Content-Disposition: form-data; name="name"',
                                'CONTENT_LENGTH': len(payload),
                                'wsgi.input': StringIO(payload)})
         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):
         """
                                'wsgi.input': StringIO(payload)})
         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'
         request = WSGIRequest({'REQUEST_METHOD': 'POST',
                                'CONTENT_LENGTH': len(payload),
                                'wsgi.input': StringIO(payload)})
-        raw_data = request.raw_post_data
+        raw_data = request.body
         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.
         """
         payload = 'name=value'
         request = WSGIRequest({'REQUEST_METHOD': 'POST',
                                'CONTENT_LENGTH': len(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.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.
         """
         payload = "\r\n".join([
                                'CONTENT_TYPE': 'multipart/form-data; boundary=boundary',
                                'CONTENT_LENGTH': len(payload),
                                'wsgi.input': StringIO(payload)})
-        raw_data = request.raw_post_data
+        raw_data = request.body
         # 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']})
+
+    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)

tests/regressiontests/test_client_regress/models.py

 
 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.
 
     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."""
-        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):
         """HttpRequest.read() on a test client GET request should return the

tests/regressiontests/test_client_regress/urls.py

     (r'^parse_unicode_json/$', views.return_json_file),
     (r'^check_headers/$', views.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_buffer/$', views.read_buffer),
     (r'^request_context_view/$', views.request_context_view),

tests/regressiontests/test_client_regress/views.py

+import warnings
+
 from django.conf import settings
 from django.contrib.auth.decorators import login_required
 from django.http import HttpResponse, HttpResponseRedirect
         charset = settings.DEFAULT_CHARSET
 
     # 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,
                                 cls=DjangoJSONEncoder,
                                 ensure_ascii=False)
     "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'))
 
-def raw_post_data(request):
-    "A view that is requested with GET and accesses request.raw_post_data. Refs #14753."
-    return HttpResponse(request.raw_post_data)
+def body(request):
+    "A view that is requested with GET and accesses request.body. Refs #14753."
+    return HttpResponse(request.body)
 
 def read_all(request):
     "A view that is requested with accesses request.read()."