1
0
Fork 0
mirror of https://github.com/terribleplan/next.js.git synced 2024-01-19 02:48:18 +00:00

Handle decoding errors correctly (#5589)

Fixes #4887
Fixes #3612

Also removes http-errors dependency from next-server, leaving a smaller install size
This commit is contained in:
Tim Neutkens 2018-11-04 01:22:33 +01:00 committed by GitHub
parent 15854f515b
commit 54b9df535d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 22 additions and 9 deletions

View file

@ -32,7 +32,6 @@
"fresh": "0.5.2", "fresh": "0.5.2",
"hoist-non-react-statics": "^3.0.1", "hoist-non-react-statics": "^3.0.1",
"htmlescape": "1.1.1", "htmlescape": "1.1.1",
"http-errors": "1.6.2",
"path-to-regexp": "2.1.0", "path-to-regexp": "2.1.0",
"prop-types": "15.6.2", "prop-types": "15.6.2",
"send": "0.16.1", "send": "0.16.1",

View file

@ -3,7 +3,6 @@
// So, it'll give us issues when the app has used a newer version of path-to-regexp // So, it'll give us issues when the app has used a newer version of path-to-regexp
// (When webpack resolving packages) // (When webpack resolving packages)
var pathToRegexp = require('path-to-regexp') var pathToRegexp = require('path-to-regexp')
var createError = require('http-errors')
module.exports = function (options) { module.exports = function (options) {
options = options || {} options = options || {}
@ -36,6 +35,8 @@ function decodeParam (param) {
try { try {
return decodeURIComponent(param) return decodeURIComponent(param)
} catch (_) { } catch (_) {
throw createError(400, 'failed to decode param "' + param + '"') const err = new Error('failed to decode param')
err.code = 'DECODE_FAILED'
throw err
} }
} }

View file

@ -150,11 +150,19 @@ export default class Server {
} }
async run (req, res, parsedUrl) { async run (req, res, parsedUrl) {
try {
const fn = this.router.match(req, res, parsedUrl) const fn = this.router.match(req, res, parsedUrl)
if (fn) { if (fn) {
await fn() await fn()
return return
} }
} catch (err) {
if (err.code === 'DECODE_FAILED') {
res.statusCode = 400
return this.renderError(null, req, res, '/_error', {})
}
throw err
}
if (req.method === 'GET' || req.method === 'HEAD') { if (req.method === 'GET' || req.method === 'HEAD') {
await this.render404(req, res, parsedUrl) await this.render404(req, res, parsedUrl)
@ -201,6 +209,7 @@ export default class Server {
} }
async renderError (err, req, res, pathname, query) { async renderError (err, req, res, pathname, query) {
res.setHeader('Cache-Control', 'no-cache, no-store, max-age=0, must-revalidate')
const html = await this.renderErrorToHTML(err, req, res, pathname, query) const html = await this.renderErrorToHTML(err, req, res, pathname, query)
return sendHTML(req, res, html, req.method, this.renderOpts) return sendHTML(req, res, html, req.method, this.renderOpts)
} }
@ -212,7 +221,6 @@ export default class Server {
async render404 (req, res, parsedUrl = parseUrl(req.url, true)) { async render404 (req, res, parsedUrl = parseUrl(req.url, true)) {
const { pathname, query } = parsedUrl const { pathname, query } = parsedUrl
res.statusCode = 404 res.statusCode = 404
res.setHeader('Cache-Control', 'no-cache, no-store, max-age=0, must-revalidate')
return this.renderError(null, req, res, pathname, query) return this.renderError(null, req, res, pathname, query)
} }

View file

@ -64,7 +64,6 @@
"glob": "7.1.2", "glob": "7.1.2",
"hoist-non-react-statics": "2.5.5", "hoist-non-react-statics": "2.5.5",
"htmlescape": "1.1.1", "htmlescape": "1.1.1",
"http-errors": "1.6.2",
"http-status": "1.0.1", "http-status": "1.0.1",
"launch-editor": "2.2.1", "launch-editor": "2.2.1",
"loader-utils": "1.1.0", "loader-utils": "1.1.0",

View file

@ -291,6 +291,12 @@ describe('Production Usage', () => {
expect(serverSideJsBody).toMatch(/404/) expect(serverSideJsBody).toMatch(/404/)
}) })
it('should handle failed param decoding', async () => {
const html = await renderViaHTTP(appPort, '/%DE~%C7%1fY/')
expect(html).toMatch(/400/)
expect(html).toMatch(/Bad Request/)
})
dynamicImportTests(context, (p, q) => renderViaHTTP(context.appPort, p, q)) dynamicImportTests(context, (p, q) => renderViaHTTP(context.appPort, p, q))
processEnv(context) processEnv(context)