Skip to content

Commit bd3dfe1

Browse files
ijjktimneutkens
andauthored
Update status code for normalize error (#36580)
This updates to show a 400 (bad request) when an invalid path is sent to Next.js similar to our decode failure handling. ## Bug - [x] Related issues linked using `fixes #number` - [x] Integration tests added - [ ] Errors have helpful link attached, see `contributing.md` Closes: #36555 Co-authored-by: Tim Neutkens <[email protected]>
1 parent 7a09f88 commit bd3dfe1

File tree

4 files changed

+18
-14
lines changed

4 files changed

+18
-14
lines changed

packages/next/server/base-server.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,12 @@ import type { ParsedUrlQuery } from 'querystring'
1111
import type { RenderOpts, RenderOptsPartial } from './render'
1212
import type { ResponseCacheEntry, ResponseCacheValue } from './response-cache'
1313
import type { UrlWithParsedQuery } from 'url'
14-
import type { CacheFs } from '../shared/lib/utils'
14+
import {
15+
CacheFs,
16+
NormalizeError,
17+
DecodeError,
18+
normalizeRepeatedSlashes,
19+
} from '../shared/lib/utils'
1520
import type { PreviewData } from 'next/types'
1621
import type { PagesManifest } from '../build/webpack/plugins/pages-manifest-plugin'
1722
import type { BaseNextRequest, BaseNextResponse } from './base-http'
@@ -39,7 +44,6 @@ import {
3944
checkIsManualRevalidate,
4045
} from './api-utils'
4146
import * as envConfig from '../shared/lib/runtime-config'
42-
import { DecodeError, normalizeRepeatedSlashes } from '../shared/lib/utils'
4347
import { isTargetLikeServerless } from './utils'
4448
import Router from './router'
4549
import { getPathMatch } from '../shared/lib/router/utils/path-match'
@@ -564,7 +568,7 @@ export default abstract class Server<ServerOptions extends Options = Options> {
564568
])
565569
}
566570
} catch (err) {
567-
if (err instanceof DecodeError) {
571+
if (err instanceof DecodeError || err instanceof NormalizeError) {
568572
res.statusCode = 400
569573
return this.renderError(null, req, res, '/_error', {})
570574
}
@@ -612,7 +616,8 @@ export default abstract class Server<ServerOptions extends Options = Options> {
612616
} catch (err: any) {
613617
if (
614618
(err && typeof err === 'object' && err.code === 'ERR_INVALID_URL') ||
615-
err instanceof DecodeError
619+
err instanceof DecodeError ||
620+
err instanceof NormalizeError
616621
) {
617622
res.statusCode = 400
618623
return this.renderError(null, req, res, '/_error', {})
@@ -985,7 +990,7 @@ export default abstract class Server<ServerOptions extends Options = Options> {
985990
return
986991
}
987992
} catch (err) {
988-
if (err instanceof DecodeError) {
993+
if (err instanceof DecodeError || err instanceof NormalizeError) {
989994
res.statusCode = 400
990995
return this.renderError(null, req, res, '/_error', {})
991996
}
@@ -1745,7 +1750,7 @@ export default abstract class Server<ServerOptions extends Options = Options> {
17451750
if (err instanceof NoFallbackError && bubbleNoFallback) {
17461751
throw err
17471752
}
1748-
if (err instanceof DecodeError) {
1753+
if (err instanceof DecodeError || err instanceof NormalizeError) {
17491754
res.statusCode = 400
17501755
return await this.renderErrorToResponse(ctx, err)
17511756
}

packages/next/shared/lib/page-path/normalize-page-path.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { ensureLeadingSlash } from './ensure-leading-slash'
22
import { isDynamicRoute } from '../router/utils'
33
import { posix } from '../isomorphic/path'
4+
import { NormalizeError } from '../utils'
45

56
/**
67
* Takes a page and transforms it into its file counterpart ensuring that the
@@ -22,7 +23,7 @@ export function normalizePagePath(page: string): string {
2223

2324
const resolvedPage = posix.normalize(normalized)
2425
if (resolvedPage !== normalized) {
25-
throw new Error(
26+
throw new NormalizeError(
2627
`Requested and resolved page mismatch: ${normalized} ${resolvedPage}`
2728
)
2829
}

packages/next/shared/lib/utils.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,7 @@ export const ST =
397397
typeof performance.measure === 'function'
398398

399399
export class DecodeError extends Error {}
400+
export class NormalizeError extends Error {}
400401

401402
export interface CacheFs {
402403
readFile(f: string): Promise<string>

test/integration/production/test/security.js

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,7 @@ import { readFileSync } from 'fs'
55
import http from 'http'
66
import url from 'url'
77
import { join } from 'path'
8-
import {
9-
renderViaHTTP,
10-
getBrowserBodyText,
11-
waitFor,
12-
fetchViaHTTP,
13-
} from 'next-test-utils'
8+
import { getBrowserBodyText, waitFor, fetchViaHTTP } from 'next-test-utils'
149
import { recursiveReadDir } from 'next/dist/lib/recursive-readdir'
1510
import { homedir } from 'os'
1611

@@ -73,8 +68,10 @@ module.exports = (context) => {
7368
]
7469

7570
for (const path of pathsToCheck) {
76-
const data = await renderViaHTTP(context.appPort, path)
71+
const res = await fetchViaHTTP(context.appPort, path)
72+
const data = await res.text()
7773
expect(data.includes('cool-version')).toBeFalsy()
74+
expect([400, 404].includes(res.status)).toBeTruthy()
7875
}
7976
})
8077

0 commit comments

Comments
 (0)