diff --git a/server/middleware/upload.js b/server/middleware/upload.js index ed9f0c7..faa96a5 100644 --- a/server/middleware/upload.js +++ b/server/middleware/upload.js @@ -8,6 +8,21 @@ const storage = multer.diskStorage({ cb(null, config.contentDir); }, filename: (req, file, cb) => { + // busboy decodes the Content-Disposition filename header as latin1 by + // default. Modern clients send raw UTF-8 bytes for non-ASCII filenames + // (e.g. browsers + curl on UTF-8 locales send "Begrussungsscreens.jpg" + // with c3 bc for u-umlaut). Reading those bytes as latin1 produces the + // string "A-tilde + quarter-mark" which JS then re-encodes as 4 UTF-8 + // bytes on the way to the DB - classic double-encoding mojibake. + // + // The `defParamCharset: 'utf8'` option below only takes effect for + // RFC 5987 encoded `filename*=...` params, which most clients don't send. + // For the plain `filename="..."` case, re-decode here to recover the + // original UTF-8 byte sequence. Mutating originalname here propagates to + // every downstream consumer (route handlers reading req.file.originalname). + if (file.originalname) { + file.originalname = Buffer.from(file.originalname, 'latin1').toString('utf8'); + } const ext = path.extname(file.originalname); cb(null, `${uuidv4()}${ext}`); }