From 4669adf4951e58073fd456cf13bc82355dfafd5d Mon Sep 17 00:00:00 2001 From: Piero Toffanin Date: Thu, 18 Jul 2024 15:11:25 -0400 Subject: [PATCH 1/2] Use StreamingHttpResponse when downloading zip streams --- app/api/tasks.py | 11 +++++++++-- app/vendor/zipfly.py | 13 ++++++++----- package.json | 2 +- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/app/api/tasks.py b/app/api/tasks.py index c65e94253..2d60e38d8 100644 --- a/app/api/tasks.py +++ b/app/api/tasks.py @@ -11,6 +11,8 @@ from django.db import transaction from django.http import FileResponse from django.http import HttpResponse +from django.http import StreamingHttpResponse +from app.vendor import zipfly from rest_framework import status, serializers, viewsets, filters, exceptions, permissions, parsers from rest_framework.decorators import action from rest_framework.permissions import AllowAny @@ -340,8 +342,13 @@ def download_file_response(request, filePath, content_disposition, download_file def download_file_stream(request, stream, content_disposition, download_filename=None): - response = HttpResponse(FileWrapper(stream), - content_type=(mimetypes.guess_type(download_filename)[0] or "application/zip")) + if isinstance(stream, zipfly.ZipStream): + f = stream.generator() + else: + # This should never happen, but just in case.. + raise exceptions.ValidationError("stream not a zipstream instance") + + response = StreamingHttpResponse(f, content_type=(mimetypes.guess_type(download_filename)[0] or "application/zip")) response['Content-Type'] = mimetypes.guess_type(download_filename)[0] or "application/zip" response['Content-Disposition'] = "{}; filename={}".format(content_disposition, download_filename) diff --git a/app/vendor/zipfly.py b/app/vendor/zipfly.py index 35a64c6d2..108023ac5 100644 --- a/app/vendor/zipfly.py +++ b/app/vendor/zipfly.py @@ -46,7 +46,6 @@ def get(self): def size(self): return self._size - class ZipFly: def __init__(self, @@ -280,13 +279,17 @@ def get_size(self): class ZipStream: def __init__(self, paths): self.paths = paths - self.generator = None + self._generator = None def lazy_load(self, chunksize): - if self.generator is None: + if self._generator is None: zfly = ZipFly(paths=self.paths, mode='w', chunksize=chunksize) - self.generator = zfly.generator() + self._generator = zfly.generator() def read(self, count): self.lazy_load(count) - return next(self.generator) \ No newline at end of file + return next(self._generator) + + def generator(self): + self.lazy_load(0x8000) + return self._generator \ No newline at end of file diff --git a/package.json b/package.json index 64f311481..010ce4562 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "WebODM", - "version": "2.5.3", + "version": "2.5.4", "description": "User-friendly, extendable application and API for processing aerial imagery.", "main": "index.js", "scripts": { From def6a59675dd1d8a701fafe7e64780c926428694 Mon Sep 17 00:00:00 2001 From: Piero Toffanin Date: Thu, 18 Jul 2024 15:38:55 -0400 Subject: [PATCH 2/2] Fix tests --- app/tests/test_api_task_import.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/tests/test_api_task_import.py b/app/tests/test_api_task_import.py index 04e2bf82e..9dc04d10e 100644 --- a/app/tests/test_api_task_import.py +++ b/app/tests/test_api_task_import.py @@ -74,7 +74,7 @@ def test_task(self): assets_path = os.path.join(settings.MEDIA_TMP, "all.zip") with open(assets_path, 'wb') as f: - f.write(res.content) + f.write(b''.join(res.streaming_content)) remove_perm('change_project', user, project) @@ -272,7 +272,7 @@ def test_backup(self): assets_path = os.path.join(settings.MEDIA_TMP, "backup.zip") with open(assets_path, 'wb') as f: - f.write(res.content) + f.write(b''.join(res.streaming_content)) assets_file = open(assets_path, 'rb')