Merge remote-tracking branch 'origin/pr/5236'

This commit is contained in:
Florian Bruhin 2020-07-27 16:53:22 +02:00
commit 60dae30aa0
3 changed files with 46 additions and 2 deletions

View File

@ -230,9 +230,16 @@ def suggested_fn_from_title(url_path, title=None):
suggested_fn = None # type: typing.Optional[str]
if ext.lower() in ext_whitelist and title:
suggested_fn = utils.sanitize_filename(title)
suggested_fn = utils.sanitize_filename(
title,
max_bytes=(255 - len("(123).download"))
)
if not suggested_fn.lower().endswith((".html", ".htm")):
suggested_fn += ".html"
suggested_fn = utils.sanitize_filename(
suggested_fn,
max_bytes=(255 - len("(123).download"))
)
return suggested_fn

View File

@ -520,7 +520,8 @@ def force_encoding(text: str, encoding: str) -> str:
def sanitize_filename(name: str,
replacement: typing.Optional[str] = '_') -> str:
replacement: typing.Optional[str] = '_',
max_bytes: typing.Optional[int] = None) -> str:
"""Replace invalid filename characters.
Note: This should be used for the basename, as it also removes the path
@ -529,6 +530,7 @@ def sanitize_filename(name: str,
Args:
name: The filename.
replacement: The replacement character (or None).
max_bytes: The biggest length in bytes allowed (or None, which is ).
"""
if replacement is None:
replacement = ''
@ -550,6 +552,34 @@ def sanitize_filename(name: str,
for bad_char in bad_chars:
name = name.replace(bad_char, replacement)
if max_bytes:
# Truncate the filename if it's too long.
root, ext = os.path.splitext(name)
root = root[:max_bytes - len(ext)]
excess = len(os.fsencode(root + ext)) - max_bytes
while excess > 0 and root:
# Max 4 bytes per character is assumed.
# Integer division floors to -∞, not to 0.
root = root[:(-excess // 4)]
excess = len(os.fsencode(root + ext)) - max_bytes
if not root:
# Trimming the root is not enough. We must trim the extension.
# We leave one character in the root, so that the filename
# doesn't start with a dot, which makes the file hidden.
root = name[0]
excess = len(os.fsencode(root + ext)) - max_bytes
while excess > 0 and ext:
ext = ext[:(-excess // 4)]
excess = len(os.fsencode(root + ext)) - max_bytes
if not ext:
raise ValueError("max_bytes is too small")
name = root + ext
return name

View File

@ -644,6 +644,13 @@ def test_sanitize_filename_empty_replacement():
assert utils.sanitize_filename(name, replacement=None) == 'Bad File'
@hypothesis.given(filename=strategies.text(min_size=100),
max_bytes=strategies.integers(min_value=50))
def test_sanitize_filename_invariants(filename, max_bytes):
sanitized = utils.sanitize_filename(filename, max_bytes=max_bytes)
assert len(os.fsencode(sanitized)) <= max_bytes
class TestGetSetClipboard:
@pytest.fixture(autouse=True)