Files
upstream-zulip/zerver/upload_handler.py
upstream-mirror 64898b2c79
Some checks failed
Code scanning / CodeQL (push) Failing after 15s
Zulip production suite / Ubuntu 22.04 production build (push) Failing after 26s
Zulip production suite / Debian 12 production install with custom db name and user (push) Has been skipped
Zulip production suite / Ubuntu 22.04 production install and PostgreSQL upgrade with pgroonga (push) Has been skipped
Zulip production suite / Ubuntu 24.04 production install (push) Has been skipped
Zulip production suite / Ubuntu 26.04 production install (push) Has been skipped
Zulip production suite / Debian 13 production install (push) Has been skipped
Zulip production suite / 7.0 Version Upgrade (push) Has been skipped
Zulip production suite / 8.0 Version Upgrade (push) Has been skipped
Zulip production suite / 6.0 Version Upgrade (push) Has been skipped
Zulip production suite / 10.0 Version Upgrade (push) Has been skipped
Zulip production suite / 9.0 Version Upgrade (push) Has been skipped
Zulip production suite / 12.0 Version Upgrade (push) Has been skipped
Zulip production suite / 11.0 Version Upgrade (push) Has been skipped
GitHub Actions Security Analysis with zizmor / zizmor (push) Failing after 3s
Zulip CI / Debian 12 (Python 3.11, backend + documentation) (push) Failing after 26s
Zulip CI / Ubuntu 22.04 (Python 3.10, backend + frontend) (push) Failing after 3s
Zulip CI / Ubuntu 24.04 (Python 3.12, backend) (push) Failing after 25s
Zulip CI / Ubuntu 26.04 (Python 3.14, backend) (push) Failing after 25s
Zulip CI / Debian 13 (Python 3.13, backend) (push) Failing after 28s
Zulip production suite / Required jobs (push) Has been cancelled
Zulip CI / Required jobs (push) Has been cancelled
API Documentation Update Check / check-feature-level-updated (push) Has been cancelled
API Documentation Update Check / notify-if-api-docs-changed (push) Has been cancelled
snapshot of https://github.com/zulip/zulip.git @ 48c69911c7dd4e03b20552eb3bd77ad8151c1357 (2026-09-15)
2026-09-15 15:05:30 +05:00

61 lines
2.3 KiB
Python

import os
import tempfile
from django.core.files.uploadhandler import TemporaryFileUploadHandler
from typing_extensions import override
# Django spools each uploaded file to a temporary file named
# f"{tempfile.gettempprefix()}{8 random characters}.upload{extension}",
# where the extension is taken verbatim from the client-provided filename.
#
# Since a filename is limited to NAME_MAX (255) bytes, a sufficiently
# long extension makes creating that temporary file fail with
# 'OSError: [Errno 36] File name too long', which Django does not handle.
TEMPORARY_FILE_MAX_EXTENSION_LENGTH = 255 - len(tempfile.gettempprefix()) - 8 - len(".upload")
def truncate_filename_extension(filename: str) -> str:
"""Shortens filename extensions that are too long to fit in the name of
the temporary file Django spools an upload to. NAME_MAX limits bytes
rather than characters, so we truncate the encoded extension and discard
any character left partially encoded at the end.
"""
root, extension = os.path.splitext(filename)
encoded_extension = extension.encode()
if len(encoded_extension) <= TEMPORARY_FILE_MAX_EXTENSION_LENGTH:
return filename
return root + encoded_extension[:TEMPORARY_FILE_MAX_EXTENSION_LENGTH].decode(errors="ignore")
class ZulipTemporaryFileUploadHandler(TemporaryFileUploadHandler):
"""Django's TemporaryFileUploadHandler, made tolerant of filenames whose
extension alone exceeds what the filesystem allows in a filename.
Django does sanitize an over-long filename, in UploadedFile._set_name,
but only after creating the temporary file whose name embeds the
extension; shortening the extension is therefore something we have to do
beforehand. The cap is far longer than any extension in practice.
This workaround can go away once https://code.djangoproject.com/ticket/37292
is fixed upstream.
"""
@override
def new_file(
self,
field_name: str,
file_name: str,
content_type: str,
content_length: int | None,
charset: str | None = None,
content_type_extra: dict[str, bytes] | None = None,
) -> None:
super().new_file(
field_name,
truncate_filename_extension(file_name),
content_type,
content_length,
charset,
content_type_extra,
)