Skip to content

Commit c375e15

Browse files
committed
Wrap exceptions caused by parsers in ParseError in request wrapper
1 parent 4d06626 commit c375e15

File tree

2 files changed

+23
-1
lines changed

2 files changed

+23
-1
lines changed

rest_framework/request.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,14 +356,17 @@ def _parse(self):
356356

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

369372
# Parser classes may return the raw data, or a

tests/test_request.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
from rest_framework import status
2020
from rest_framework.authentication import SessionAuthentication
21+
from rest_framework.exceptions import ParseError
2122
from rest_framework.parsers import BaseParser, FormParser, MultiPartParser
2223
from rest_framework.request import Request, WrappedAttributeError
2324
from rest_framework.response import Response
@@ -52,6 +53,13 @@ def parse(self, stream, media_type=None, parser_context=None):
5253
return stream.read()
5354

5455

56+
class BrokenParser(BaseParser):
57+
media_type = 'text/plain'
58+
59+
def parse(self, stream, media_type=None, parser_context=None):
60+
raise AttributeError
61+
62+
5563
class TestContentParsing(TestCase):
5664
def test_standard_behaviour_determines_no_content_GET(self):
5765
"""
@@ -126,6 +134,17 @@ def test_standard_behaviour_determines_non_form_content_PUT(self):
126134
request.parsers = (PlainTextParser(), )
127135
assert request.data == content
128136

137+
def test_request_data_with_broken_parser(self):
138+
"""
139+
Ensure request.data raise ParseError if anything went wrong during parsing
140+
"""
141+
content = b'qwerty'
142+
content_type = 'text/plain'
143+
request = Request(factory.post('/', content, content_type=content_type))
144+
request.parsers = (BrokenParser(), )
145+
with self.assertRaises(ParseError):
146+
request.data
147+
129148

130149
class MockView(APIView):
131150
authentication_classes = (SessionAuthentication,)

0 commit comments

Comments
 (0)