Skip to content

Commit

Permalink
Wrap exceptions caused by parsers in ParseError in request wrapper
Browse files Browse the repository at this point in the history
  • Loading branch information
sevdog committed Jun 28, 2024
1 parent 4d06626 commit 3640913
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 1 deletion.
5 changes: 4 additions & 1 deletion rest_framework/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -356,14 +356,17 @@ def _parse(self):

try:
parsed = parser.parse(stream, media_type, self.parser_context)
except Exception:
except Exception as exc:
# If we get an exception during parsing, fill in empty data and
# re-raise. Ensures we don't simply repeat the error when
# attempting to render the browsable renderer response, or when
# logging the request or similar.
self._data = QueryDict('', encoding=self._request._encoding)
self._files = MultiValueDict()
self._full_data = self._data
if isinstance(exc, AttributeError):
raise exceptions.ParseError(str(exc))

raise

# Parser classes may return the raw data, or a
Expand Down
21 changes: 21 additions & 0 deletions tests/test_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

from rest_framework import status
from rest_framework.authentication import SessionAuthentication
from rest_framework.exceptions import ParseError
from rest_framework.parsers import BaseParser, FormParser, MultiPartParser
from rest_framework.request import Request, WrappedAttributeError
from rest_framework.response import Response
Expand Down Expand Up @@ -52,6 +53,14 @@ def parse(self, stream, media_type=None, parser_context=None):
return stream.read()



class BrokenParser(BaseParser):
media_type = 'text/plain'

def parse(self, stream, media_type=None, parser_context=None):
raise AttributeError


class TestContentParsing(TestCase):
def test_standard_behaviour_determines_no_content_GET(self):
"""
Expand Down Expand Up @@ -126,6 +135,18 @@ def test_standard_behaviour_determines_non_form_content_PUT(self):
request.parsers = (PlainTextParser(), )
assert request.data == content

def test_request_data_with_broken_parser(self):
"""
Ensure request.data raise ParseError if anything went wrong during parsing
"""
content = b'qwerty'
content_type = 'text/plain'
request = Request(factory.post('/', content, content_type=content_type))
request.parsers = (BrokenParser(), )
with self.assertRaises(ParseError):
request.data



class MockView(APIView):
authentication_classes = (SessionAuthentication,)
Expand Down

0 comments on commit 3640913

Please sign in to comment.