Refs #33173 -- Removed use of deprecated cgi module.
https://peps.python.org/pep-0594/#cgi
This commit is contained in:
parent
02dbf1667c
commit
34e2148fc7
|
@ -1,5 +1,4 @@
|
|||
import argparse
|
||||
import cgi
|
||||
import mimetypes
|
||||
import os
|
||||
import posixpath
|
||||
|
@ -15,6 +14,7 @@ from django.core.management.base import BaseCommand, CommandError
|
|||
from django.core.management.utils import handle_extensions, run_formatters
|
||||
from django.template import Context, Engine
|
||||
from django.utils import archive
|
||||
from django.utils.http import parse_header_parameters
|
||||
from django.utils.version import get_docs_version
|
||||
|
||||
|
||||
|
@ -327,7 +327,7 @@ class TemplateCommand(BaseCommand):
|
|||
# Trying to get better name from response headers
|
||||
content_disposition = headers["content-disposition"]
|
||||
if content_disposition:
|
||||
_, params = cgi.parse_header(content_disposition)
|
||||
_, params = parse_header_parameters(content_disposition)
|
||||
guessed_filename = params.get("filename") or used_name
|
||||
else:
|
||||
guessed_filename = used_name
|
||||
|
|
|
@ -6,7 +6,6 @@ file upload handlers for processing.
|
|||
"""
|
||||
import base64
|
||||
import binascii
|
||||
import cgi
|
||||
import collections
|
||||
import html
|
||||
from urllib.parse import unquote
|
||||
|
@ -20,6 +19,7 @@ from django.core.exceptions import (
|
|||
from django.core.files.uploadhandler import SkipFile, StopFutureHandlers, StopUpload
|
||||
from django.utils.datastructures import MultiValueDict
|
||||
from django.utils.encoding import force_str
|
||||
from django.utils.regex_helper import _lazy_re_compile
|
||||
|
||||
__all__ = ("MultiPartParser", "MultiPartParserError", "InputStreamExhausted")
|
||||
|
||||
|
@ -49,6 +49,8 @@ class MultiPartParser:
|
|||
and returns a tuple of ``(MultiValueDict(POST), MultiValueDict(FILES))``.
|
||||
"""
|
||||
|
||||
boundary_re = _lazy_re_compile(rb"[ -~]{0,200}[!-~]")
|
||||
|
||||
def __init__(self, META, input_data, upload_handlers, encoding=None):
|
||||
"""
|
||||
Initialize the MultiPartParser object.
|
||||
|
@ -77,7 +79,7 @@ class MultiPartParser:
|
|||
% force_str(content_type)
|
||||
)
|
||||
boundary = opts.get("boundary")
|
||||
if not boundary or not cgi.valid_boundary(boundary):
|
||||
if not boundary or not self.boundary_re.fullmatch(boundary):
|
||||
raise MultiPartParserError(
|
||||
"Invalid boundary in multipart: %s" % force_str(boundary)
|
||||
)
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import cgi
|
||||
import codecs
|
||||
import copy
|
||||
from io import BytesIO
|
||||
|
@ -22,7 +21,7 @@ from django.utils.datastructures import (
|
|||
)
|
||||
from django.utils.encoding import escape_uri_path, iri_to_uri
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.http import is_same_domain
|
||||
from django.utils.http import is_same_domain, parse_header_parameters
|
||||
from django.utils.regex_helper import _lazy_re_compile
|
||||
|
||||
from .multipartparser import parse_header
|
||||
|
@ -97,7 +96,7 @@ class HttpRequest:
|
|||
|
||||
def _set_content_type_params(self, meta):
|
||||
"""Set content_type, content_params, and encoding."""
|
||||
self.content_type, self.content_params = cgi.parse_header(
|
||||
self.content_type, self.content_params = parse_header_parameters(
|
||||
meta.get("CONTENT_TYPE", "")
|
||||
)
|
||||
if "charset" in self.content_params:
|
||||
|
|
|
@ -366,3 +366,36 @@ def escape_leading_slashes(url):
|
|||
if url.startswith("//"):
|
||||
url = "/%2F{}".format(url[2:])
|
||||
return url
|
||||
|
||||
|
||||
def _parseparam(s):
|
||||
while s[:1] == ";":
|
||||
s = s[1:]
|
||||
end = s.find(";")
|
||||
while end > 0 and (s.count('"', 0, end) - s.count('\\"', 0, end)) % 2:
|
||||
end = s.find(";", end + 1)
|
||||
if end < 0:
|
||||
end = len(s)
|
||||
f = s[:end]
|
||||
yield f.strip()
|
||||
s = s[end:]
|
||||
|
||||
|
||||
def parse_header_parameters(line):
|
||||
"""
|
||||
Parse a Content-type like header.
|
||||
Return the main content-type and a dictionary of options.
|
||||
"""
|
||||
parts = _parseparam(";" + line)
|
||||
key = parts.__next__()
|
||||
pdict = {}
|
||||
for p in parts:
|
||||
i = p.find("=")
|
||||
if i >= 0:
|
||||
name = p[:i].strip().lower()
|
||||
value = p[i + 1 :].strip()
|
||||
if len(value) >= 2 and value[0] == value[-1] == '"':
|
||||
value = value[1:-1]
|
||||
value = value.replace("\\\\", "\\").replace('\\"', '"')
|
||||
pdict[name] = value
|
||||
return key, pdict
|
||||
|
|
|
@ -12,6 +12,7 @@ from django.utils.http import (
|
|||
int_to_base36,
|
||||
is_same_domain,
|
||||
parse_etags,
|
||||
parse_header_parameters,
|
||||
parse_http_date,
|
||||
quote_etag,
|
||||
url_has_allowed_host_and_scheme,
|
||||
|
@ -435,3 +436,39 @@ class EscapeLeadingSlashesTests(unittest.TestCase):
|
|||
for url, expected in tests:
|
||||
with self.subTest(url=url):
|
||||
self.assertEqual(escape_leading_slashes(url), expected)
|
||||
|
||||
|
||||
class ParseHeaderParameterTests(unittest.TestCase):
|
||||
def test_basic(self):
|
||||
tests = [
|
||||
("text/plain", ("text/plain", {})),
|
||||
("text/vnd.just.made.this.up ; ", ("text/vnd.just.made.this.up", {})),
|
||||
("text/plain;charset=us-ascii", ("text/plain", {"charset": "us-ascii"})),
|
||||
(
|
||||
'text/plain ; charset="us-ascii"',
|
||||
("text/plain", {"charset": "us-ascii"}),
|
||||
),
|
||||
(
|
||||
'text/plain ; charset="us-ascii"; another=opt',
|
||||
("text/plain", {"charset": "us-ascii", "another": "opt"}),
|
||||
),
|
||||
(
|
||||
'attachment; filename="silly.txt"',
|
||||
("attachment", {"filename": "silly.txt"}),
|
||||
),
|
||||
(
|
||||
'attachment; filename="strange;name"',
|
||||
("attachment", {"filename": "strange;name"}),
|
||||
),
|
||||
(
|
||||
'attachment; filename="strange;name";size=123;',
|
||||
("attachment", {"filename": "strange;name", "size": "123"}),
|
||||
),
|
||||
(
|
||||
'form-data; name="files"; filename="fo\\"o;bar"',
|
||||
("form-data", {"name": "files", "filename": 'fo"o;bar'}),
|
||||
),
|
||||
]
|
||||
for header, expected in tests:
|
||||
with self.subTest(header=header):
|
||||
self.assertEqual(parse_header_parameters(header), expected)
|
||||
|
|
Loading…
Reference in New Issue