fix: serve data files with reserved characters in dev and preview

sirv decodes request paths with decodeURI, which leaves %26 (&) and
%23 (#) encoded, so data files with such characters in their names
were not found by the dev and preview servers. Hand sirv the fully
decoded path, the way Apache resolves it in production.
This commit is contained in:
2026-09-14 18:33:37 +09:00
parent c94d272342
commit 0d79a0ffd6
+28 -1
View File
@@ -20,7 +20,34 @@ const staticContents = (): Plugin => {
// browser revalidates against the ETag instead of falling back to
// heuristic caching. Without it a re-dump, or another site served
// from the same localhost port, is answered from a stale cache.
middlewares.use(sirv(dir, { dev, etag: true, maxAge: 0 }));
const serve = sirv(dir, { dev, etag: true, maxAge: 0 });
middlewares.use((req, res, next) => {
// sirv decodes the path with decodeURI, which leaves reserved
// characters such as %26 (&) and %23 (#) encoded, so a file like
// `CFP&Reg.png` is not found. sirv reuses `req._parsedUrl` when
// it was parsed from the same `req.url`, so hand it the path
// decoded the way Apache resolves it.
const raw = req.url ?? '/';
const idx = raw.search(/[?#]/);
const pathname = idx === -1 ? raw : raw.slice(0, idx);
if (pathname.includes('%')) {
try {
const decoded = pathname.split('/').map(decodeURIComponent).join('/');
if (!decoded.includes('%')) {
(req as typeof req & { _parsedUrl?: object })._parsedUrl = {
pathname: decoded,
search: '',
query: undefined,
hash: undefined,
raw,
};
}
} catch {
// leave malformed escapes to sirv
}
}
serve(req, res, next);
});
}
};
return {