securityos/node_modules/next/dist/server/lib/router-utils/filesystem.js

502 lines
23 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
0 && (module.exports = {
buildCustomRoute: null,
setupFsCheck: null
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
buildCustomRoute: function() {
return buildCustomRoute;
},
setupFsCheck: function() {
return setupFsCheck;
}
});
const _path = /*#__PURE__*/ _interop_require_default(require("path"));
const _promises = /*#__PURE__*/ _interop_require_default(require("fs/promises"));
const _log = /*#__PURE__*/ _interop_require_wildcard(require("../../../build/output/log"));
const _debug = /*#__PURE__*/ _interop_require_default(require("next/dist/compiled/debug"));
const _lrucache = /*#__PURE__*/ _interop_require_default(require("next/dist/compiled/lru-cache"));
const _loadcustomroutes = /*#__PURE__*/ _interop_require_default(require("../../../lib/load-custom-routes"));
const _redirectstatus = require("../../../lib/redirect-status");
const _fileexists = require("../../../lib/file-exists");
const _recursivereaddir = require("../../../lib/recursive-readdir");
const _utils = require("../../../shared/lib/router/utils");
const _escaperegexp = require("../../../shared/lib/escape-regexp");
const _pathmatch = require("../../../shared/lib/router/utils/path-match");
const _routeregex = require("../../../shared/lib/router/utils/route-regex");
const _routematcher = require("../../../shared/lib/router/utils/route-matcher");
const _pathhasprefix = require("../../../shared/lib/router/utils/path-has-prefix");
const _normalizelocalepath = require("../../../shared/lib/i18n/normalize-locale-path");
const _removepathprefix = require("../../../shared/lib/router/utils/remove-path-prefix");
const _middlewareroutematcher = require("../../../shared/lib/router/utils/middleware-route-matcher");
const _constants = require("../../../shared/lib/constants");
const _normalizepathsep = require("../../../shared/lib/page-path/normalize-path-sep");
const _getmetadataroute = require("../../../lib/metadata/get-metadata-route");
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function _getRequireWildcardCache(nodeInterop) {
if (typeof WeakMap !== "function") return null;
var cacheBabelInterop = new WeakMap();
var cacheNodeInterop = new WeakMap();
return (_getRequireWildcardCache = function(nodeInterop) {
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
})(nodeInterop);
}
function _interop_require_wildcard(obj, nodeInterop) {
if (!nodeInterop && obj && obj.__esModule) {
return obj;
}
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
return {
default: obj
};
}
var cache = _getRequireWildcardCache(nodeInterop);
if (cache && cache.has(obj)) {
return cache.get(obj);
}
var newObj = {};
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
for(var key in obj){
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
if (desc && (desc.get || desc.set)) {
Object.defineProperty(newObj, key, desc);
} else {
newObj[key] = obj[key];
}
}
}
newObj.default = obj;
if (cache) {
cache.set(obj, newObj);
}
return newObj;
}
const debug = (0, _debug.default)("next:router-server:filesystem");
const buildCustomRoute = (type, item, basePath, caseSensitive)=>{
const restrictedRedirectPaths = [
"/_next"
].map((p)=>basePath ? `${basePath}${p}` : p);
const match = (0, _pathmatch.getPathMatch)(item.source, {
strict: true,
removeUnnamedParams: true,
regexModifier: !item.internal ? (regex)=>(0, _redirectstatus.modifyRouteRegex)(regex, type === "redirect" ? restrictedRedirectPaths : undefined) : undefined,
sensitive: caseSensitive
});
return {
...item,
...type === "rewrite" ? {
check: true
} : {},
match
};
};
async function setupFsCheck(opts) {
const getItemsLru = !opts.dev ? new _lrucache.default({
max: 1024 * 1024,
length (value, key) {
if (!value) return (key == null ? void 0 : key.length) || 0;
return (key || "").length + (value.fsPath || "").length + value.itemPath.length + value.type.length;
}
}) : undefined;
// routes that have _next/data endpoints (SSG/SSP)
const nextDataRoutes = new Set();
const publicFolderItems = new Set();
const nextStaticFolderItems = new Set();
const legacyStaticFolderItems = new Set();
const appFiles = new Set();
const pageFiles = new Set();
let dynamicRoutes = [];
let middlewareMatcher = ()=>false;
const distDir = _path.default.join(opts.dir, opts.config.distDir);
const publicFolderPath = _path.default.join(opts.dir, "public");
const nextStaticFolderPath = _path.default.join(distDir, "static");
const legacyStaticFolderPath = _path.default.join(opts.dir, "static");
let customRoutes = {
redirects: [],
rewrites: {
beforeFiles: [],
afterFiles: [],
fallback: []
},
headers: []
};
let buildId = "development";
let prerenderManifest;
if (!opts.dev) {
var _middlewareManifest_middleware_, _middlewareManifest_middleware;
const buildIdPath = _path.default.join(opts.dir, opts.config.distDir, _constants.BUILD_ID_FILE);
buildId = await _promises.default.readFile(buildIdPath, "utf8");
try {
for (const file of (await (0, _recursivereaddir.recursiveReadDir)(publicFolderPath))){
// Ensure filename is encoded and normalized.
publicFolderItems.add(encodeURI((0, _normalizepathsep.normalizePathSep)(file)));
}
} catch (err) {
if (err.code !== "ENOENT") {
throw err;
}
}
try {
for (const file of (await (0, _recursivereaddir.recursiveReadDir)(legacyStaticFolderPath))){
// Ensure filename is encoded and normalized.
legacyStaticFolderItems.add(encodeURI((0, _normalizepathsep.normalizePathSep)(file)));
}
_log.warn(`The static directory has been deprecated in favor of the public directory. https://nextjs.org/docs/messages/static-dir-deprecated`);
} catch (err) {
if (err.code !== "ENOENT") {
throw err;
}
}
try {
for (const file of (await (0, _recursivereaddir.recursiveReadDir)(nextStaticFolderPath))){
// Ensure filename is encoded and normalized.
nextStaticFolderItems.add(_path.default.posix.join("/_next/static", encodeURI((0, _normalizepathsep.normalizePathSep)(file))));
}
} catch (err) {
if (opts.config.output !== "standalone") throw err;
}
const routesManifestPath = _path.default.join(distDir, _constants.ROUTES_MANIFEST);
const prerenderManifestPath = _path.default.join(distDir, _constants.PRERENDER_MANIFEST);
const middlewareManifestPath = _path.default.join(distDir, "server", _constants.MIDDLEWARE_MANIFEST);
const pagesManifestPath = _path.default.join(distDir, "server", _constants.PAGES_MANIFEST);
const appRoutesManifestPath = _path.default.join(distDir, _constants.APP_PATH_ROUTES_MANIFEST);
const routesManifest = JSON.parse(await _promises.default.readFile(routesManifestPath, "utf8"));
prerenderManifest = JSON.parse(await _promises.default.readFile(prerenderManifestPath, "utf8"));
const middlewareManifest = JSON.parse(await _promises.default.readFile(middlewareManifestPath, "utf8").catch(()=>"{}"));
const pagesManifest = JSON.parse(await _promises.default.readFile(pagesManifestPath, "utf8"));
const appRoutesManifest = JSON.parse(await _promises.default.readFile(appRoutesManifestPath, "utf8").catch(()=>"{}"));
for (const key of Object.keys(pagesManifest)){
// ensure the non-locale version is in the set
if (opts.config.i18n) {
pageFiles.add((0, _normalizelocalepath.normalizeLocalePath)(key, opts.config.i18n.locales).pathname);
} else {
pageFiles.add(key);
}
}
for (const key of Object.keys(appRoutesManifest)){
appFiles.add(appRoutesManifest[key]);
}
const escapedBuildId = (0, _escaperegexp.escapeStringRegexp)(buildId);
for (const route of routesManifest.dataRoutes){
if ((0, _utils.isDynamicRoute)(route.page)) {
const routeRegex = (0, _routeregex.getRouteRegex)(route.page);
dynamicRoutes.push({
...route,
regex: routeRegex.re.toString(),
match: (0, _routematcher.getRouteMatcher)({
// TODO: fix this in the manifest itself, must also be fixed in
// upstream builder that relies on this
re: opts.config.i18n ? new RegExp(route.dataRouteRegex.replace(`/${escapedBuildId}/`, `/${escapedBuildId}/(?<nextLocale>[^/]+?)/`)) : new RegExp(route.dataRouteRegex),
groups: routeRegex.groups
})
});
}
nextDataRoutes.add(route.page);
}
for (const route of routesManifest.dynamicRoutes){
dynamicRoutes.push({
...route,
match: (0, _routematcher.getRouteMatcher)((0, _routeregex.getRouteRegex)(route.page))
});
}
if ((_middlewareManifest_middleware = middlewareManifest.middleware) == null ? void 0 : (_middlewareManifest_middleware_ = _middlewareManifest_middleware["/"]) == null ? void 0 : _middlewareManifest_middleware_.matchers) {
var _middlewareManifest_middleware_1, _middlewareManifest_middleware1;
middlewareMatcher = (0, _middlewareroutematcher.getMiddlewareRouteMatcher)((_middlewareManifest_middleware1 = middlewareManifest.middleware) == null ? void 0 : (_middlewareManifest_middleware_1 = _middlewareManifest_middleware1["/"]) == null ? void 0 : _middlewareManifest_middleware_1.matchers);
}
customRoutes = {
redirects: routesManifest.redirects,
rewrites: routesManifest.rewrites ? Array.isArray(routesManifest.rewrites) ? {
beforeFiles: [],
afterFiles: routesManifest.rewrites,
fallback: []
} : routesManifest.rewrites : {
beforeFiles: [],
afterFiles: [],
fallback: []
},
headers: routesManifest.headers
};
} else {
// dev handling
customRoutes = await (0, _loadcustomroutes.default)(opts.config);
prerenderManifest = {
version: 4,
routes: {},
dynamicRoutes: {},
notFoundRoutes: [],
preview: {
previewModeId: require("crypto").randomBytes(16).toString("hex"),
previewModeSigningKey: require("crypto").randomBytes(32).toString("hex"),
previewModeEncryptionKey: require("crypto").randomBytes(32).toString("hex")
}
};
}
const headers = customRoutes.headers.map((item)=>buildCustomRoute("header", item, opts.config.basePath, opts.config.experimental.caseSensitiveRoutes));
const redirects = customRoutes.redirects.map((item)=>buildCustomRoute("redirect", item, opts.config.basePath, opts.config.experimental.caseSensitiveRoutes));
const rewrites = {
// TODO: add interception routes generateInterceptionRoutesRewrites()
beforeFiles: customRoutes.rewrites.beforeFiles.map((item)=>buildCustomRoute("before_files_rewrite", item)),
afterFiles: customRoutes.rewrites.afterFiles.map((item)=>buildCustomRoute("rewrite", item, opts.config.basePath, opts.config.experimental.caseSensitiveRoutes)),
fallback: customRoutes.rewrites.fallback.map((item)=>buildCustomRoute("rewrite", item, opts.config.basePath, opts.config.experimental.caseSensitiveRoutes))
};
const { i18n } = opts.config;
const handleLocale = (pathname, locales)=>{
let locale;
if (i18n) {
const i18nResult = (0, _normalizelocalepath.normalizeLocalePath)(pathname, locales || i18n.locales);
pathname = i18nResult.pathname;
locale = i18nResult.detectedLocale;
}
return {
locale,
pathname
};
};
debug("nextDataRoutes", nextDataRoutes);
debug("dynamicRoutes", dynamicRoutes);
debug("pageFiles", pageFiles);
debug("appFiles", appFiles);
let ensureFn;
return {
headers,
rewrites,
redirects,
buildId,
handleLocale,
appFiles,
pageFiles,
dynamicRoutes,
nextDataRoutes,
interceptionRoutes: undefined,
devVirtualFsItems: new Set(),
prerenderManifest,
middlewareMatcher: middlewareMatcher,
ensureCallback (fn) {
ensureFn = fn;
},
async getItem (itemPath) {
const originalItemPath = itemPath;
const itemKey = originalItemPath;
const lruResult = getItemsLru == null ? void 0 : getItemsLru.get(itemKey);
if (lruResult) {
return lruResult;
}
// handle minimal mode case with .rsc output path (this is
// mostly for testings)
if (opts.minimalMode && itemPath.endsWith(".rsc")) {
itemPath = itemPath.substring(0, itemPath.length - ".rsc".length);
}
const { basePath } = opts.config;
if (basePath && !(0, _pathhasprefix.pathHasPrefix)(itemPath, basePath)) {
return null;
}
itemPath = (0, _removepathprefix.removePathPrefix)(itemPath, basePath) || "/";
if (itemPath !== "/" && itemPath.endsWith("/")) {
itemPath = itemPath.substring(0, itemPath.length - 1);
}
let decodedItemPath = itemPath;
try {
decodedItemPath = decodeURIComponent(itemPath);
} catch {}
if (itemPath === "/_next/image") {
return {
itemPath,
type: "nextImage"
};
}
const itemsToCheck = [
[
this.devVirtualFsItems,
"devVirtualFsItem"
],
[
nextStaticFolderItems,
"nextStaticFolder"
],
[
legacyStaticFolderItems,
"legacyStaticFolder"
],
[
publicFolderItems,
"publicFolder"
],
[
appFiles,
"appFile"
],
[
pageFiles,
"pageFile"
]
];
for (let [items, type] of itemsToCheck){
let locale;
let curItemPath = itemPath;
let curDecodedItemPath = decodedItemPath;
const isDynamicOutput = type === "pageFile" || type === "appFile";
if (i18n) {
const localeResult = handleLocale(itemPath, // legacy behavior allows visiting static assets under
// default locale but no other locale
isDynamicOutput ? undefined : [
i18n == null ? void 0 : i18n.defaultLocale
]);
if (localeResult.pathname !== curItemPath) {
curItemPath = localeResult.pathname;
locale = localeResult.locale;
try {
curDecodedItemPath = decodeURIComponent(curItemPath);
} catch {}
}
}
if (type === "legacyStaticFolder") {
if (!(0, _pathhasprefix.pathHasPrefix)(curItemPath, "/static")) {
continue;
}
curItemPath = curItemPath.substring("/static".length);
try {
curDecodedItemPath = decodeURIComponent(curItemPath);
} catch {}
}
if (type === "nextStaticFolder" && !(0, _pathhasprefix.pathHasPrefix)(curItemPath, "/_next/static")) {
continue;
}
const nextDataPrefix = `/_next/data/${buildId}/`;
if (type === "pageFile" && curItemPath.startsWith(nextDataPrefix) && curItemPath.endsWith(".json")) {
items = nextDataRoutes;
// remove _next/data/<build-id> prefix
curItemPath = curItemPath.substring(nextDataPrefix.length - 1);
// remove .json postfix
curItemPath = curItemPath.substring(0, curItemPath.length - ".json".length);
const curLocaleResult = handleLocale(curItemPath);
curItemPath = curLocaleResult.pathname === "/index" ? "/" : curLocaleResult.pathname;
locale = curLocaleResult.locale;
try {
curDecodedItemPath = decodeURIComponent(curItemPath);
} catch {}
}
let matchedItem = items.has(curItemPath);
// check decoded variant as well
if (!matchedItem && !opts.dev) {
matchedItem = items.has(curItemPath);
if (matchedItem) curItemPath = curDecodedItemPath;
else {
// x-ref: https://github.com/vercel/next.js/issues/54008
// There're cases that urls get decoded before requests, we should support both encoded and decoded ones.
// e.g. nginx could decode the proxy urls, the below ones should be treated as the same:
// decoded version: `/_next/static/chunks/pages/blog/[slug]-d4858831b91b69f6.js`
// encoded version: `/_next/static/chunks/pages/blog/%5Bslug%5D-d4858831b91b69f6.js`
try {
// encode the special characters in the path and retrieve again to determine if path exists.
const encodedCurItemPath = encodeURI(curItemPath);
matchedItem = items.has(encodedCurItemPath);
} catch {}
}
}
if (matchedItem || opts.dev) {
let fsPath;
let itemsRoot;
switch(type){
case "nextStaticFolder":
{
itemsRoot = nextStaticFolderPath;
curItemPath = curItemPath.substring("/_next/static".length);
break;
}
case "legacyStaticFolder":
{
itemsRoot = legacyStaticFolderPath;
break;
}
case "publicFolder":
{
itemsRoot = publicFolderPath;
break;
}
default:
{
break;
}
}
if (itemsRoot && curItemPath) {
fsPath = _path.default.posix.join(itemsRoot, curItemPath);
}
// dynamically check fs in development so we don't
// have to wait on the watcher
if (!matchedItem && opts.dev) {
const isStaticAsset = [
"nextStaticFolder",
"publicFolder",
"legacyStaticFolder"
].includes(type);
if (isStaticAsset && itemsRoot) {
let found = fsPath && await (0, _fileexists.fileExists)(fsPath, _fileexists.FileType.File);
if (!found) {
try {
// In dev, we ensure encoded paths match
// decoded paths on the filesystem so check
// that variation as well
const tempItemPath = decodeURIComponent(curItemPath);
fsPath = _path.default.posix.join(itemsRoot, tempItemPath);
found = await (0, _fileexists.fileExists)(fsPath, _fileexists.FileType.File);
} catch {}
if (!found) {
continue;
}
}
} else if (type === "pageFile" || type === "appFile") {
var _ensureFn;
const isAppFile = type === "appFile";
if (ensureFn && await ((_ensureFn = ensureFn({
type,
itemPath: isAppFile ? (0, _getmetadataroute.normalizeMetadataRoute)(curItemPath) : curItemPath
})) == null ? void 0 : _ensureFn.catch(()=>"ENSURE_FAILED")) === "ENSURE_FAILED") {
continue;
}
} else {
continue;
}
}
// i18n locales aren't matched for app dir
if (type === "appFile" && locale && locale !== (i18n == null ? void 0 : i18n.defaultLocale)) {
continue;
}
const itemResult = {
type,
fsPath,
locale,
itemsRoot,
itemPath: curItemPath
};
getItemsLru == null ? void 0 : getItemsLru.set(itemKey, itemResult);
return itemResult;
}
}
getItemsLru == null ? void 0 : getItemsLru.set(itemKey, null);
return null;
},
getDynamicRoutes () {
// this should include data routes
return this.dynamicRoutes;
},
getMiddlewareMatchers () {
return this.middlewareMatcher;
}
};
}
//# sourceMappingURL=filesystem.js.map