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:
@@ -0,0 +1,62 @@
|
||||
# tests/test_pdf_stream.py — Regression tests for BUG-001 (PDF stream HTTP 500)
|
||||
#
|
||||
# BUG-001: opening a PDF whose filename contains accented characters
|
||||
# (e.g. "Bière blonde envoyé par Desja.pdf") returned HTTP 500 because the raw
|
||||
# Unicode name was injected into the Content-Disposition header, producing an
|
||||
# invalid (non-ASCII) header value. /pdf/info worked because it sets no
|
||||
# filename header.
|
||||
#
|
||||
# Fix: RFC 5987 header encoding (ASCII `filename` fallback + `filename*=UTF-8''…`).
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
# Minimal valid PDF so pypdf/stream treats the bytes as a real PDF.
|
||||
MIN_PDF = (
|
||||
b"%PDF-1.4\n"
|
||||
b"1 0 obj<</Type/Catalog/Pages 2 0 R>>endobj\n"
|
||||
b"2 0 obj<</Type/Pages/Kids[3 0 R]/Count 1>>endobj\n"
|
||||
b"3 0 obj<</Type/Page/Parent 2 0 R/MediaBox[0 0 612 792]>>endobj\n"
|
||||
b"xref\n0 4\n0000000000 65535 f \n"
|
||||
b"trailer<</Size 4/Root 1 0 R>>\nstartxref\n0\n%%EOF\n"
|
||||
)
|
||||
|
||||
|
||||
def _create_pdf_with_unicode_name():
|
||||
vault = Path(os.environ["VAULT_1_PATH"])
|
||||
sub = vault / "98_Boite_Outils" / "98.2_Attachments"
|
||||
sub.mkdir(parents=True, exist_ok=True)
|
||||
pdf = sub / "Bière blonde envoyé par Desja.pdf"
|
||||
pdf.write_bytes(MIN_PDF)
|
||||
return "98_Boite_Outils/98.2_Attachments/Bière blonde envoyé par Desja.pdf"
|
||||
|
||||
|
||||
class TestPdfStreamUnicodeFilename:
|
||||
def test_full_stream_ok(self, client):
|
||||
rel = _create_pdf_with_unicode_name()
|
||||
resp = client.get("/api/file/TestVault/pdf/stream", params={"path": rel})
|
||||
assert resp.status_code == 200, resp.text
|
||||
assert resp.headers["content-type"] == "application/pdf"
|
||||
cd = resp.headers.get("content-disposition", "")
|
||||
# Content-Disposition must be RFC 5987 encoded (ASCII-safe)
|
||||
assert "filename*=UTF-8''" in cd, cd
|
||||
# UTF-8 percent-encoded accented name present (é -> %C3%A8)
|
||||
assert "%C3%A8re%20blonde" in cd
|
||||
|
||||
def test_range_request_ok(self, client):
|
||||
rel = _create_pdf_with_unicode_name()
|
||||
resp = client.get(
|
||||
"/api/file/TestVault/pdf/stream",
|
||||
params={"path": rel},
|
||||
headers={"Range": "bytes=0-99"},
|
||||
)
|
||||
assert resp.status_code == 206
|
||||
assert resp.headers.get("content-range", "").startswith("bytes 0-99/")
|
||||
|
||||
def test_disposition_ascii_safe(self, client):
|
||||
rel = _create_pdf_with_unicode_name()
|
||||
resp = client.get("/api/file/TestVault/pdf/stream", params={"path": rel})
|
||||
cd = resp.headers.get("content-disposition", "")
|
||||
# Every header field value must be ASCII-encodable (no UnicodeEncodeError)
|
||||
cd.encode("ascii")
|
||||
# ASCII fallback filename present
|
||||
assert 'filename="' in cd
|
||||
Reference in New Issue
Block a user