mirror of
https://github.com/blender/blender
synced 2026-09-29 04:37:17 +03:00
Python: add size limit to HTTP downloader
Add an option to the HTTP downloader that sets a size limit (in bytes).
Any download that's larger than this will be rejected with a
`ContentLengthTooBigError` exception.
This is useful to prevent Blender from choking on the parsing of huge
JSON files, which can be served relatively cheaply via compression
techniques.
```py
from _bpy_internal.http import downloader as http_dl
downloader = http_dl.ConditionalDownloader(
metadata_provider=metadata_provider)
downloader.max_size_bytes = 100
downloader.download_to_file("https://example.com/huge.json",
Path("/tmp/huge.json"))
```
The `DownloaderOptions` dataclass has also been extended with a
`max_size_bytes` parameter, so that this can be passed to the background
downloader process as well.
Note: the HTTP downloader is not used in Blender 5.1 (it's intended
for the Remote Asset Libraries in 5.2). However, since this can be
considered a fix for a security issue (potential DOS of Blender), I
feel it's still warranted to include this in 5.1. See !154464 for this
change in context.
Pull Request: https://projects.blender.org/blender/blender/pulls/155259
This commit is contained in:
parent
61f26af3fa
commit
705ff33bc0
2 changed files with 54 additions and 1 deletions
|
|
@ -3,7 +3,7 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
"""
|
||||
blender -b --factory-startup -P tests/python/bl_http_downloader.py -- output-dir /tmp/should-not-exist --verbose
|
||||
blender -b --factory-startup -P tests/python/bl_http_downloader.py -- --verbose
|
||||
"""
|
||||
|
||||
|
||||
|
|
@ -62,6 +62,32 @@ class BasicImportTest(unittest.TestCase):
|
|||
self.assertFalse(downloader.is_subprocess_alive)
|
||||
|
||||
|
||||
class MaxDownloadSizeTest(unittest.TestCase):
|
||||
def test_max_size(self) -> None:
|
||||
from _bpy_internal.http import downloader as http_dl
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
metadata_provider = MagicMock(spec=http_dl.MetadataProvider)
|
||||
metadata_provider.load.return_value = None
|
||||
|
||||
downloader = http_dl.ConditionalDownloader(metadata_provider=metadata_provider)
|
||||
downloader.max_size_bytes = 100
|
||||
|
||||
mock_response = MagicMock()
|
||||
mock_response.headers = {"Content-Length": "200", "Content-Type": "text/plain"}
|
||||
mock_response.status_code = 200
|
||||
# When used as context manager, return itself.
|
||||
mock_response.__enter__.return_value = mock_response
|
||||
|
||||
# NOTE: when this test fails, it will say "TypeError: a bytes-like object is required, not 'MagicMock'". This
|
||||
# indicates that the HTTP downloader tried to actually read bytes from the mock response, which it doesn't
|
||||
# support.
|
||||
|
||||
with patch.object(http_dl.requests.Session, 'send', return_value=mock_response):
|
||||
with self.assertRaises(http_dl.ContentLengthTooBigError):
|
||||
downloader.download_to_file("https://example.com/huge.json", Path("/tmp/huge.json"))
|
||||
|
||||
|
||||
class BackgroundDownloaderProcessTest(unittest.TestCase):
|
||||
"""Start & stop the background process for the BackgroundDownloader.
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue