From a5e4db99fba9a7c526ab1f9524e84409c720cdd5 Mon Sep 17 00:00:00 2001 From: thomas girod Date: Mon, 5 Aug 2024 00:36:29 +0200 Subject: [PATCH] Use X-Accel-Redirect to send files in prod --- core/views/files.py | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/core/views/files.py b/core/views/files.py index 6bc76a5e..52474b55 100644 --- a/core/views/files.py +++ b/core/views/files.py @@ -12,6 +12,7 @@ # OR WITHIN THE LOCAL FILE "LICENSE" # # +from urllib.parse import quote # This file contains all the views that concern the page model from wsgiref.util import FileWrapper @@ -45,10 +46,13 @@ def send_file( file_id: int, file_class: type[SithFile] = SithFile, file_attr: str = "file", -): - """Send a file through Django without loading the whole file into - memory at once. The FileWrapper will turn the file object into an - iterator for chunks of 8KB. +) -> HttpResponse: + """Send a protected file, if the user can see it. + + In prod, the server won't handle the download itself, + but set the appropriate headers in the response to make the reverse-proxy + deal with it. + In debug mode, the server will directly send the file. """ f = get_object_or_404(file_class, id=file_id) if not can_view(f, request.user) and not sent_from_logged_counter(request): @@ -60,6 +64,16 @@ def send_file( if not filepath.exists(): raise Http404 + if not settings.DEBUG: + # When receiving a response with the Accel-Redirect header, + # the reverse proxy will automatically handle the file sending. + # This is really hard to test (thus isn't tested) + # so please do not mess with this. + response = HttpResponse(status=200) + response["Content-Type"] = "" + response["X-Accel-Redirect"] = f"/data/{quote(name)}" + return response + with open(filepath, "rb") as filename: wrapper = FileWrapper(filename) response = HttpResponse(wrapper, content_type=f.mime_type)