File fix-cve-2022-36359.patch of Package python-Django.18746
Index: Django-2.2.28/django/http/response.py
===================================================================
--- Django-2.2.28.orig/django/http/response.py
+++ Django-2.2.28/django/http/response.py
@@ -442,7 +442,9 @@ class FileResponse(StreamingHttpResponse
if filename:
try:
filename.encode('ascii')
- file_expr = 'filename="{}"'.format(filename)
+ file_expr = 'filename="{}"'.format(
+ filename.replace('\\', '\\\\').replace('"', r'\"')
+ )
except UnicodeEncodeError:
file_expr = "filename*=utf-8''{}".format(quote(filename))
self['Content-Disposition'] = 'attachment; {}'.format(file_expr)
Index: Django-2.2.28/tests/responses/test_fileresponse.py
===================================================================
--- Django-2.2.28.orig/tests/responses/test_fileresponse.py
+++ Django-2.2.28/tests/responses/test_fileresponse.py
@@ -71,3 +71,38 @@ class FileResponseTests(SimpleTestCase):
response['Content-Disposition'],
"attachment; filename*=utf-8''%E7%A5%9D%E6%82%A8%E5%B9%B3%E5%AE%89.odt"
)
+
+ def test_content_disposition_escaping(self):
+ # fmt: off
+ tests = [
+ (
+ 'multi-part-one";\" dummy".txt',
+ r"multi-part-one\";\" dummy\".txt"
+ ),
+ ]
+ # fmt: on
+ # Non-escape sequence backslashes are path segments on Windows, and are
+ # eliminated by an os.path.basename() check in FileResponse.
+ if sys.platform != "win32":
+ # fmt: off
+ tests += [
+ (
+ 'multi-part-one\\";\" dummy".txt',
+ r"multi-part-one\\\";\" dummy\".txt"
+ ),
+ (
+ 'multi-part-one\\";\\\" dummy".txt',
+ r"multi-part-one\\\";\\\" dummy\".txt"
+ )
+ ]
+ # fmt: on
+ for filename, escaped in tests:
+ with self.subTest(filename=filename, escaped=escaped):
+ response = FileResponse(
+ io.BytesIO(b"binary content"), filename=filename, as_attachment=True
+ )
+ response.close()
+ self.assertEqual(
+ response["Content-Disposition"],
+ f'attachment; filename="{escaped}"',
+ )