Files
2025-10-03 11:29:31 +09:00

159 lines
5.6 KiB
Python

"""
ComfyUI ProxyFix Extension
This extension fixes the URL encoding issue when ComfyUI is accessed through
jupyter-server-proxy or other reverse proxies that decode URL-encoded slashes.
The fix works in two parts:
1. Frontend (JavaScript): Converts workflows/ to workflows__SLASH__ in API calls
2. Backend (Python): Converts workflows__SLASH__ back to workflows/ before processing
The __SLASH__ separator is unique and won't conflict with user filenames.
"""
import os
from aiohttp import web
# Tell ComfyUI where to find our web extension files
WEB_DIRECTORY = "./web"
# ComfyUI requires these exports even if we don't define any custom nodes
NODE_CLASS_MAPPINGS = {}
NODE_DISPLAY_NAME_MAPPINGS = {}
# Unique separator that matches the frontend (must be identical)
SLASH_REPLACEMENT = '__SLASH__'
# Debug mode: set environment variable DEBUG_PROXYFIX=1 to enable verbose logging
DEBUG = os.environ.get('DEBUG_PROXYFIX', '').lower() in ('1', 'true', 'yes')
def _log(message):
"""Log message if debug mode is enabled"""
if DEBUG:
print(f"[ComfyUI-ProxyFix] {message}")
def convert_workflow_path_back(path):
"""
Converts all remaining __SLASH__ markers back to / in the path.
Examples:
'workflows__SLASH__test.json' -> 'workflows/test.json'
'userdata/workflows__SLASH__my_flow.json' -> 'userdata/workflows/my_flow.json'
'workflows__SLASH__foo__SLASH__bar.json' -> 'workflows/foo/bar.json'
"""
if SLASH_REPLACEMENT in path:
# Convert all __SLASH__ markers back to /
path = path.replace(SLASH_REPLACEMENT, '/')
return path
@web.middleware
async def proxy_fix_middleware(request, handler):
"""
aiohttp middleware to convert workflows__SLASH__ back to workflows/ in request paths.
"""
original_path = str(request.rel_url.path) if hasattr(request.rel_url, 'path') else request.path
# Only process userdata requests that contain workflows__SLASH__
if '/userdata/' in original_path and SLASH_REPLACEMENT in original_path:
_log(f"Processing request: {original_path}")
# Wrap handler to modify match_info after routing
async def fixed_handler(req):
from aiohttp.web_urldispatcher import MatchInfoError
# Check if routing was successful (not a 404)
if not isinstance(req.match_info, MatchInfoError):
# Convert all match_info values containing __SLASH__
for key in list(req.match_info.keys()):
value = req.match_info[key]
if isinstance(value, str) and SLASH_REPLACEMENT in value:
new_value = convert_workflow_path_back(value)
_log(f"Converting match_info['{key}']: {value} -> {new_value}")
# Update match_info
try:
req.match_info[key] = new_value
except Exception as e:
_log(f"Error updating match_info: {e}")
# Call the actual handler
return await handler(req)
return await fixed_handler(request)
# For non-userdata requests, process normally
return await handler(request)
def apply_middleware():
"""
Apply the proxy fix middleware to the ComfyUI server.
"""
try:
import server
# Get the PromptServer instance
if hasattr(server, 'PromptServer') and hasattr(server.PromptServer, 'instance'):
prompt_server = server.PromptServer.instance
if prompt_server is not None and hasattr(prompt_server, 'app'):
app = prompt_server.app
# Apply middleware if not already applied
if proxy_fix_middleware not in app.middlewares:
app.middlewares.insert(0, proxy_fix_middleware)
print("[ComfyUI-ProxyFix] Middleware applied successfully")
return True
else:
_log("Middleware already applied")
return True
_log("Warning: Could not find PromptServer instance")
return False
except ImportError:
_log("server module not found (might load later)")
return False
except Exception as e:
print(f"[ComfyUI-ProxyFix] Error applying middleware: {e}")
return False
# Try to apply middleware immediately
middleware_applied = apply_middleware()
if not middleware_applied:
# Delay initialization to ensure ComfyUI server is loaded
import threading
import time
def delayed_init():
"""Retry applying middleware after a delay"""
max_retries = 3
retry_delay = 1
for attempt in range(max_retries):
time.sleep(retry_delay)
_log(f"Retry {attempt + 1}/{max_retries}: Attempting to apply middleware...")
if apply_middleware():
print("[ComfyUI-ProxyFix] Middleware applied after delayed retry")
return
print("[ComfyUI-ProxyFix] Warning: Failed to apply middleware after all retries")
print("[ComfyUI-ProxyFix] Frontend fix will still work for most cases")
thread = threading.Thread(target=delayed_init, daemon=True)
thread.start()
# Print confirmation that the extension is loaded
print("[ComfyUI-ProxyFix] Extension loaded")
if DEBUG:
print(f"[ComfyUI-ProxyFix] Debug mode enabled")
print(f"[ComfyUI-ProxyFix] Web directory: {WEB_DIRECTORY}")
print(f"[ComfyUI-ProxyFix] Using separator: {SLASH_REPLACEMENT}")
__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS', 'WEB_DIRECTORY']