Skip to content

Commit

Permalink
Refactor decode failures (#26899)
Browse files Browse the repository at this point in the history
  • Loading branch information
devknoll authored Jul 5, 2021
1 parent f1fe4bb commit 402f036
Show file tree
Hide file tree
Showing 7 changed files with 28 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { parse as parseUrl } from 'url'
import { IncomingMessage, ServerResponse } from 'http'
import { apiResolver } from '../../../../server/api-utils'
import { getUtils, vercelHeader, ServerlessHandlerCtx } from './utils'
import { DecodeError } from '../../../../shared/lib/utils'

export function getApiHandler(ctx: ServerlessHandlerCtx) {
const { pageModule, encodedPreviewProps, pageIsDynamic } = ctx
Expand Down Expand Up @@ -50,8 +51,7 @@ export function getApiHandler(ctx: ServerlessHandlerCtx) {
} catch (err) {
console.error(err)

// TODO: better error for DECODE_FAILED?
if (err.code === 'DECODE_FAILED') {
if (err instanceof DecodeError) {
res.statusCode = 400
res.end('Bad Request')
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { IncomingMessage, ServerResponse } from 'http'
import { parse as parseUrl, format as formatUrl, UrlWithParsedQuery } from 'url'
import { isResSent } from '../../../../shared/lib/utils'
import { DecodeError, isResSent } from '../../../../shared/lib/utils'
import { sendPayload } from '../../../../server/send-payload'
import { getUtils, vercelHeader, ServerlessHandlerCtx } from './utils'

Expand Down Expand Up @@ -409,8 +409,7 @@ export function getPageHandler(ctx: ServerlessHandlerCtx) {

if (err.code === 'ENOENT') {
res.statusCode = 404
} else if (err.code === 'DECODE_FAILED' || err.code === 'ENAMETOOLONG') {
// TODO: better error?
} else if (err instanceof DecodeError) {
res.statusCode = 400
} else {
console.error('Unhandled error during request:', err)
Expand Down
7 changes: 2 additions & 5 deletions packages/next/server/dev/hot-reloader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { stringify } from 'querystring'
import { difference } from '../../build/utils'
import { NextConfig } from '../config'
import { CustomRoutes } from '../../lib/load-custom-routes'
import { DecodeError } from '../../shared/lib/utils'

export async function renderScriptError(
res: ServerResponse,
Expand Down Expand Up @@ -212,11 +213,7 @@ export default class HotReloader {
.map((param) => decodeURIComponent(param))
.join('/')}`
} catch (_) {
const err: Error & { code?: string } = new Error(
'failed to decode param'
)
err.code = 'DECODE_FAILED'
throw err
throw new DecodeError('failed to decode param')
}

const page = denormalizePagePath(decodedPagePath)
Expand Down
5 changes: 2 additions & 3 deletions packages/next/server/dev/next-dev-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import {
LoadComponentsReturnType,
loadDefaultErrorComponents,
} from '../load-components'
import { DecodeError } from '../../shared/lib/utils'

if (typeof React.Suspense === 'undefined') {
throw new Error(
Expand Down Expand Up @@ -376,9 +377,7 @@ export default class DevServer extends Server {
try {
decodedPath = decodeURIComponent(path)
} catch (_) {
const err: Error & { code?: string } = new Error('failed to decode param')
err.code = 'DECODE_FAILED'
throw err
throw new DecodeError('failed to decode param')
}

if (await this.hasPublicFile(decodedPath)) {
Expand Down
35 changes: 16 additions & 19 deletions packages/next/server/next-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,12 @@ import {
isDynamicRoute,
} from '../shared/lib/router/utils'
import * as envConfig from '../shared/lib/runtime-config'
import { isResSent, NextApiRequest, NextApiResponse } from '../shared/lib/utils'
import {
DecodeError,
isResSent,
NextApiRequest,
NextApiResponse,
} from '../shared/lib/utils'
import {
apiResolver,
setLazyProp,
Expand Down Expand Up @@ -1276,7 +1281,7 @@ export default class Server {
return
}
} catch (err) {
if (err.code === 'DECODE_FAILED' || err.code === 'ENAMETOOLONG') {
if (err instanceof DecodeError) {
res.statusCode = 400
return this.renderError(null, req, res, '/_error', {})
}
Expand Down Expand Up @@ -1381,16 +1386,15 @@ export default class Server {
pagePath!,
!this.renderOpts.dev && this._isLikeServerless
)
// if loading an static HTML file the locale is required
// to be present since all HTML files are output under their locale

if (
query.__nextLocale &&
typeof components.Component === 'string' &&
!pagePath?.startsWith(`/${query.__nextLocale}`)
) {
const err = new Error('NOT_FOUND')
;(err as any).code = 'ENOENT'
throw err
// if loading an static HTML file the locale is required
// to be present since all HTML files are output under their locale
continue
}

return {
Expand Down Expand Up @@ -1589,13 +1593,8 @@ export default class Server {
try {
seg = escapePathDelimiters(decodeURIComponent(seg), true)
} catch (_) {
// An improperly encoded URL was provided, this is considered
// a bad request (400)
const err: Error & { code?: string } = new Error(
'failed to decode param'
)
err.code = 'DECODE_FAILED'
throw err
// An improperly encoded URL was provided
throw new DecodeError('failed to decode param')
}
return seg
})
Expand Down Expand Up @@ -1962,16 +1961,14 @@ export default class Server {
}
}
} catch (err) {
const isNoFallbackError = err instanceof NoFallbackError

if (isNoFallbackError && bubbleNoFallback) {
if (err instanceof NoFallbackError && bubbleNoFallback) {
throw err
}

if (err && err.code === 'DECODE_FAILED') {
if (err instanceof DecodeError) {
res.statusCode = 400
return await this.renderErrorToHTML(err, req, res, pathname, query)
}

res.statusCode = 500
const isWrappedError = err instanceof WrappedBuildError
const html = await this.renderErrorToHTML(
Expand Down
7 changes: 2 additions & 5 deletions packages/next/shared/lib/router/utils/route-matcher.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { DecodeError } from '../../utils'
import { getRouteRegex } from './route-regex'

export function getRouteMatcher(routeRegex: ReturnType<typeof getRouteRegex>) {
Expand All @@ -12,11 +13,7 @@ export function getRouteMatcher(routeRegex: ReturnType<typeof getRouteRegex>) {
try {
return decodeURIComponent(param)
} catch (_) {
const err: Error & { code?: string } = new Error(
'failed to decode param'
)
err.code = 'DECODE_FAILED'
throw err
throw new DecodeError('failed to decode param')
}
}
const params: { [paramName: string]: string | string[] } = {}
Expand Down
2 changes: 2 additions & 0 deletions packages/next/shared/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -406,3 +406,5 @@ export const ST =
SP &&
typeof performance.mark === 'function' &&
typeof performance.measure === 'function'

export class DecodeError extends Error {}

0 comments on commit 402f036

Please sign in to comment.