mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-25 11:04:02 +03:00
Fallback behavior for request parsing when request.POST already accessed. (#4500)
This commit is contained in:
parent
e82ee91078
commit
be74d11165
|
@ -15,6 +15,7 @@ import sys
|
|||
from django.conf import settings
|
||||
from django.http import QueryDict
|
||||
from django.http.multipartparser import parse_header
|
||||
from django.http.request import RawPostDataException
|
||||
from django.utils import six
|
||||
from django.utils.datastructures import MultiValueDict
|
||||
|
||||
|
@ -263,10 +264,20 @@ class Request(object):
|
|||
|
||||
if content_length == 0:
|
||||
self._stream = None
|
||||
elif hasattr(self._request, 'read'):
|
||||
elif not self._request._read_started:
|
||||
self._stream = self._request
|
||||
else:
|
||||
self._stream = six.BytesIO(self.raw_post_data)
|
||||
self._stream = six.BytesIO(self.body)
|
||||
|
||||
def _supports_form_parsing(self):
|
||||
"""
|
||||
Return True if this requests supports parsing form data.
|
||||
"""
|
||||
form_media = (
|
||||
'application/x-www-form-urlencoded',
|
||||
'multipart/form-data'
|
||||
)
|
||||
return any([parser.media_type in form_media for parser in self.parsers])
|
||||
|
||||
def _parse(self):
|
||||
"""
|
||||
|
@ -274,8 +285,18 @@ class Request(object):
|
|||
|
||||
May raise an `UnsupportedMediaType`, or `ParseError` exception.
|
||||
"""
|
||||
stream = self.stream
|
||||
media_type = self.content_type
|
||||
try:
|
||||
stream = self.stream
|
||||
except RawPostDataException:
|
||||
if not hasattr(self._request, '_post'):
|
||||
raise
|
||||
# If request.POST has been accessed in middleware, and a method='POST'
|
||||
# request was made with 'multipart/form-data', then the request stream
|
||||
# will already have been exhausted.
|
||||
if self._supports_form_parsing():
|
||||
return (self._request.POST, self._request.FILES)
|
||||
stream = None
|
||||
|
||||
if stream is None or media_type is None:
|
||||
empty_data = QueryDict('', encoding=self._request._encoding)
|
||||
|
|
|
@ -7,11 +7,16 @@ from django import forms
|
|||
from django.core.files.uploadhandler import (
|
||||
MemoryFileUploadHandler, TemporaryFileUploadHandler
|
||||
)
|
||||
from django.http.request import RawPostDataException
|
||||
from django.test import TestCase
|
||||
from django.utils.six.moves import StringIO
|
||||
|
||||
from rest_framework.exceptions import ParseError
|
||||
from rest_framework.parsers import FileUploadParser, FormParser
|
||||
from rest_framework.parsers import (
|
||||
FileUploadParser, FormParser, JSONParser, MultiPartParser
|
||||
)
|
||||
from rest_framework.request import Request
|
||||
from rest_framework.test import APIRequestFactory
|
||||
|
||||
|
||||
class Form(forms.Form):
|
||||
|
@ -122,3 +127,39 @@ class TestFileUploadParser(TestCase):
|
|||
|
||||
def __replace_content_disposition(self, disposition):
|
||||
self.parser_context['request'].META['HTTP_CONTENT_DISPOSITION'] = disposition
|
||||
|
||||
|
||||
class TestPOSTAccessed(TestCase):
|
||||
def setUp(self):
|
||||
self.factory = APIRequestFactory()
|
||||
|
||||
def test_post_accessed_in_post_method(self):
|
||||
django_request = self.factory.post('/', {'foo': 'bar'})
|
||||
request = Request(django_request, parsers=[FormParser(), MultiPartParser()])
|
||||
django_request.POST
|
||||
assert request.POST == {'foo': ['bar']}
|
||||
assert request.data == {'foo': ['bar']}
|
||||
|
||||
def test_post_accessed_in_post_method_with_json_parser(self):
|
||||
django_request = self.factory.post('/', {'foo': 'bar'})
|
||||
request = Request(django_request, parsers=[JSONParser()])
|
||||
django_request.POST
|
||||
assert request.POST == {}
|
||||
assert request.data == {}
|
||||
|
||||
def test_post_accessed_in_put_method(self):
|
||||
django_request = self.factory.put('/', {'foo': 'bar'})
|
||||
request = Request(django_request, parsers=[FormParser(), MultiPartParser()])
|
||||
django_request.POST
|
||||
assert request.POST == {'foo': ['bar']}
|
||||
assert request.data == {'foo': ['bar']}
|
||||
|
||||
def test_request_read_before_parsing(self):
|
||||
django_request = self.factory.put('/', {'foo': 'bar'})
|
||||
request = Request(django_request, parsers=[FormParser(), MultiPartParser()])
|
||||
django_request.read()
|
||||
with pytest.raises(RawPostDataException):
|
||||
request.POST
|
||||
with pytest.raises(RawPostDataException):
|
||||
request.POST
|
||||
request.data
|
||||
|
|
Loading…
Reference in New Issue
Block a user