diff --git a/server.py b/server.py index 881da8e66..aaab13b8b 100644 --- a/server.py +++ b/server.py @@ -54,6 +54,31 @@ if args.enable_manager: import comfyui_manager +def _make_content_disposition(filename: str, disposition: str = "inline") -> str: + """ + Generate RFC 8187 compliant Content-Disposition header. + + According to RFC 8187, the filename parameter should use the extended notation + with 'filename*=' and 'utf-8'' language tag when the filename contains non-ASCII + characters or needs special encoding. + + Examples: + ASCII: inline; filename="test.png"; filename*=UTF-8''test.png + Unicode: inline; filename="__.png"; filename*=UTF-8''%E6%B5%8B%E8%AF%95.png + """ + import urllib.parse + + # Create ASCII-safe fallback filename + fallback = "".join( + ch if 0x20 <= ord(ch) < 0x7F and ch not in {'"', '\\'} else "_" + for ch in filename + ) or "download" + + # Percent-encode the UTF-8 filename + encoded_filename = urllib.parse.quote(filename, safe='') + return f"{disposition}; filename=\"{fallback}\"; filename*=UTF-8''{encoded_filename}" + + def _remove_sensitive_from_queue(queue: list) -> list: """Remove sensitive data (index 5) from queue item tuples.""" return [item[:5] for item in queue] @@ -559,7 +584,7 @@ class PromptServer(): buffer.seek(0) return web.Response(body=buffer.read(), content_type=f'image/{image_format}', - headers={"Content-Disposition": f"filename=\"{filename}\""}) + headers={"Content-Disposition": _make_content_disposition(filename)}) if 'channel' not in request.rel_url.query: channel = 'rgba' @@ -579,7 +604,7 @@ class PromptServer(): buffer.seek(0) return web.Response(body=buffer.read(), content_type='image/png', - headers={"Content-Disposition": f"filename=\"{filename}\""}) + headers={"Content-Disposition": _make_content_disposition(filename)}) elif channel == 'a': with Image.open(file) as img: @@ -596,7 +621,7 @@ class PromptServer(): alpha_buffer.seek(0) return web.Response(body=alpha_buffer.read(), content_type='image/png', - headers={"Content-Disposition": f"filename=\"{filename}\""}) + headers={"Content-Disposition": _make_content_disposition(filename)}) else: # Use the content type from asset resolution if available, # otherwise guess from the filename. @@ -613,7 +638,7 @@ class PromptServer(): return web.FileResponse( file, headers={ - "Content-Disposition": f"filename=\"{filename}\"", + "Content-Disposition": _make_content_disposition(filename), "Content-Type": content_type } )