Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions comfy_api_nodes/util/_helpers.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
import asyncio
import contextlib
import os
import re
import time
from collections.abc import Callable
from io import BytesIO

from yarl import URL

from comfy.cli_args import args
from comfy.model_management import processing_interrupted
from comfy_api.latest import IO

from .common_exceptions import ProcessingInterrupted

_HAS_PCT_ESC = re.compile(r"%[0-9A-Fa-f]{2}") # any % followed by 2 hex digits
_HAS_BAD_PCT = re.compile(r"%(?![0-9A-Fa-f]{2})") # any % not followed by 2 hex digits


def is_processing_interrupted() -> bool:
"""Return True if user/runtime requested interruption."""
Expand Down Expand Up @@ -69,3 +75,17 @@ def get_fs_object_size(path_or_object: str | BytesIO) -> int:
if isinstance(path_or_object, str):
return os.path.getsize(path_or_object)
return len(path_or_object.getvalue())


def to_aiohttp_url(url: str) -> URL:
"""If `url` appears to be already percent-encoded (contains at least one valid %HH
escape and no malformed '%' sequences) and contains no raw whitespace/control
characters preserve the original encoding byte-for-byte (important for signed/presigned URLs).
Otherwise, return `URL(url)` and allow yarl to normalize/quote as needed."""
if any(c.isspace() for c in url) or any(ord(c) < 0x20 for c in url):
# Avoid encoded=True if URL contains raw whitespace/control chars
return URL(url)
if _HAS_PCT_ESC.search(url) and not _HAS_BAD_PCT.search(url):
# Preserve encoding only if it appears pre-encoded AND has no invalid % sequences
return URL(url, encoded=True)
return URL(url)
3 changes: 2 additions & 1 deletion comfy_api_nodes/util/download_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
get_auth_header,
is_processing_interrupted,
sleep_with_interrupt,
to_aiohttp_url,
)
from .client import _diagnose_connectivity
from .common_exceptions import ApiServerError, LocalNetworkError, ProcessingInterrupted
Expand Down Expand Up @@ -94,7 +95,7 @@ async def _monitor():

monitor_task = asyncio.create_task(_monitor())

req_task = asyncio.create_task(session.get(url, headers=headers))
req_task = asyncio.create_task(session.get(to_aiohttp_url(url), headers=headers))
done, pending = await asyncio.wait({req_task, monitor_task}, return_when=asyncio.FIRST_COMPLETED)

if monitor_task in done and req_task in pending:
Expand Down
Loading