Wrap exceptions caused by parsers in ParseError in request wrapper

This commit is contained in:
sevdog 2024-06-28 18:27:05 +02:00
parent 4d0662663a
commit c375e155a3
No known key found for this signature in database
GPG Key ID: D939AF7A93A9C178
2 changed files with 23 additions and 1 deletions

View File

@ -356,7 +356,7 @@ class Request:
try: try:
parsed = parser.parse(stream, media_type, self.parser_context) 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 # If we get an exception during parsing, fill in empty data and
# re-raise. Ensures we don't simply repeat the error when # re-raise. Ensures we don't simply repeat the error when
# attempting to render the browsable renderer response, or when # attempting to render the browsable renderer response, or when
@ -364,6 +364,9 @@ class Request:
self._data = QueryDict('', encoding=self._request._encoding) self._data = QueryDict('', encoding=self._request._encoding)
self._files = MultiValueDict() self._files = MultiValueDict()
self._full_data = self._data self._full_data = self._data
if isinstance(exc, AttributeError):
raise exceptions.ParseError(str(exc))
raise raise
# Parser classes may return the raw data, or a # Parser classes may return the raw data, or a

View File

@ -18,6 +18,7 @@ from django.urls import path
from rest_framework import status from rest_framework import status
from rest_framework.authentication import SessionAuthentication from rest_framework.authentication import SessionAuthentication
from rest_framework.exceptions import ParseError
from rest_framework.parsers import BaseParser, FormParser, MultiPartParser from rest_framework.parsers import BaseParser, FormParser, MultiPartParser
from rest_framework.request import Request, WrappedAttributeError from rest_framework.request import Request, WrappedAttributeError
from rest_framework.response import Response from rest_framework.response import Response
@ -52,6 +53,13 @@ class PlainTextParser(BaseParser):
return stream.read() 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): class TestContentParsing(TestCase):
def test_standard_behaviour_determines_no_content_GET(self): def test_standard_behaviour_determines_no_content_GET(self):
""" """
@ -126,6 +134,17 @@ class TestContentParsing(TestCase):
request.parsers = (PlainTextParser(), ) request.parsers = (PlainTextParser(), )
assert request.data == content 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): class MockView(APIView):
authentication_classes = (SessionAuthentication,) authentication_classes = (SessionAuthentication,)