Created
June 25, 2026 13:09
-
-
Save t-book/cba464714f475011f44eb9ac7436a78d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| tonischonbuchner@MacBook-Pro-von-Toni ~/dev/github/csgis/QFieldCloud $% git diff | |
| diff --git a/docker-app/qfieldcloud/filestorage/backend.py b/docker-app/qfieldcloud/filestorage/backend.py | |
| index 7854ddcb..0b5aab18 100644 | |
| --- a/docker-app/qfieldcloud/filestorage/backend.py | |
| +++ b/docker-app/qfieldcloud/filestorage/backend.py | |
| @@ -25,12 +25,17 @@ class QfcBackendStorageMixin(ABC): | |
| "Subclassing QFC specific storages must implement this method." | |
| ) | |
| - def patch_nginx_download_redirect(self, response: HttpResponse) -> None: | |
| + def patch_nginx_download_redirect( | |
| + self, response: HttpResponse, content_disposition: str | None = None | |
| + ) -> None: | |
| """Patches a nginx redirect response for usage with the storage backend. | |
| At the moment, does nothing. | |
| Arguments: | |
| response: HTTP redirect response to patch. | |
| + content_disposition: optional Content-Disposition header value to | |
| + forward to the client (used by backends that cannot set it on | |
| + the storage object itself, e.g. WebDAV). | |
| """ | |
| pass | |
| @@ -51,12 +56,16 @@ class QfcS3Boto3Storage(QfcBackendStorageMixin, S3Storage): | |
| return True | |
| - def patch_nginx_download_redirect(self, response: HttpResponse) -> None: | |
| + def patch_nginx_download_redirect( | |
| + self, response: HttpResponse, content_disposition: str | None = None | |
| + ) -> None: | |
| """Patches a nginx redirect response for usage with S3. | |
| - At the moment, does nothing. | |
| + Does nothing: S3 sets Content-Disposition via the presigned URL | |
| + response parameters, so no nginx-level forwarding is required. | |
| Arguments: | |
| response: HTTP redirect response to patch. | |
| + content_disposition: ignored for S3 (handled by presigned URL). | |
| """ | |
| pass | |
| @@ -284,16 +293,22 @@ class QfcWebDavStorage(QfcBackendStorageMixin, Storage): | |
| """ | |
| return self.get_public_url(name) | |
| - def patch_nginx_download_redirect(self, response: HttpResponse) -> None: | |
| + def patch_nginx_download_redirect( | |
| + self, response: HttpResponse, content_disposition: str | None = None | |
| + ) -> None: | |
| """Patches a nginx redirect response for usage with WebDAV. | |
| Adds configured webdav/HTTP basic auth, required for nginx redirect. | |
| + Optionally forwards a Content-Disposition value to the client, since | |
| + WebDAV cannot set it on the stored object itself. | |
| Arguments: | |
| response: HTTP redirect response to patch. | |
| + content_disposition: optional Content-Disposition header value. | |
| """ | |
| b64_auth = base64.b64encode(self.basic_auth.encode()).decode() | |
| - basic_auth = f"Basic {b64_auth}" | |
| - response["webdav_auth"] = basic_auth | |
| + response["webdav_auth"] = f"Basic {b64_auth}" | |
| + if content_disposition: | |
| + response["webdav_content_disposition"] = content_disposition | |
| def get_available_name(self, name: str, max_length: int | None = None) -> str: | |
| """Returns a filename that is available on the configured webdav storage. | |
| diff --git a/docker-app/qfieldcloud/filestorage/view_helpers.py b/docker-app/qfieldcloud/filestorage/view_helpers.py | |
| index 865d67f5..3ff6e323 100644 | |
| --- a/docker-app/qfieldcloud/filestorage/view_helpers.py | |
| +++ b/docker-app/qfieldcloud/filestorage/view_helpers.py | |
| @@ -306,6 +306,7 @@ def download_field_file( | |
| if_unmodified_since_int, tz=tz.utc | |
| ) | |
| + response_content_disposition: str | None = None | |
| if as_attachment: | |
| parameters.update( | |
| { | |
| @@ -313,6 +314,7 @@ def download_field_file( | |
| "ResponseContentDisposition": f'attachment;filename="{filename}"', | |
| } | |
| ) | |
| + response_content_disposition = f'attachment; filename="{filename}"' | |
| url = field_file.storage.url( | |
| storage_filename, | |
| @@ -330,7 +332,9 @@ def download_field_file( | |
| if range: | |
| response["file_range"] = range.header | |
| - field_file.storage.patch_nginx_download_redirect(response) # type: ignore | |
| + field_file.storage.patch_nginx_download_redirect( | |
| + response, content_disposition=response_content_disposition | |
| + ) # type: ignore | |
| return response | |
| elif settings.DEBUG or settings.IN_TEST_SUITE: | |
| diff --git a/docker-nginx/templates/includes/qfieldcloud.conf.template b/docker-nginx/templates/includes/qfieldcloud.conf.template | |
| index 5bce54c1..0165fadb 100644 | |
| --- a/docker-nginx/templates/includes/qfieldcloud.conf.template | |
| +++ b/docker-nginx/templates/includes/qfieldcloud.conf.template | |
| @@ -70,6 +70,9 @@ location /storage-download/ { | |
| set $webdav_auth "$upstream_http_webdav_auth"; | |
| # if a Range header is provided | |
| set $file_range "$upstream_http_file_range"; | |
| + # webdav storage cannot set Content-Disposition on the object itself; | |
| + # the app forwards it via this header so we can return it to the client. | |
| + set $webdav_content_disposition "$upstream_http_webdav_content_disposition"; | |
| # Add Docker's DNS resolver with IPv6 turned off | |
| resolver 127.0.0.11 ipv6=off; | |
| @@ -113,6 +116,12 @@ location /storage-download/ { | |
| proxy_intercept_errors on; | |
| + # Return the app-provided Content-Disposition (filename) to the client. | |
| + # Hide any Content-Disposition coming from the storage upstream first, | |
| + # so we don't end up with a duplicate / wrong one. | |
| + proxy_hide_header Content-Disposition; | |
| + add_header Content-Disposition $webdav_content_disposition; | |
| + | |
| proxy_pass $redirect_uri; | |
| error_page 404 =404 /pages/404.html; | |
| error_page 403 =403 /pages/403.html; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment