fix(pdf,excalidraw): BUG-001 + BUG-002
CI / lint (push) Successful in 47s
CI / security (push) Successful in 32s
CI / test (push) Successful in 1m0s
CI / build (push) Successful in 30s
CI / e2e (push) Successful in 9m22s
Desktop Build / build-windows (push) Canceled after 0s
Desktop Build / build-linux (push) Canceled after 0s
CI / lint (push) Successful in 47s
CI / security (push) Successful in 32s
CI / test (push) Successful in 1m0s
CI / build (push) Successful in 30s
CI / e2e (push) Successful in 9m22s
Desktop Build / build-windows (push) Canceled after 0s
Desktop Build / build-linux (push) Canceled after 0s
BUG-001 (PDF stream 500) : le nom Unicode du fichier etait injecte brut dans Content-Disposition -> en-tete HTTP invalide -> 500. Nouveau helper _content_disposition (RFC 5987 : filename ASCII + filename*=UTF-8''). Applique aux 2 branches /pdf/stream. Test: tests/test_pdf_stream.py. BUG-002 (Excalidraw 'Loading...' infini) : deux causes. 1) L'import esm.sh avec ?alias=react:... etait propage a chaque dep transitive; esm.sh renvoie 408 sur les builds a gamme semver (jotai@>=2.9.2) -> import entier echoue. On retire l'alias et on utilise React 19 coherent (spec a gamme + target identique a celle d'Excalidraw) -> plus de 408. 2) L'editeur passait la prop legacy 'excalidrawRef', inoperante en 0.18 (la prop reelle est 'excalidrawAPI') -> l'API n'etait jamais recue, le 'Loading' ne se masquait pas, save/export morts. Verifie : 534 tests backend verts (dont 3 nouveaux PDF) + E2E navigateur (loading masque + cycle requestSave->save OK).
This commit is contained in:
+18
-2
@@ -735,6 +735,22 @@ FRONTEND_DIR = Path(__file__).resolve().parent.parent / "frontend"
|
||||
# Path safety helper
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _content_disposition(disposition: str, filename: str) -> str:
|
||||
"""Build a header-safe Content-Disposition value.
|
||||
|
||||
HTTP header values must be ASCII. Unicode filenames are sent per
|
||||
RFC 5987 via ``filename*`` (percent-encoded UTF-8) with a pure-ASCII
|
||||
``filename`` fallback. This avoids a UnicodeDecodeError / HTTP 500 when
|
||||
the filename contains accented characters (e.g. 'Bière blonde…pdf').
|
||||
"""
|
||||
from urllib.parse import quote
|
||||
ascii_name = "".join(c for c in filename if c.isascii() and (c.isalnum() or c in " _-.")).strip() or "file"
|
||||
ext = Path(filename).suffix
|
||||
if ext and not Path(ascii_name).suffix:
|
||||
ascii_name = ascii_name + ext
|
||||
return f"{disposition}; filename=\"{ascii_name}\"; filename*=UTF-8''{quote(filename)}"
|
||||
|
||||
|
||||
def _resolve_safe_path(vault_root: Path, relative_path: str) -> Path:
|
||||
"""Resolve a relative path safely within the vault root.
|
||||
|
||||
@@ -2801,13 +2817,13 @@ async def api_pdf_stream(
|
||||
"Content-Range": f"bytes {start}-{end}/{file_size}",
|
||||
"Accept-Ranges": "bytes",
|
||||
"Content-Length": str(chunk_size),
|
||||
"Content-Disposition": f'inline; filename="{file_path.name}"',
|
||||
"Content-Disposition": _content_disposition("inline", file_path.name),
|
||||
},
|
||||
)
|
||||
|
||||
return FileResponse(str(file_path), media_type="application/pdf", headers={
|
||||
"Accept-Ranges": "bytes",
|
||||
"Content-Disposition": f'inline; filename="{file_path.name}"'})
|
||||
"Content-Disposition": _content_disposition("inline", file_path.name)})
|
||||
|
||||
|
||||
@app.get("/api/file/{vault_name}/pdf/info")
|
||||
|
||||
Reference in New Issue
Block a user