From 00ea883ef56fb5e092cbe4a6f7ff2e7470886ac4 Mon Sep 17 00:00:00 2001 From: Virtosu Bogdan Date: Fri, 23 Jul 2021 12:26:22 +0200 Subject: [PATCH] Fixed #32329 -- Made CsrfViewMiddleware catch more specific UnreadablePostError. Thanks Chris Jerdonek for the review. --- django/middleware/csrf.py | 3 ++- tests/csrf_tests/tests.py | 22 +++++++++++++++++----- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/django/middleware/csrf.py b/django/middleware/csrf.py index d103900bdf..f8b8cf1ca0 100644 --- a/django/middleware/csrf.py +++ b/django/middleware/csrf.py @@ -11,6 +11,7 @@ from urllib.parse import urlparse from django.conf import settings from django.core.exceptions import DisallowedHost, ImproperlyConfigured +from django.http import UnreadablePostError from django.http.request import HttpHeaders from django.urls import get_callable from django.utils.cache import patch_vary_headers @@ -342,7 +343,7 @@ class CsrfViewMiddleware(MiddlewareMixin): if request.method == 'POST': try: request_csrf_token = request.POST.get('csrfmiddlewaretoken', '') - except OSError: + except UnreadablePostError: # Handle a broken connection before we've completed reading the # POST data. process_view shouldn't raise any exceptions, so # we'll ignore and serve the user a 403 (assuming they're still diff --git a/tests/csrf_tests/tests.py b/tests/csrf_tests/tests.py index e823ff11ee..6ec0c6326a 100644 --- a/tests/csrf_tests/tests.py +++ b/tests/csrf_tests/tests.py @@ -3,7 +3,7 @@ import re from django.conf import settings from django.contrib.sessions.backends.cache import SessionStore from django.core.exceptions import ImproperlyConfigured -from django.http import HttpRequest, HttpResponse +from django.http import HttpRequest, HttpResponse, UnreadablePostError from django.middleware.csrf import ( CSRF_ALLOWED_CHARS, CSRF_SESSION_KEY, CSRF_TOKEN_LENGTH, REASON_BAD_ORIGIN, REASON_CSRF_TOKEN_MISSING, REASON_NO_CSRF_COOKIE, CsrfViewMiddleware, @@ -728,10 +728,10 @@ class CsrfViewMiddlewareTestMixin: req = self._get_request() ensure_csrf_cookie_view(req) - def test_post_data_read_failure(self): + def test_reading_post_data_raises_unreadable_post_error(self): """ - OSErrors during POST data reading are caught and treated as if the - POST data wasn't there. + An UnreadablePostError raised while reading the POST data should be + handled by the middleware. """ req = self._get_POST_request_with_token() mw = CsrfViewMiddleware(post_form_view) @@ -740,7 +740,7 @@ class CsrfViewMiddlewareTestMixin: self.assertIsNone(resp) req = self._get_POST_request_with_token(request_class=PostErrorRequest) - req.post_error = OSError('error reading input data') + req.post_error = UnreadablePostError('Error reading input data.') mw.process_request(req) with self.assertLogs('django.security.csrf', 'WARNING') as cm: resp = mw.process_view(req, post_form_view, (), {}) @@ -750,6 +750,18 @@ class CsrfViewMiddlewareTestMixin: 'Forbidden (%s): ' % REASON_CSRF_TOKEN_MISSING, ) + def test_reading_post_data_raises_os_error(self): + """ + An OSError raised while reading the POST data should not be handled by + the middleware. + """ + mw = CsrfViewMiddleware(post_form_view) + req = self._get_POST_request_with_token(request_class=PostErrorRequest) + req.post_error = OSError('Deleted directories/Missing permissions.') + mw.process_request(req) + with self.assertRaises(OSError): + mw.process_view(req, post_form_view, (), {}) + @override_settings(ALLOWED_HOSTS=['www.example.com']) def test_bad_origin_bad_domain(self): """A request with a bad origin is rejected."""