Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions src/runtime/internal/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@ import type { CacheOptions, CachedEventHandlerOptions } from "nitro/types";

let _storageReady = false;

/**
* Sanitize a cache group or name so it is safe for filesystem-based storage
* drivers (fs, fs-lite). Unstorage maps ":" to "/" on disk, so any "/" already
* present in the value would create unexpected directory nesting and cause
* ENOTDIR errors when a path is both a file and a prefix of another path.
*/
function sanitizeCacheKey(value: string | undefined): string | undefined {
return value?.replace(/\//g, "_");
}

function ensureStorage() {
if (_storageReady) {
return;
Expand All @@ -37,9 +47,10 @@ export function defineCachedFunction<T, ArgsT extends unknown[] = any[]>(
): (...args: ArgsT) => Promise<T> {
ensureStorage();
return _defineCachedFunction(fn, {
group: "nitro/functions",
group: "nitro-functions",
onError: defaultOnError,
...opts,
name: sanitizeCacheKey(opts.name),
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
});
}

Expand All @@ -49,12 +60,13 @@ export function defineCachedHandler(
): EventHandler {
ensureStorage();
const ocacheHandler = _defineCachedHandler(handler as any, {
group: "nitro/handlers",
group: "nitro-handlers",
onError: defaultOnError,
toResponse: (value, event) => toResponse(value, event as H3Event),
createResponse: (body, init) => new FastResponse(body, init),
handleCacheHeaders: (event, conditions) => handleCacheHeaders(event as H3Event, conditions),
...opts,
name: sanitizeCacheKey(opts.name),
});
return defineHandler((event) => ocacheHandler(event as any));
}
9 changes: 7 additions & 2 deletions src/runtime/internal/route-rules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,14 @@ export const cache: RouteRuleCtor<"cache"> = ((m) =>
const key = `${m.route}:${route}`;
let cachedHandler = cachedHandlers.get(key);
if (!cachedHandler) {
// Sanitize the name to avoid filesystem path conflicts.
// Route paths contain "/" which unstorage's fs drivers interpret as
// directory separators, causing ENOTDIR when a path like "/foo" is
// cached as a file but "/foo/bar" needs it to be a directory.
const safeName = key.replace(/\//g, "_");
cachedHandler = defineCachedHandler(handler, {
group: "nitro/route-rules",
name: key,
group: "nitro-route-rules",
name: safeName,
...m.options,
});
cachedHandlers.set(key, cachedHandler);
Expand Down
Loading