fix: stabilize generated ZIP download for large archives
Some checks failed
ERP CI/CD Pipeline / test (push) Has been cancelled
ERP CI/CD Pipeline / Deploy (server git pull + compose) (push) Has been cancelled

Avoid HTTP/2 streaming failures on large archive downloads by returning the stored ZIP as a buffered HttpResponse with explicit Content-Length.

Also update archive download tests to support both buffered and streaming response objects.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
mariomitte
2026-08-06 11:17:15 +02:00
parent 456c9e4c3e
commit 18c65a6f84
2 changed files with 10 additions and 3 deletions

View File

@@ -351,7 +351,7 @@ class WorkOrderImagesEndpointTests(TestCase):
download_response = self.client.get(f"/api/fleet/reports/generated-archives/{generated.pk}/download/") download_response = self.client.get(f"/api/fleet/reports/generated-archives/{generated.pk}/download/")
self.assertEqual(download_response.status_code, 200) self.assertEqual(download_response.status_code, 200)
self.assertEqual(download_response['Content-Type'], 'application/zip') self.assertEqual(download_response['Content-Type'], 'application/zip')
archive_bytes = b''.join(download_response.streaming_content) archive_bytes = download_response.content if hasattr(download_response, 'content') else b''.join(download_response.streaming_content)
archive = zipfile.ZipFile(BytesIO(archive_bytes)) archive = zipfile.ZipFile(BytesIO(archive_bytes))
self.assertIn('MT150726.SN-Test_servisni_zadatak.docx', archive.namelist()) self.assertIn('MT150726.SN-Test_servisni_zadatak.docx', archive.namelist())
@@ -392,7 +392,7 @@ class WorkOrderImagesEndpointTests(TestCase):
download_response = self.client.get(f"/api/fleet/reports/generated-archives/{generated.pk}/download/") download_response = self.client.get(f"/api/fleet/reports/generated-archives/{generated.pk}/download/")
self.assertEqual(download_response.status_code, 200) self.assertEqual(download_response.status_code, 200)
self.assertEqual(download_response['Content-Type'], 'application/zip') self.assertEqual(download_response['Content-Type'], 'application/zip')
archive_bytes = b''.join(download_response.streaming_content) archive_bytes = download_response.content if hasattr(download_response, 'content') else b''.join(download_response.streaming_content)
archive = zipfile.ZipFile(BytesIO(archive_bytes)) archive = zipfile.ZipFile(BytesIO(archive_bytes))
names = archive.namelist() names = archive.namelist()

View File

@@ -3063,15 +3063,22 @@ def generated_archive_download(request, archive_id):
raise DRFValidationError({'detail': 'ZIP arhiva nije dostupna ili je istekla.'}) raise DRFValidationError({'detail': 'ZIP arhiva nije dostupna ili je istekla.'})
generated_archive.file.open('rb') generated_archive.file.open('rb')
try:
archive_bytes = generated_archive.file.read()
finally:
generated_archive.file.close()
if not archive_bytes:
raise DRFValidationError({'detail': 'ZIP arhiva je prazna ili nedostupna.'})
filename = generated_archive.filename or _generated_archive_filename_for_user( filename = generated_archive.filename or _generated_archive_filename_for_user(
request.user, request.user,
year=generated_archive.year, year=generated_archive.year,
month=generated_archive.month, month=generated_archive.month,
archive_type=generated_archive.archive_type, archive_type=generated_archive.archive_type,
) )
response = FileResponse(generated_archive.file, content_type='application/zip') response = HttpResponse(archive_bytes, content_type='application/zip')
response['Content-Disposition'] = f'attachment; filename="{filename}"' response['Content-Disposition'] = f'attachment; filename="{filename}"'
response['Cache-Control'] = 'private, max-age=3600' response['Cache-Control'] = 'private, max-age=3600'
response['Content-Length'] = str(len(archive_bytes))
return response return response