diff --git a/src/qwenpaw/app/routers/files.py b/src/qwenpaw/app/routers/files.py index d9c0b18e5..d364b9136 100644 --- a/src/qwenpaw/app/routers/files.py +++ b/src/qwenpaw/app/routers/files.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- from pathlib import Path +from urllib.parse import unquote from fastapi import APIRouter, HTTPException from starlette.responses import FileResponse @@ -15,9 +16,30 @@ async def preview_file( filepath: str, ): """Preview file.""" - path = Path(filepath) + normalized = unquote(filepath) + + # Tolerate duplicated preview prefix from some clients, e.g. + # /api/files/preview/api/files/preview/C%3A/Users/... + while True: + trimmed = normalized.lstrip("/") + prefix = "api/files/preview/" + if trimmed.startswith(prefix): + normalized = trimmed[len(prefix) :] + continue + break + + # Normalize /C:/... to C:/... on Windows. + if ( + len(normalized) >= 4 + and normalized[0] == "/" + and normalized[2] == ":" + and normalized[1].isalpha() + ): + normalized = normalized[1:] + + path = Path(normalized) if not path.is_absolute(): - path = Path("/" + filepath) + path = Path("/" + normalized) path = path.resolve() if not path.is_file(): raise HTTPException(status_code=404, detail="Not found")