fix(image): handle root URL cache paths

This commit is contained in:
jxxghp
2026-09-17 11:26:45 +08:00
parent 07585b1a95
commit abe445b39b
2 changed files with 29 additions and 3 deletions

View File

@@ -2,6 +2,7 @@ import io
import threading
from collections.abc import Mapping
from dataclasses import dataclass
from hashlib import sha256
from pathlib import Path
from typing import Any, Callable, List, Optional, Protocol
@@ -15,6 +16,8 @@ from app.runtime.log import logger
WallpaperProvider = Callable[[], Optional[str]]
WallpaperListProvider = Callable[[int], List[str]]
_IMAGE_CACHE_PATH_PREFIX = "proxy_"
_IMAGE_CACHE_HASH_LENGTH = 16
@dataclass(frozen=True, slots=True)
@@ -373,9 +376,16 @@ class ImageHelper(metaclass=Singleton):
@staticmethod
def _prepare_cache_path(url: str) -> str:
"""缓存路径"""
sanitized_path = SecurityUtils.sanitize_url_path(url)
cache_path = Path(sanitized_path)
"""
根据图片 URL 生成缓存路径。
根路径或其他无有效文件名的 URL 使用完整 URL 的短哈希兜底,避免
`Path.with_suffix()` 对空路径抛出异常,并保证不同 URL 不共用该缓存名。
"""
cache_path = Path(SecurityUtils.sanitize_url_path(url))
if not cache_path.name:
hash_value = sha256(url.encode()).hexdigest()[:_IMAGE_CACHE_HASH_LENGTH]
cache_path = Path(f"{_IMAGE_CACHE_PATH_PREFIX}{hash_value}")
if not cache_path.suffix:
cache_path = cache_path.with_suffix(".jpg")
return cache_path.as_posix()

View File

@@ -1,6 +1,7 @@
import asyncio
import io
from collections.abc import Iterator, Mapping
from hashlib import sha256
from types import SimpleNamespace
from typing import Any, Optional
from unittest.mock import AsyncMock, Mock, patch
@@ -238,6 +239,21 @@ def test_async_fetch_image_with_mime_type_validates_network_content_once():
assert transport.async_calls[0][0] == "https://images.example/wallpaper.png"
@pytest.mark.parametrize(
"url",
[
"https://example.com",
"https://example.com/",
"https://example.com/?param=value",
],
)
def test_prepare_cache_path_uses_url_hash_for_urls_without_path(url: str) -> None:
"""没有有效路径的图片 URL 应生成稳定合法的缓存文件名。"""
expected_hash = sha256(url.encode()).hexdigest()[:16]
assert ImageHelper._prepare_cache_path(url) == f"proxy_{expected_hash}.jpg"
def test_image_request_uses_internal_address_port_for_proxy_decision(monkeypatch):
"""自动代理策略必须通过注入端口判断内部地址。"""
internal_address = _FakeInternalAddress(internal=True)