1
0
mirror of https://github.com/django/django.git synced 2025-04-12 03:22:21 +00:00

Added FormParser and MultiPartParser

This commit is contained in:
David Smith 2023-11-28 21:04:04 +00:00
parent 9e7ac58901
commit caab50bb85
3 changed files with 77 additions and 34 deletions
django/http
tests/requests_tests

53
django/http/parsers.py Normal file

@ -0,0 +1,53 @@
from io import BytesIO
from django.core.exceptions import BadRequest
from django.http.multipartparser import MultiPartParser as _MultiPartParser
from django.utils.datastructures import ImmutableList, MultiValueDict
class BaseParser:
media_type = None
def parse(self, request):
pass
class FormParser(BaseParser):
media_type = "application/x-www-form-urlencoded"
def parse(self, request):
from django.http import QueryDict
# 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 request._encoding is not None and request._encoding.lower() != "utf-8":
raise BadRequest(
"HTTP requests with the 'application/x-www-form-urlencoded' "
"content type must be UTF-8 encoded."
)
return QueryDict(request.body, encoding="utf-8"), MultiValueDict()
class MultiPartParser(BaseParser):
media_type = "multipart/form-data"
def parse(self, request):
if hasattr(request, "_body"):
# Use already read data
data = BytesIO(request._body)
else:
data = request
request.upload_handlers = ImmutableList(
request.upload_handlers,
warning=(
"You cannot alter upload handlers after the upload has been "
"processed."
),
)
parser = _MultiPartParser(
request.META, data, request.upload_handlers, request.encoding
)
_post, _files = parser.parse()
return _post, _files

@ -7,18 +7,14 @@ 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,
TooManyFieldsSent,
)
from django.core.files import uploadhandler
from django.http.multipartparser import (
MultiPartParser,
MultiPartParserError,
TooManyFilesSent,
)
from django.http import parsers
from django.http.multipartparser import MultiPartParser
from django.utils.datastructures import (
CaseInsensitiveMapping,
ImmutableList,
@ -362,32 +358,26 @@ class HttpRequest:
self._mark_post_parse_error()
return
if self.content_type == "multipart/form-data":
if hasattr(self, "_body"):
# Use already read data
data = BytesIO(self._body)
else:
data = self
# TODO create a parsers setter/getter/initializer like upload_handlers
parser_list = (parsers.FormParser(), parsers.MultiPartParser())
selected_parser = None
for parser in parser_list:
if self.content_type == parser.media_type:
selected_parser = parser
break
if selected_parser:
try:
self._post, self._files = self.parse_file_upload(self.META, data)
except (MultiPartParserError, TooManyFilesSent):
self._post, self._files = parser.parse(self)
except Exception as e:
# TODO 'application/x-www-form-urlencoded' didn't do this.
# An error occurred while parsing POST data. Since when
# formatting the error the request handler might access
# self.POST, set self._post and self._file to prevent
# attempts to parse POST data again.
self._mark_post_parse_error()
raise
elif self.content_type == "application/x-www-form-urlencoded":
# 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()
raise e
else:
self._post, self._files = (
QueryDict(encoding=self._encoding),

@ -387,20 +387,20 @@ class RequestsTests(SimpleTestCase):
def test_non_utf8_charset_POST_bad_request(self):
payload = FakePayload(urlencode({"key": "España".encode("latin-1")}))
request = WSGIRequest(
{
"REQUEST_METHOD": "POST",
"CONTENT_LENGTH": len(payload),
"CONTENT_TYPE": "application/x-www-form-urlencoded; charset=iso-8859-1",
"wsgi.input": payload,
}
)
environ = {
"REQUEST_METHOD": "POST",
"CONTENT_LENGTH": len(payload),
"CONTENT_TYPE": "application/x-www-form-urlencoded; charset=iso-8859-1",
"wsgi.input": payload,
}
request = WSGIRequest(environ)
msg = (
"HTTP requests with the 'application/x-www-form-urlencoded' content type "
"must be UTF-8 encoded."
)
with self.assertRaisesMessage(BadRequest, msg):
request.POST
request = WSGIRequest(environ)
with self.assertRaisesMessage(BadRequest, msg):
request.FILES