From c375e155a3245c80af32bc330858661f1b2ef0df Mon Sep 17 00:00:00 2001 From: sevdog Date: Fri, 28 Jun 2024 18:27:05 +0200 Subject: [PATCH] Wrap exceptions caused by parsers in ParseError in request wrapper --- rest_framework/request.py | 5 ++++- tests/test_request.py | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/rest_framework/request.py b/rest_framework/request.py index b29e64d16..26c96cffa 100644 --- a/rest_framework/request.py +++ b/rest_framework/request.py @@ -356,7 +356,7 @@ class Request: 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 @@ -364,6 +364,9 @@ class Request: 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 diff --git a/tests/test_request.py b/tests/test_request.py index e37aa7dda..8b8aa4d23 100644 --- a/tests/test_request.py +++ b/tests/test_request.py @@ -18,6 +18,7 @@ from django.urls import path 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 @@ -52,6 +53,13 @@ class PlainTextParser(BaseParser): 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): """ @@ -126,6 +134,17 @@ class TestContentParsing(TestCase): 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,)