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:
parent
9e7ac58901
commit
caab50bb85
53
django/http/parsers.py
Normal file
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
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user