Etikettenvorlage: der Umlaut aus macOS sprengte den Download
macOS legt Dateinamen zerlegt ab - das "ae" in "Lagerplaetze.lbx" ist dort nicht ein Zeichen, sondern "a" plus ein kombinierender Trema-Akzent. Genau diese Form landet beim Hochladen in der Datenbank. Starlette schreibt Header aber als latin-1, und fuer den Akzent gibt es dort nichts - die Route starb mit UnicodeEncodeError und antwortete 500, obwohl der Name am Bildschirm voellig harmlos aussah. Der Header wird jetzt nach RFC 6266 zweigleisig gebaut: filename= traegt eine ASCII-Fassung als Rueckfall, filename*= den echten Namen prozentkodiert. Browser bevorzugen filename* und zeigen den Umlaut richtig. Derselbe Riegel liegt auf dem CSV-Download, wo der frei getippte Vorlagenname in den Header geht - gleicher Defekt, nur noch nicht aufgefallen. Fuer die Download-Route gab es bisher keinen Test; zwei kommen dazu. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
b3256457d2
commit
94f8ed4db9
@@ -6,7 +6,9 @@ deshalb ohne HTTP, direkt am Ergebnis.
|
||||
|
||||
import io
|
||||
import json
|
||||
import unicodedata
|
||||
import zipfile
|
||||
from urllib.parse import unquote
|
||||
|
||||
import pytest
|
||||
from fastapi import HTTPException
|
||||
@@ -23,7 +25,7 @@ from app.models import (
|
||||
Role,
|
||||
User,
|
||||
)
|
||||
from app.routers.etiketten import _pruefe_lbx, spalten
|
||||
from app.routers.etiketten import _pruefe_lbx, datei_herunterladen, spalten
|
||||
from app.services.etiketten import csv_erzeugen, konfiguration_lesen
|
||||
|
||||
|
||||
@@ -351,3 +353,49 @@ def test_vorlage_uebersteht_die_sicherung(db, admin, kabel):
|
||||
neue_fd = zweite.query(FieldDefinition).filter(FieldDefinition.label == "Länge").one()
|
||||
assert feld_spalte == f"feld:{neue_fd.id}"
|
||||
zweite.close()
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Download der hinterlegten .lbx
|
||||
# --------------------------------------------------------------------------
|
||||
def _disposition_pruefen(antwort, erwarteter_name):
|
||||
"""Header muss sich senden lassen UND den echten Namen tragen."""
|
||||
roh = antwort.headers["content-disposition"]
|
||||
# Starlette kodiert Header als latin-1. Wirft das hier, antwortet die
|
||||
# Route im Betrieb mit 500 statt mit der Datei.
|
||||
roh.encode("latin-1")
|
||||
stern = roh.split("filename*=UTF-8''", 1)[1]
|
||||
assert unquote(stern) == erwarteter_name
|
||||
|
||||
|
||||
def test_lbx_mit_zerlegtem_umlaut_laesst_sich_herunterladen(db, admin):
|
||||
"""macOS legt Dateinamen ZERLEGT ab: das "ä" ist dort "a" + U+0308.
|
||||
|
||||
Am Bildschirm sieht das wie die zusammengesetzte Form aus, aber nur die
|
||||
passt in latin-1 - die Kodierung, mit der HTTP-Header geschrieben werden.
|
||||
Ein Name, den der Dateiwaehler eines Macs liefert, darf den Download
|
||||
nicht sprengen.
|
||||
"""
|
||||
name = unicodedata.normalize("NFD", "Lagerplätze.lbx")
|
||||
v = _vorlage(db, ["uid"])
|
||||
v.datei_name = name
|
||||
v.datei = _zip(["label.xml"])
|
||||
db.commit()
|
||||
|
||||
antwort = datei_herunterladen(vorlage_id=v.id, db=db, _=admin)
|
||||
|
||||
assert antwort.body == _zip(["label.xml"])
|
||||
_disposition_pruefen(antwort, name)
|
||||
|
||||
|
||||
def test_lbx_mit_schlichtem_namen_bleibt_unveraendert(db, admin):
|
||||
"""Der haeufige Fall darf von der Umstellung nicht beruehrt werden."""
|
||||
v = _vorlage(db, ["uid"])
|
||||
v.datei_name = "kabel.lbx"
|
||||
v.datei = _zip(["label.xml"])
|
||||
db.commit()
|
||||
|
||||
antwort = datei_herunterladen(vorlage_id=v.id, db=db, _=admin)
|
||||
|
||||
assert 'filename="kabel.lbx"' in antwort.headers["content-disposition"]
|
||||
_disposition_pruefen(antwort, "kabel.lbx")
|
||||
|
||||
Reference in New Issue
Block a user