.
This commit is contained in:
+629
@@ -0,0 +1,629 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
Object.defineProperty(exports, "getResolveRoutes", {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return getResolveRoutes;
|
||||
}
|
||||
});
|
||||
const _nodepath = /*#__PURE__*/ _interop_require_default(require("node:path"));
|
||||
const _debug = /*#__PURE__*/ _interop_require_default(require("next/dist/compiled/debug"));
|
||||
const _bodystreams = require("../../body-streams");
|
||||
const _utils = require("../server-ipc/utils");
|
||||
const _serverrouteutils = require("../../server-route-utils");
|
||||
const _formathostname = require("../format-hostname");
|
||||
const _utils1 = require("../../web/utils");
|
||||
const _pipereadable = require("../../pipe-readable");
|
||||
const _gethostname = require("../../../shared/lib/get-hostname");
|
||||
const _redirectstatus = require("../../../lib/redirect-status");
|
||||
const _utils2 = require("../../../shared/lib/utils");
|
||||
const _relativizeurl = require("../../../shared/lib/router/utils/relativize-url");
|
||||
const _addpathprefix = require("../../../shared/lib/router/utils/add-path-prefix");
|
||||
const _pathhasprefix = require("../../../shared/lib/router/utils/path-has-prefix");
|
||||
const _parseurl = require("../../../shared/lib/router/utils/parse-url");
|
||||
const _detectdomainlocale = require("../../../shared/lib/i18n/detect-domain-locale");
|
||||
const _normalizelocalepath = require("../../../shared/lib/i18n/normalize-locale-path");
|
||||
const _removepathprefix = require("../../../shared/lib/router/utils/remove-path-prefix");
|
||||
const _nextdata = require("../../normalizers/request/next-data");
|
||||
const _basepath = require("../../normalizers/request/base-path");
|
||||
const _requestmeta = require("../../request-meta");
|
||||
const _preparedestination = require("../../../shared/lib/router/utils/prepare-destination");
|
||||
const _approuterheaders = require("../../../client/components/app-router-headers");
|
||||
function _interop_require_default(obj) {
|
||||
return obj && obj.__esModule ? obj : {
|
||||
default: obj
|
||||
};
|
||||
}
|
||||
const debug = (0, _debug.default)('next:router-server:resolve-routes');
|
||||
function getResolveRoutes(fsChecker, config, opts, renderServer, renderServerOpts, ensureMiddleware) {
|
||||
let clientHashes = undefined;
|
||||
if (process.env.__NEXT_TEST_MODE && process.env.IS_TURBOPACK_TEST) {
|
||||
try {
|
||||
clientHashes = JSON.parse(require('fs').readFileSync(_nodepath.default.join(opts.dir, config.distDir, 'immutable-static-hashes.json'), 'utf8'));
|
||||
} catch {}
|
||||
}
|
||||
let routes = null;
|
||||
const calculateRoutes = ()=>{
|
||||
return [
|
||||
// _next/data with middleware handling
|
||||
{
|
||||
match: ()=>({}),
|
||||
name: 'middleware_next_data'
|
||||
},
|
||||
...opts.minimalMode ? [] : fsChecker.headers,
|
||||
...opts.minimalMode ? [] : fsChecker.redirects,
|
||||
// check middleware (using matchers)
|
||||
{
|
||||
match: ()=>({}),
|
||||
name: 'middleware'
|
||||
},
|
||||
...opts.minimalMode ? [] : fsChecker.rewrites.beforeFiles,
|
||||
// check middleware (using matchers)
|
||||
{
|
||||
match: ()=>({}),
|
||||
name: 'before_files_end'
|
||||
},
|
||||
// we check exact matches on fs before continuing to
|
||||
// after files rewrites
|
||||
{
|
||||
match: ()=>({}),
|
||||
name: 'check_fs'
|
||||
},
|
||||
...opts.minimalMode ? [] : fsChecker.rewrites.afterFiles,
|
||||
// we always do the check: true handling before continuing to
|
||||
// fallback rewrites
|
||||
{
|
||||
check: true,
|
||||
match: ()=>({}),
|
||||
name: 'after files check: true'
|
||||
},
|
||||
...opts.minimalMode ? [] : fsChecker.rewrites.fallback
|
||||
];
|
||||
};
|
||||
async function resolveRoutes({ req, res, isUpgradeReq, invokedOutputs }) {
|
||||
var _req_socket, _req_headers_xforwardedproto;
|
||||
let finished = false;
|
||||
let resHeaders = {};
|
||||
let matchedOutput = null;
|
||||
let parsedUrl = (0, _parseurl.parseUrl)(req.url || '');
|
||||
let didRewrite = false;
|
||||
const urlParts = (req.url || '').split('?', 1);
|
||||
const urlNoQuery = urlParts[0];
|
||||
// Refresh the routes every time in development mode, but only initialize them
|
||||
// once in production. We don't need to recompute these every time unless the routes
|
||||
// are changing like in development, and the performance can be costly.
|
||||
if (!routes || opts.dev) {
|
||||
routes = calculateRoutes();
|
||||
}
|
||||
// this normalizes repeated slashes in the path e.g. hello//world ->
|
||||
// hello/world or backslashes to forward slashes, this does not
|
||||
// handle trailing slash as that is handled the same as a next.config.js
|
||||
// redirect
|
||||
if (urlNoQuery == null ? void 0 : urlNoQuery.match(/(\\|\/\/)/)) {
|
||||
parsedUrl = (0, _parseurl.parseUrl)((0, _utils2.normalizeRepeatedSlashes)(req.url));
|
||||
return {
|
||||
parsedUrl,
|
||||
resHeaders,
|
||||
finished: true,
|
||||
statusCode: 308
|
||||
};
|
||||
}
|
||||
// TODO: inherit this from higher up
|
||||
const protocol = (req == null ? void 0 : (_req_socket = req.socket) == null ? void 0 : _req_socket.encrypted) || ((_req_headers_xforwardedproto = req.headers['x-forwarded-proto']) == null ? void 0 : _req_headers_xforwardedproto.includes('https')) ? 'https' : 'http';
|
||||
// When there are hostname and port we build an absolute URL
|
||||
const initUrl = config.experimental.trustHostHeader ? `https://${req.headers.host || 'localhost'}${req.url}` : opts.port ? `${protocol}://${(0, _formathostname.formatHostname)(opts.hostname || 'localhost')}:${opts.port}${req.url}` : req.url || '';
|
||||
(0, _requestmeta.addRequestMeta)(req, 'initURL', initUrl);
|
||||
(0, _requestmeta.addRequestMeta)(req, 'initQuery', {
|
||||
...parsedUrl.query
|
||||
});
|
||||
(0, _requestmeta.addRequestMeta)(req, 'initProtocol', protocol);
|
||||
if (!isUpgradeReq) {
|
||||
const bodySizeLimit = config.experimental.proxyClientMaxBodySize;
|
||||
(0, _requestmeta.addRequestMeta)(req, 'clonableBody', (0, _bodystreams.getCloneableBody)(req, bodySizeLimit));
|
||||
}
|
||||
const maybeAddTrailingSlash = (pathname)=>{
|
||||
if (config.trailingSlash && !config.skipProxyUrlNormalize && !pathname.endsWith('/')) {
|
||||
return `${pathname}/`;
|
||||
}
|
||||
return pathname;
|
||||
};
|
||||
let domainLocale;
|
||||
let defaultLocale;
|
||||
let initialLocaleResult = undefined;
|
||||
if (config.i18n) {
|
||||
var _parsedUrl_pathname;
|
||||
const hadTrailingSlash = (_parsedUrl_pathname = parsedUrl.pathname) == null ? void 0 : _parsedUrl_pathname.endsWith('/');
|
||||
const hadBasePath = (0, _pathhasprefix.pathHasPrefix)(parsedUrl.pathname || '', config.basePath);
|
||||
let normalizedPath = parsedUrl.pathname || '/';
|
||||
if (config.basePath && (0, _pathhasprefix.pathHasPrefix)(normalizedPath, config.basePath)) {
|
||||
normalizedPath = (0, _removepathprefix.removePathPrefix)(normalizedPath, config.basePath);
|
||||
} else if (config.assetPrefix && (0, _pathhasprefix.pathHasPrefix)(normalizedPath, config.assetPrefix)) {
|
||||
normalizedPath = (0, _removepathprefix.removePathPrefix)(normalizedPath, config.assetPrefix);
|
||||
}
|
||||
initialLocaleResult = (0, _normalizelocalepath.normalizeLocalePath)(normalizedPath, config.i18n.locales);
|
||||
domainLocale = (0, _detectdomainlocale.detectDomainLocale)(config.i18n.domains, (0, _gethostname.getHostname)(parsedUrl, req.headers));
|
||||
defaultLocale = (domainLocale == null ? void 0 : domainLocale.defaultLocale) || config.i18n.defaultLocale;
|
||||
(0, _requestmeta.addRequestMeta)(req, 'defaultLocale', defaultLocale);
|
||||
(0, _requestmeta.addRequestMeta)(req, 'locale', initialLocaleResult.detectedLocale || defaultLocale);
|
||||
// ensure locale is present for resolving routes
|
||||
if (!initialLocaleResult.detectedLocale && !initialLocaleResult.pathname.startsWith('/_next/')) {
|
||||
parsedUrl.pathname = (0, _addpathprefix.addPathPrefix)(initialLocaleResult.pathname === '/' ? `/${defaultLocale}` : (0, _addpathprefix.addPathPrefix)(initialLocaleResult.pathname || '', `/${defaultLocale}`), hadBasePath ? config.basePath : '');
|
||||
if (hadTrailingSlash) {
|
||||
parsedUrl.pathname = maybeAddTrailingSlash(parsedUrl.pathname);
|
||||
}
|
||||
}
|
||||
}
|
||||
const checkLocaleApi = (pathname)=>{
|
||||
if (config.i18n && pathname === urlNoQuery && (initialLocaleResult == null ? void 0 : initialLocaleResult.detectedLocale) && (0, _pathhasprefix.pathHasPrefix)(initialLocaleResult.pathname, '/api')) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
async function checkTrue() {
|
||||
const pathname = parsedUrl.pathname || '/';
|
||||
if (checkLocaleApi(pathname)) {
|
||||
return;
|
||||
}
|
||||
if (!(invokedOutputs == null ? void 0 : invokedOutputs.has(pathname))) {
|
||||
const output = await fsChecker.getItem(pathname);
|
||||
if (output) {
|
||||
if (config.useFileSystemPublicRoutes || didRewrite || output.type !== 'appFile' && output.type !== 'pageFile') {
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
||||
const dynamicRoutes = fsChecker.getDynamicRoutes();
|
||||
let curPathname = parsedUrl.pathname;
|
||||
if (config.basePath) {
|
||||
if (!(0, _pathhasprefix.pathHasPrefix)(curPathname || '', config.basePath)) {
|
||||
return;
|
||||
}
|
||||
curPathname = (curPathname == null ? void 0 : curPathname.substring(config.basePath.length)) || '/';
|
||||
}
|
||||
const localeResult = fsChecker.handleLocale(curPathname || '');
|
||||
for (const route of dynamicRoutes){
|
||||
// when resolving fallback: false the
|
||||
// render worker may return a no-fallback response
|
||||
// which signals we need to continue resolving.
|
||||
// TODO: optimize this to collect static paths
|
||||
// to use at the routing layer
|
||||
if (invokedOutputs == null ? void 0 : invokedOutputs.has(route.page)) {
|
||||
continue;
|
||||
}
|
||||
const params = route.match(localeResult.pathname);
|
||||
if (params) {
|
||||
const pageOutput = await fsChecker.getItem((0, _addpathprefix.addPathPrefix)(route.page, config.basePath || ''));
|
||||
// i18n locales aren't matched for app dir
|
||||
if ((pageOutput == null ? void 0 : pageOutput.type) === 'appFile' && (initialLocaleResult == null ? void 0 : initialLocaleResult.detectedLocale)) {
|
||||
continue;
|
||||
}
|
||||
if (pageOutput && (curPathname == null ? void 0 : curPathname.startsWith('/_next/data'))) {
|
||||
(0, _requestmeta.addRequestMeta)(req, 'isNextDataReq', true);
|
||||
}
|
||||
if (config.useFileSystemPublicRoutes || didRewrite) {
|
||||
return pageOutput;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const normalizers = {
|
||||
basePath: config.basePath && config.basePath !== '/' ? new _basepath.BasePathPathnameNormalizer(config.basePath) : undefined,
|
||||
data: new _nextdata.NextDataPathnameNormalizer(fsChecker.buildId)
|
||||
};
|
||||
async function handleRoute(route) {
|
||||
let curPathname = parsedUrl.pathname || '/';
|
||||
if (config.i18n && route.internal) {
|
||||
const hadTrailingSlash = curPathname.endsWith('/');
|
||||
if (config.basePath) {
|
||||
curPathname = (0, _removepathprefix.removePathPrefix)(curPathname, config.basePath);
|
||||
}
|
||||
const hadBasePath = curPathname !== parsedUrl.pathname;
|
||||
const localeResult = (0, _normalizelocalepath.normalizeLocalePath)(curPathname, config.i18n.locales);
|
||||
const isDefaultLocale = localeResult.detectedLocale === defaultLocale;
|
||||
if (isDefaultLocale) {
|
||||
curPathname = localeResult.pathname === '/' && hadBasePath ? config.basePath : (0, _addpathprefix.addPathPrefix)(localeResult.pathname, hadBasePath ? config.basePath : '');
|
||||
} else if (hadBasePath) {
|
||||
curPathname = curPathname === '/' ? config.basePath : (0, _addpathprefix.addPathPrefix)(curPathname, config.basePath);
|
||||
}
|
||||
if ((isDefaultLocale || hadBasePath) && hadTrailingSlash) {
|
||||
curPathname = maybeAddTrailingSlash(curPathname);
|
||||
}
|
||||
}
|
||||
let params = route.match(curPathname);
|
||||
if ((route.has || route.missing) && params) {
|
||||
const hasParams = (0, _preparedestination.matchHas)(req, parsedUrl.query, route.has, route.missing);
|
||||
if (hasParams) {
|
||||
Object.assign(params, hasParams);
|
||||
} else {
|
||||
params = false;
|
||||
}
|
||||
}
|
||||
if (params) {
|
||||
if (fsChecker.exportPathMapRoutes && route.name === 'before_files_end') {
|
||||
for (const exportPathMapRoute of fsChecker.exportPathMapRoutes){
|
||||
const result = await handleRoute(exportPathMapRoute);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (route.name === 'middleware_next_data' && parsedUrl.pathname) {
|
||||
var _fsChecker_getMiddlewareMatchers;
|
||||
if ((_fsChecker_getMiddlewareMatchers = fsChecker.getMiddlewareMatchers()) == null ? void 0 : _fsChecker_getMiddlewareMatchers.length) {
|
||||
var _normalizers_basePath;
|
||||
let normalized = parsedUrl.pathname;
|
||||
// Remove the base path if it exists.
|
||||
const hadBasePath = (_normalizers_basePath = normalizers.basePath) == null ? void 0 : _normalizers_basePath.match(parsedUrl.pathname);
|
||||
if (hadBasePath && normalizers.basePath) {
|
||||
normalized = normalizers.basePath.normalize(normalized, true);
|
||||
}
|
||||
let updated = false;
|
||||
if (normalizers.data.match(normalized)) {
|
||||
updated = true;
|
||||
(0, _requestmeta.addRequestMeta)(req, 'isNextDataReq', true);
|
||||
normalized = normalizers.data.normalize(normalized, true);
|
||||
}
|
||||
if (config.i18n) {
|
||||
const curLocaleResult = (0, _normalizelocalepath.normalizeLocalePath)(normalized, config.i18n.locales);
|
||||
if (curLocaleResult.detectedLocale) {
|
||||
(0, _requestmeta.addRequestMeta)(req, 'locale', curLocaleResult.detectedLocale);
|
||||
}
|
||||
}
|
||||
// If we updated the pathname, and it had a base path, re-add the
|
||||
// base path.
|
||||
if (updated) {
|
||||
if (hadBasePath) {
|
||||
normalized = normalized === '/' ? config.basePath : _nodepath.default.posix.join(config.basePath, normalized);
|
||||
}
|
||||
// Re-add the trailing slash (if required).
|
||||
normalized = maybeAddTrailingSlash(normalized);
|
||||
parsedUrl.pathname = normalized;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (route.name === 'check_fs') {
|
||||
const pathname = parsedUrl.pathname || '/';
|
||||
if ((invokedOutputs == null ? void 0 : invokedOutputs.has(pathname)) || checkLocaleApi(pathname)) {
|
||||
return;
|
||||
}
|
||||
const output = await fsChecker.getItem(pathname);
|
||||
if (output && !(config.i18n && (initialLocaleResult == null ? void 0 : initialLocaleResult.detectedLocale) && (0, _pathhasprefix.pathHasPrefix)(pathname, '/api'))) {
|
||||
if (config.useFileSystemPublicRoutes || didRewrite || output.type !== 'appFile' && output.type !== 'pageFile') {
|
||||
matchedOutput = output;
|
||||
if (output.locale) {
|
||||
(0, _requestmeta.addRequestMeta)(req, 'locale', output.locale);
|
||||
}
|
||||
if (process.env.__NEXT_TEST_MODE && process.env.IS_TURBOPACK_TEST && output.type === 'nextStaticFolder' && config.deploymentId) {
|
||||
let useImmutableToken = config.experimental.immutableAssetToken && clientHashes[`static${decodeURI(output.itemPath)}`];
|
||||
const expectedToken = useImmutableToken ? config.experimental.immutableAssetToken : config.deploymentId;
|
||||
if (parsedUrl.query.dpl !== expectedToken) {
|
||||
console.error(`Invalid dpl query param: ${req.url}, expected: ${expectedToken}`);
|
||||
return {
|
||||
finished: true,
|
||||
parsedUrl,
|
||||
resHeaders,
|
||||
matchedOutput: null
|
||||
};
|
||||
}
|
||||
}
|
||||
return {
|
||||
parsedUrl,
|
||||
resHeaders,
|
||||
finished: true,
|
||||
matchedOutput
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!opts.minimalMode && route.name === 'middleware') {
|
||||
const match = fsChecker.getMiddlewareMatchers();
|
||||
let maybeDecodedPathname = parsedUrl.pathname || '/';
|
||||
try {
|
||||
maybeDecodedPathname = decodeURIComponent(maybeDecodedPathname);
|
||||
} catch {
|
||||
/* non-fatal we can't decode so can't match it */ }
|
||||
if (// @ts-expect-error BaseNextRequest stuff
|
||||
(match == null ? void 0 : match(parsedUrl.pathname, req, parsedUrl.query)) || (match == null ? void 0 : match(maybeDecodedPathname, // @ts-expect-error BaseNextRequest stuff
|
||||
req, parsedUrl.query))) {
|
||||
if (ensureMiddleware) {
|
||||
await ensureMiddleware(req.url);
|
||||
}
|
||||
const serverResult = await (renderServer == null ? void 0 : renderServer.initialize(renderServerOpts));
|
||||
if (!serverResult) {
|
||||
throw Object.defineProperty(new Error(`Failed to initialize render server "middleware"`), "__NEXT_ERROR_CODE", {
|
||||
value: "E222",
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
});
|
||||
}
|
||||
(0, _requestmeta.addRequestMeta)(req, 'invokePath', '');
|
||||
(0, _requestmeta.addRequestMeta)(req, 'invokeOutput', '');
|
||||
(0, _requestmeta.addRequestMeta)(req, 'invokeQuery', {});
|
||||
(0, _requestmeta.addRequestMeta)(req, 'middlewareInvoke', true);
|
||||
if (opts.dev) {
|
||||
(0, _requestmeta.addRequestMeta)(req, 'devRequestTimingMiddlewareStart', process.hrtime.bigint());
|
||||
}
|
||||
debug('invoking middleware', req.url, req.headers);
|
||||
let middlewareRes = undefined;
|
||||
let bodyStream = undefined;
|
||||
try {
|
||||
try {
|
||||
await serverResult.requestHandler(req, res, parsedUrl);
|
||||
} catch (err) {
|
||||
if (!('result' in err) || !('response' in err.result)) {
|
||||
throw err;
|
||||
}
|
||||
middlewareRes = err.result.response;
|
||||
res.statusCode = middlewareRes.status;
|
||||
if (middlewareRes.body) {
|
||||
bodyStream = middlewareRes.body;
|
||||
} else if (middlewareRes.status) {
|
||||
bodyStream = new ReadableStream({
|
||||
start (controller) {
|
||||
controller.enqueue('');
|
||||
controller.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
} finally{
|
||||
if (opts.dev) {
|
||||
(0, _requestmeta.addRequestMeta)(req, 'devRequestTimingMiddlewareEnd', process.hrtime.bigint());
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// If the client aborts before we can receive a response object
|
||||
// (when the headers are flushed), then we can early exit without
|
||||
// further processing.
|
||||
if ((0, _pipereadable.isAbortError)(e)) {
|
||||
return {
|
||||
parsedUrl,
|
||||
resHeaders,
|
||||
finished: true
|
||||
};
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
if (res.closed || res.finished || !middlewareRes) {
|
||||
return {
|
||||
parsedUrl,
|
||||
resHeaders,
|
||||
finished: true
|
||||
};
|
||||
}
|
||||
const middlewareHeaders = (0, _utils1.toNodeOutgoingHttpHeaders)(middlewareRes.headers);
|
||||
debug('middleware res', middlewareRes.status, middlewareHeaders);
|
||||
if (middlewareHeaders['x-middleware-override-headers']) {
|
||||
const overriddenHeaders = new Set();
|
||||
let overrideHeaders = middlewareHeaders['x-middleware-override-headers'];
|
||||
if (typeof overrideHeaders === 'string') {
|
||||
overrideHeaders = overrideHeaders.split(',');
|
||||
}
|
||||
for (const key of overrideHeaders){
|
||||
overriddenHeaders.add(key.trim());
|
||||
}
|
||||
delete middlewareHeaders['x-middleware-override-headers'];
|
||||
// Delete headers.
|
||||
for (const key of Object.keys(req.headers)){
|
||||
if (!overriddenHeaders.has(key)) {
|
||||
delete req.headers[key];
|
||||
}
|
||||
}
|
||||
// Update or add headers.
|
||||
for (const key of overriddenHeaders.keys()){
|
||||
const valueKey = 'x-middleware-request-' + key;
|
||||
const newValue = middlewareHeaders[valueKey];
|
||||
const oldValue = req.headers[key];
|
||||
if (oldValue !== newValue) {
|
||||
req.headers[key] = newValue === null ? undefined : newValue;
|
||||
}
|
||||
delete middlewareHeaders[valueKey];
|
||||
}
|
||||
}
|
||||
if (!middlewareHeaders['x-middleware-rewrite'] && !middlewareHeaders['x-middleware-next'] && !middlewareHeaders['location']) {
|
||||
middlewareHeaders['x-middleware-refresh'] = '1';
|
||||
}
|
||||
delete middlewareHeaders['x-middleware-next'];
|
||||
for (const [key, value] of Object.entries({
|
||||
...(0, _utils.filterReqHeaders)(middlewareHeaders, _utils.ipcForbiddenHeaders)
|
||||
})){
|
||||
if ([
|
||||
'content-length',
|
||||
'x-middleware-rewrite',
|
||||
'x-middleware-redirect',
|
||||
'x-middleware-refresh'
|
||||
].includes(key)) {
|
||||
continue;
|
||||
}
|
||||
// for set-cookie, the header shouldn't be added to the response
|
||||
// as it's only needed for the request to the middleware function.
|
||||
if (key === 'x-middleware-set-cookie') {
|
||||
req.headers[key] = value;
|
||||
continue;
|
||||
}
|
||||
if (value) {
|
||||
resHeaders[key] = value;
|
||||
req.headers[key] = value;
|
||||
}
|
||||
}
|
||||
if (middlewareHeaders['x-middleware-rewrite']) {
|
||||
const value = middlewareHeaders['x-middleware-rewrite'];
|
||||
const destination = (0, _relativizeurl.getRelativeURL)(value, initUrl);
|
||||
resHeaders['x-middleware-rewrite'] = destination;
|
||||
parsedUrl = (0, _parseurl.parseUrl)(destination);
|
||||
if (parsedUrl.protocol) {
|
||||
return {
|
||||
parsedUrl,
|
||||
resHeaders,
|
||||
finished: true
|
||||
};
|
||||
}
|
||||
if (config.i18n) {
|
||||
const curLocaleResult = (0, _normalizelocalepath.normalizeLocalePath)(parsedUrl.pathname || '', config.i18n.locales);
|
||||
if (curLocaleResult.detectedLocale) {
|
||||
(0, _requestmeta.addRequestMeta)(req, 'locale', curLocaleResult.detectedLocale);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (middlewareHeaders['location']) {
|
||||
const value = middlewareHeaders['location'];
|
||||
// Only process Location header as a redirect if it has a proper redirect status
|
||||
// This prevents a Location header with non-redirect status from being treated as a redirect
|
||||
const isRedirectStatus = _redirectstatus.allowedStatusCodes.has(middlewareRes.status);
|
||||
if (isRedirectStatus) {
|
||||
// Process as redirect: update parsedUrl and convert to relative URL
|
||||
const rel = (0, _relativizeurl.getRelativeURL)(value, initUrl);
|
||||
resHeaders['location'] = rel;
|
||||
parsedUrl = (0, _parseurl.parseUrl)(rel);
|
||||
return {
|
||||
parsedUrl,
|
||||
resHeaders,
|
||||
finished: true,
|
||||
statusCode: middlewareRes.status
|
||||
};
|
||||
} else {
|
||||
// Not a redirect: just pass through the Location header
|
||||
resHeaders['location'] = value;
|
||||
return {
|
||||
parsedUrl,
|
||||
resHeaders,
|
||||
finished: true,
|
||||
bodyStream,
|
||||
statusCode: middlewareRes.status
|
||||
};
|
||||
}
|
||||
}
|
||||
if (middlewareHeaders['x-middleware-refresh']) {
|
||||
return {
|
||||
parsedUrl,
|
||||
resHeaders,
|
||||
finished: true,
|
||||
bodyStream,
|
||||
statusCode: middlewareRes.status
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
// handle redirect
|
||||
if (('statusCode' in route || 'permanent' in route) && route.destination) {
|
||||
const { parsedDestination } = (0, _preparedestination.prepareDestination)({
|
||||
appendParamsToQuery: false,
|
||||
destination: route.destination,
|
||||
params: params,
|
||||
query: parsedUrl.query
|
||||
});
|
||||
const { query } = parsedDestination;
|
||||
delete parsedDestination.query;
|
||||
parsedDestination.search = (0, _serverrouteutils.stringifyQuery)(req, query);
|
||||
parsedDestination.pathname = (0, _utils2.normalizeRepeatedSlashes)(parsedDestination.pathname);
|
||||
return {
|
||||
finished: true,
|
||||
parsedUrl: parsedDestination,
|
||||
resHeaders: null,
|
||||
statusCode: (0, _redirectstatus.getRedirectStatus)(route)
|
||||
};
|
||||
}
|
||||
// handle headers
|
||||
if (route.headers) {
|
||||
const hasParams = Object.keys(params).length > 0;
|
||||
for (const header of route.headers){
|
||||
let { key, value } = header;
|
||||
if (hasParams) {
|
||||
key = (0, _preparedestination.compileNonPath)(key, params);
|
||||
value = (0, _preparedestination.compileNonPath)(value, params);
|
||||
}
|
||||
if (key.toLowerCase() === 'set-cookie') {
|
||||
if (!Array.isArray(resHeaders[key])) {
|
||||
const val = resHeaders[key];
|
||||
resHeaders[key] = typeof val === 'string' ? [
|
||||
val
|
||||
] : [];
|
||||
}
|
||||
;
|
||||
resHeaders[key].push(value);
|
||||
} else {
|
||||
resHeaders[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
// handle rewrite
|
||||
if (route.destination) {
|
||||
var _config_experimental_clientParamParsingOrigins;
|
||||
let rewriteParams = params;
|
||||
const { parsedDestination } = (0, _preparedestination.prepareDestination)({
|
||||
appendParamsToQuery: true,
|
||||
destination: route.destination,
|
||||
params: rewriteParams,
|
||||
query: parsedUrl.query
|
||||
});
|
||||
// Check to see if this is a non-relative rewrite. If it is, we need
|
||||
// to check to see if it's an allowed origin to receive the rewritten
|
||||
// headers.
|
||||
const parsedDestinationOrigin = parsedDestination.origin;
|
||||
const isAllowedOrigin = parsedDestinationOrigin ? (_config_experimental_clientParamParsingOrigins = config.experimental.clientParamParsingOrigins) == null ? void 0 : _config_experimental_clientParamParsingOrigins.some((origin)=>new RegExp(origin).test(parsedDestinationOrigin)) : false;
|
||||
// Set the rewrite headers only if this is a RSC request.
|
||||
if (req.headers[_approuterheaders.RSC_HEADER] === '1' && (!parsedDestination.origin || isAllowedOrigin)) {
|
||||
// We set the rewritten path and query headers on the response now
|
||||
// that we know that the it's not an external rewrite.
|
||||
if (parsedUrl.pathname !== parsedDestination.pathname) {
|
||||
res.setHeader(_approuterheaders.NEXT_REWRITTEN_PATH_HEADER, parsedDestination.pathname);
|
||||
}
|
||||
if (parsedUrl.search !== parsedDestination.search) {
|
||||
res.setHeader(_approuterheaders.NEXT_REWRITTEN_QUERY_HEADER, // remove the leading ? from the search
|
||||
parsedDestination.search.slice(1));
|
||||
}
|
||||
}
|
||||
if (parsedDestination.protocol) {
|
||||
return {
|
||||
parsedUrl: parsedDestination,
|
||||
resHeaders: null,
|
||||
finished: true
|
||||
};
|
||||
}
|
||||
if (config.i18n) {
|
||||
const curLocaleResult = (0, _normalizelocalepath.normalizeLocalePath)((0, _removepathprefix.removePathPrefix)(parsedDestination.pathname, config.basePath), config.i18n.locales);
|
||||
if (curLocaleResult.detectedLocale) {
|
||||
(0, _requestmeta.addRequestMeta)(req, 'locale', curLocaleResult.detectedLocale);
|
||||
}
|
||||
}
|
||||
didRewrite = true;
|
||||
parsedUrl.pathname = parsedDestination.pathname;
|
||||
Object.assign(parsedUrl.query, parsedDestination.query);
|
||||
}
|
||||
// handle check: true
|
||||
if (route.check) {
|
||||
const output = await checkTrue();
|
||||
if (output) {
|
||||
return {
|
||||
parsedUrl,
|
||||
resHeaders,
|
||||
finished: true,
|
||||
matchedOutput: output
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const route of routes){
|
||||
const result = await handleRoute(route);
|
||||
if (result) {
|
||||
if (result.matchedOutput) {
|
||||
// handle onMatchHeaders
|
||||
for (const onMatchHeaders of fsChecker.onMatchHeaders){
|
||||
await handleRoute(onMatchHeaders);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return {
|
||||
finished,
|
||||
parsedUrl,
|
||||
resHeaders,
|
||||
matchedOutput
|
||||
};
|
||||
}
|
||||
return resolveRoutes;
|
||||
}
|
||||
|
||||
//# sourceMappingURL=resolve-routes.js.map
|
||||
Reference in New Issue
Block a user