mirror of
https://github.com/django/django.git
synced 2025-06-05 03:29:12 +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:
parent
9c37103a98
commit
11920e7795
@ -7,6 +7,7 @@ from urllib.parse import parse_qsl, quote, urlencode, urljoin, urlsplit
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core import signing
|
from django.core import signing
|
||||||
from django.core.exceptions import (
|
from django.core.exceptions import (
|
||||||
|
BadRequest,
|
||||||
DisallowedHost,
|
DisallowedHost,
|
||||||
ImproperlyConfigured,
|
ImproperlyConfigured,
|
||||||
RequestDataTooBig,
|
RequestDataTooBig,
|
||||||
@ -377,10 +378,16 @@ class HttpRequest:
|
|||||||
self._mark_post_parse_error()
|
self._mark_post_parse_error()
|
||||||
raise
|
raise
|
||||||
elif self.content_type == "application/x-www-form-urlencoded":
|
elif self.content_type == "application/x-www-form-urlencoded":
|
||||||
self._post, self._files = (
|
# According to RFC 1866, the "application/x-www-form-urlencoded"
|
||||||
QueryDict(self.body, encoding=self._encoding),
|
# content type does not have a charset and should be always treated
|
||||||
MultiValueDict(),
|
# 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:
|
else:
|
||||||
self._post, self._files = (
|
self._post, self._files = (
|
||||||
QueryDict(encoding=self._encoding),
|
QueryDict(encoding=self._encoding),
|
||||||
|
@ -580,6 +580,10 @@ Miscellaneous
|
|||||||
* Executing SQL queries before the app registry has been fully populated now
|
* Executing SQL queries before the app registry has been fully populated now
|
||||||
raises :exc:`RuntimeWarning`.
|
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:
|
.. _deprecated-features-5.0:
|
||||||
|
|
||||||
Features deprecated in 5.0
|
Features deprecated in 5.0
|
||||||
|
@ -3,7 +3,7 @@ from io import BytesIO
|
|||||||
from itertools import chain
|
from itertools import chain
|
||||||
from urllib.parse import urlencode
|
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.core.handlers.wsgi import LimitedStream, WSGIRequest
|
||||||
from django.http import (
|
from django.http import (
|
||||||
HttpHeaders,
|
HttpHeaders,
|
||||||
@ -369,10 +369,7 @@ class RequestsTests(SimpleTestCase):
|
|||||||
)
|
)
|
||||||
self.assertEqual(request.POST, {"key": ["España"]})
|
self.assertEqual(request.POST, {"key": ["España"]})
|
||||||
|
|
||||||
def test_alternate_charset_POST(self):
|
def test_non_utf8_charset_POST_bad_request(self):
|
||||||
"""
|
|
||||||
Test a POST with non-utf-8 payload encoding.
|
|
||||||
"""
|
|
||||||
payload = FakePayload(urlencode({"key": "España".encode("latin-1")}))
|
payload = FakePayload(urlencode({"key": "España".encode("latin-1")}))
|
||||||
request = WSGIRequest(
|
request = WSGIRequest(
|
||||||
{
|
{
|
||||||
@ -382,7 +379,30 @@ class RequestsTests(SimpleTestCase):
|
|||||||
"wsgi.input": payload,
|
"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):
|
def test_body_after_POST_multipart_form_data(self):
|
||||||
"""
|
"""
|
||||||
@ -694,18 +714,31 @@ class RequestsTests(SimpleTestCase):
|
|||||||
request.body
|
request.body
|
||||||
|
|
||||||
def test_set_encoding_clears_POST(self):
|
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 = WSGIRequest(
|
||||||
{
|
{
|
||||||
"REQUEST_METHOD": "POST",
|
"REQUEST_METHOD": "POST",
|
||||||
"CONTENT_TYPE": "application/x-www-form-urlencoded",
|
"CONTENT_TYPE": MULTIPART_CONTENT,
|
||||||
"CONTENT_LENGTH": len(payload),
|
"CONTENT_LENGTH": len(payload),
|
||||||
"wsgi.input": payload,
|
"wsgi.input": payload,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
self.assertEqual(request.POST, {"name": ["Hello Günter"]})
|
self.assertEqual(request.POST, {"name": ["Hello Günter"]})
|
||||||
request.encoding = "iso-8859-16"
|
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):
|
def test_set_encoding_clears_GET(self):
|
||||||
payload = FakePayload("")
|
payload = FakePayload("")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user