diff --git a/packages/next/server/base-server.ts b/packages/next/server/base-server.ts index 1d76fa5df548e..0d66faa0451be 100644 --- a/packages/next/server/base-server.ts +++ b/packages/next/server/base-server.ts @@ -11,7 +11,12 @@ import type { ParsedUrlQuery } from 'querystring' import type { RenderOpts, RenderOptsPartial } from './render' import type { ResponseCacheEntry, ResponseCacheValue } from './response-cache' import type { UrlWithParsedQuery } from 'url' -import type { CacheFs } from '../shared/lib/utils' +import { + CacheFs, + NormalizeError, + DecodeError, + normalizeRepeatedSlashes, +} from '../shared/lib/utils' import type { PreviewData } from 'next/types' import type { PagesManifest } from '../build/webpack/plugins/pages-manifest-plugin' import type { BaseNextRequest, BaseNextResponse } from './base-http' @@ -39,7 +44,6 @@ import { checkIsManualRevalidate, } from './api-utils' import * as envConfig from '../shared/lib/runtime-config' -import { DecodeError, normalizeRepeatedSlashes } from '../shared/lib/utils' import { isTargetLikeServerless } from './utils' import Router from './router' import { getPathMatch } from '../shared/lib/router/utils/path-match' @@ -565,7 +569,7 @@ export default abstract class Server { ]) } } catch (err) { - if (err instanceof DecodeError) { + if (err instanceof DecodeError || err instanceof NormalizeError) { res.statusCode = 400 return this.renderError(null, req, res, '/_error', {}) } @@ -613,7 +617,8 @@ export default abstract class Server { } catch (err: any) { if ( (err && typeof err === 'object' && err.code === 'ERR_INVALID_URL') || - err instanceof DecodeError + err instanceof DecodeError || + err instanceof NormalizeError ) { res.statusCode = 400 return this.renderError(null, req, res, '/_error', {}) @@ -986,7 +991,7 @@ export default abstract class Server { return } } catch (err) { - if (err instanceof DecodeError) { + if (err instanceof DecodeError || err instanceof NormalizeError) { res.statusCode = 400 return this.renderError(null, req, res, '/_error', {}) } @@ -1746,7 +1751,7 @@ export default abstract class Server { if (err instanceof NoFallbackError && bubbleNoFallback) { throw err } - if (err instanceof DecodeError) { + if (err instanceof DecodeError || err instanceof NormalizeError) { res.statusCode = 400 return await this.renderErrorToResponse(ctx, err) } diff --git a/packages/next/server/normalize-page-path.ts b/packages/next/server/normalize-page-path.ts index 236504838d080..142098397929c 100644 --- a/packages/next/server/normalize-page-path.ts +++ b/packages/next/server/normalize-page-path.ts @@ -1,5 +1,6 @@ import { posix } from '../shared/lib/isomorphic/path' import { isDynamicRoute } from '../shared/lib/router/utils' +import { NormalizeError } from '../shared/lib/utils' export { normalizePathSep, denormalizePagePath } from './denormalize-page-path' @@ -17,7 +18,7 @@ export function normalizePagePath(page: string): string { // Throw when using ../ etc in the pathname const resolvedPage = posix.normalize(page) if (page !== resolvedPage) { - throw new Error( + throw new NormalizeError( `Requested and resolved page mismatch: ${page} ${resolvedPage}` ) } diff --git a/packages/next/shared/lib/utils.ts b/packages/next/shared/lib/utils.ts index 3896c7b492e33..20dbe91ea53f7 100644 --- a/packages/next/shared/lib/utils.ts +++ b/packages/next/shared/lib/utils.ts @@ -397,6 +397,7 @@ export const ST = typeof performance.measure === 'function' export class DecodeError extends Error {} +export class NormalizeError extends Error {} export interface CacheFs { readFile(f: string): Promise diff --git a/test/integration/production/test/security.js b/test/integration/production/test/security.js index 8a4778411b7a7..c456dea278406 100644 --- a/test/integration/production/test/security.js +++ b/test/integration/production/test/security.js @@ -73,8 +73,10 @@ module.exports = (context) => { ] for (const path of pathsToCheck) { - const data = await renderViaHTTP(context.appPort, path) + const res = await fetchViaHTTP(context.appPort, path) + const data = await res.text() expect(data.includes('cool-version')).toBeFalsy() + expect([400, 404].includes(res.status)).toBeTruthy() } })