From c61129590d239bef4d4da24b413527c8d6490223 Mon Sep 17 00:00:00 2001 From: Harry Date: Fri, 6 Feb 2026 16:32:45 +0800 Subject: [PATCH] fix: improve download filename handling in S3 storage and asset service --- api/core/sandbox/inspector/archive_source.py | 4 +++- api/extensions/storage/aws_s3_storage.py | 9 ++++----- api/services/app_asset_service.py | 4 +--- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/api/core/sandbox/inspector/archive_source.py b/api/core/sandbox/inspector/archive_source.py index e4cd00451d..92c7213826 100644 --- a/api/core/sandbox/inspector/archive_source.py +++ b/api/core/sandbox/inspector/archive_source.py @@ -158,7 +158,9 @@ class SandboxFileArchiveSource(SandboxFileSource): except PipelineExecutionError as exc: raise RuntimeError(str(exc)) from exc - download_url = sandbox_storage.get_download_url(export_key, self._EXPORT_EXPIRES_IN_SECONDS) + download_url = sandbox_storage.get_download_url( + export_key, self._EXPORT_EXPIRES_IN_SECONDS, download_filename=filename + ) return SandboxFileDownloadTicket( download_url=download_url, diff --git a/api/extensions/storage/aws_s3_storage.py b/api/extensions/storage/aws_s3_storage.py index 129e512bdf..a450153f5c 100644 --- a/api/extensions/storage/aws_s3_storage.py +++ b/api/extensions/storage/aws_s3_storage.py @@ -122,11 +122,10 @@ class AwsS3Storage(BaseStorage): downloads the file with this name instead of the S3 key. """ params: dict = {"Bucket": self.bucket_name, "Key": filename} - if download_filename: - # RFC 5987 / RFC 6266: Use both filename and filename* for compatibility. - # filename* with UTF-8 encoding handles non-ASCII characters. - encoded = quote(download_filename) - params["ResponseContentDisposition"] = f"attachment; filename=\"{encoded}\"; filename*=UTF-8''{encoded}" + # RFC 5987 / RFC 6266: Use both filename and filename* for compatibility. + # filename* with UTF-8 encoding handles non-ASCII characters. + encoded = quote(download_filename or filename) + params["ResponseContentDisposition"] = f"attachment; filename=\"{encoded}\"; filename*=UTF-8''{encoded}" url: str = self.client.generate_presigned_url( ClientMethod="get_object", Params=params, diff --git a/api/services/app_asset_service.py b/api/services/app_asset_service.py index bb975fa118..72db0dd473 100644 --- a/api/services/app_asset_service.py +++ b/api/services/app_asset_service.py @@ -363,9 +363,7 @@ class AppAssetService: ) -> str: with Session(db.engine) as session: assets = AppAssetService.get_or_create_assets(session, app_model, account_id) - tree = assets.asset_tree - - node = tree.get(node_id) + node = assets.asset_tree.get(node_id) if not node or node.node_type != AssetNodeType.FILE: raise AppAssetNodeNotFoundError(f"File node {node_id} not found")