1
0
mirror of https://github.com/django/django.git synced 2024-12-22 17:16:24 +00:00

Fixed #34709 -- Raised BadRequest for non-UTF-8 requests with the application/x-www-form-urlencoded content type.

Thanks Eki Xu for the report.
This commit is contained in:
Mariusz Felisiak 2023-08-25 21:27:22 +02:00 committed by GitHub
parent 9c37103a98
commit 11920e7795
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 57 additions and 13 deletions

View File

@ -7,6 +7,7 @@ from urllib.parse import parse_qsl, quote, urlencode, urljoin, urlsplit
from django.conf import settings
from django.core import signing
from django.core.exceptions import (
BadRequest,
DisallowedHost,
ImproperlyConfigured,
RequestDataTooBig,
@ -377,10 +378,16 @@ class HttpRequest:
self._mark_post_parse_error()
raise
elif self.content_type == "application/x-www-form-urlencoded":
self._post, self._files = (
QueryDict(self.body, encoding=self._encoding),
MultiValueDict(),
)
# According to RFC 1866, the "application/x-www-form-urlencoded"
# content type does not have a charset and should be always treated
# as UTF-8.
if self._encoding is not None and self._encoding.lower() != "utf-8":
raise BadRequest(
"HTTP requests with the 'application/x-www-form-urlencoded' "
"content type must be UTF-8 encoded."
)
self._post = QueryDict(self.body, encoding="utf-8")
self._files = MultiValueDict()
else:
self._post, self._files = (
QueryDict(encoding=self._encoding),

View File

@ -580,6 +580,10 @@ Miscellaneous
* Executing SQL queries before the app registry has been fully populated now
raises :exc:`RuntimeWarning`.
* :exc:`~django.core.exceptions.BadRequest` is raised for non-UTF-8 encoded
requests with the :mimetype:`application/x-www-form-urlencoded` content type.
See :rfc:`1866` for more details.
.. _deprecated-features-5.0:
Features deprecated in 5.0

View File

@ -3,7 +3,7 @@ from io import BytesIO
from itertools import chain
from urllib.parse import urlencode
from django.core.exceptions import DisallowedHost
from django.core.exceptions import BadRequest, DisallowedHost
from django.core.handlers.wsgi import LimitedStream, WSGIRequest
from django.http import (
HttpHeaders,
@ -369,10 +369,7 @@ class RequestsTests(SimpleTestCase):
)
self.assertEqual(request.POST, {"key": ["España"]})
def test_alternate_charset_POST(self):
"""
Test a POST with non-utf-8 payload encoding.
"""
def test_non_utf8_charset_POST_bad_request(self):
payload = FakePayload(urlencode({"key": "España".encode("latin-1")}))
request = WSGIRequest(
{
@ -382,7 +379,30 @@ class RequestsTests(SimpleTestCase):
"wsgi.input": payload,
}
)
self.assertEqual(request.POST, {"key": ["España"]})
msg = (
"HTTP requests with the 'application/x-www-form-urlencoded' content type "
"must be UTF-8 encoded."
)
with self.assertRaisesMessage(BadRequest, msg):
request.POST
with self.assertRaisesMessage(BadRequest, msg):
request.FILES
def test_utf8_charset_POST(self):
for charset in ["utf-8", "UTF-8"]:
with self.subTest(charset=charset):
payload = FakePayload(urlencode({"key": "España"}))
request = WSGIRequest(
{
"REQUEST_METHOD": "POST",
"CONTENT_LENGTH": len(payload),
"CONTENT_TYPE": (
f"application/x-www-form-urlencoded; charset={charset}"
),
"wsgi.input": payload,
}
)
self.assertEqual(request.POST, {"key": ["España"]})
def test_body_after_POST_multipart_form_data(self):
"""
@ -694,18 +714,31 @@ class RequestsTests(SimpleTestCase):
request.body
def test_set_encoding_clears_POST(self):
payload = FakePayload("name=Hello Günter")
payload = FakePayload(
"\r\n".join(
[
f"--{BOUNDARY}",
'Content-Disposition: form-data; name="name"',
"",
"Hello Günter",
f"--{BOUNDARY}--",
"",
]
)
)
request = WSGIRequest(
{
"REQUEST_METHOD": "POST",
"CONTENT_TYPE": "application/x-www-form-urlencoded",
"CONTENT_TYPE": MULTIPART_CONTENT,
"CONTENT_LENGTH": len(payload),
"wsgi.input": payload,
}
)
self.assertEqual(request.POST, {"name": ["Hello Günter"]})
request.encoding = "iso-8859-16"
self.assertEqual(request.POST, {"name": ["Hello GĂŒnter"]})
# FIXME: POST should be accessible after changing the encoding
# (refs #14035).
# self.assertEqual(request.POST, {"name": ["Hello GĂŒnter"]})
def test_set_encoding_clears_GET(self):
payload = FakePayload("")