Files
Isulion-ComfyUI_Isulion/Core_Nodes/net_utils.py
T
Isulion fc903d4acf refactor!: v6.0.0 — seeding, sandbox FS, decorator registry, security
Breaking changes:
- Same seeds now yield different prompts than 5.x (reproducibility fixed)
- Civitai Trending: removed broken 'model' filter widget
- Shutdown node is a no-op unless ISULION_ENABLE_SHUTDOWN=1

Highlights:
- Seeding: all 109 theme handlers share the seeded ConfigManager PRNG
  (284 global random.* call sites migrated); same seed => same prompt
- Theme registry rewritten with @register_theme decorators; removed
  HANDLER_CLASS_NAMES_MAP, star-imports and globals() lookups
- Shared ThemeRegistry singleton: INPUT_TYPES no longer re-reads ~100
  JSON files per call (2.6ms -> 0.003ms cached)
- load_images_node: paths sandboxed to ComfyUI input dir, deterministic
  sha1 IS_CHANGED, PIL context managers, no bare excepts
- Overlay node: full batch support, base channel count preserved
  (RGB in -> RGB out), pass-through on internal errors
- QR node: vectorized module drawing (np.kron), logging instead of prints
- New net_utils.safe_download: http(s)-only scheme + 20MB cap for URL
  fetching nodes (SSRF/decompression-bomb hardening)
- Removed unused soft_empty_cache() calls, dead code (culinary_handler,
  IsulionCategorySelector, orphan Core_Nodes/config dir, dead js ext),
  invalid WEB_DIRECTORY; fixed display-name mappings
- s300 handler: fixed call to non-existent config method (latent crash)
- Added MIT LICENSE and requirements.txt (requests)
2026-08-22 15:16:55 +02:00

38 lines
1.4 KiB
Python

"""Shared, hardened download helper for URL-fetching nodes."""
import logging
from urllib.parse import urlparse
import requests
logger = logging.getLogger(__name__)
MAX_IMAGE_BYTES = 20 * 1024 * 1024 # 20 MB safety cap (decompression-bomb guard)
class DownloadError(Exception):
"""Raised when a URL fails scheme validation or exceeds size limits."""
def validate_url(url: str) -> None:
"""Reject non-http(s) or hostless URLs before any network call."""
parsed = urlparse(str(url))
if parsed.scheme not in ("http", "https"):
raise DownloadError(f"URL scheme not allowed: {parsed.scheme!r}")
if not parsed.netloc:
raise DownloadError("URL has no host")
def safe_download(url: str, timeout: int = 15, max_bytes: int = MAX_IMAGE_BYTES) -> bytes:
"""Download `url` enforcing http(s)-only schemes and a hard size cap."""
validate_url(url)
with requests.get(url, timeout=timeout, stream=True) as response:
response.raise_for_status()
content_length = response.headers.get("Content-Length")
if content_length is not None and int(content_length) > max_bytes:
raise DownloadError(f"Content too large ({content_length} bytes > {max_bytes})")
data = response.raw.read(max_bytes + 1, decode_content=True)
if len(data) > max_bytes:
raise DownloadError(f"Content exceeded {max_bytes} bytes while streaming")
return data