Add opt-in 405 Method Not Allowed responses by EduardoAC · Pull Request #191 · pillarjs/router
Expand Up
@@ -65,6 +65,7 @@ function Router (options) {
router.caseSensitive = opts.caseSensitive router.mergeParams = opts.mergeParams router.methodNotAllowed = opts.methodNotAllowed router.params = {} router.strict = opts.strict router.stack = [] Expand Down Expand Up @@ -155,6 +156,7 @@ Router.prototype.handle = function handle (req, res, callback) {
let idx = 0 let methods let methodNotAllowed const protohost = getProtohost(req.url) || '' let removed = '' const self = this Expand All @@ -179,6 +181,14 @@ Router.prototype.handle = function handle (req, res, callback) { done = wrap(done, generateOptionsResponder(res, methods)) }
if (self.methodNotAllowed) { methodNotAllowed = { methods: [], methodMatched: false } done = wrap(done, generateMethodNotAllowedResponder(req, res, methodNotAllowed)) }
// setup basic req values req.baseUrl = parentUrl req.originalUrl = req.originalUrl || req.url Expand Down Expand Up @@ -260,11 +270,19 @@ Router.prototype.handle = function handle (req, res, callback) { const method = req.method const hasMethod = route._handlesMethod(method)
if (methodNotAllowed && hasMethod) { methodNotAllowed.methodMatched = true }
// build up automatic options response if (!hasMethod && method === 'OPTIONS' && methods) { methods.push.apply(methods, route._methods()) }
if (!hasMethod && methodNotAllowed && method !== 'OPTIONS') { methodNotAllowed.methods.push.apply(methodNotAllowed.methods, route._methods()) }
// don't even bother matching route if (!hasMethod && method !== 'HEAD') { match = false Expand Down Expand Up @@ -468,6 +486,25 @@ function generateOptionsResponder (res, methods) { } }
/** * Generate a callback that will make a 405 response. * * @param {IncomingMessage} req * @param {OutgoingMessage} res * @param {object} methodNotAllowed * @private */
function generateMethodNotAllowedResponder (req, res, methodNotAllowed) { return function onDone (fn, err) { if (err || methodNotAllowed.methodMatched || methodNotAllowed.methods.length === 0 || req.method === 'OPTIONS') { return fn(err) }
trySendMethodNotAllowedResponse(res, methodNotAllowed.methods, fn) } }
/** * Get pathname of request. * Expand Down Expand Up @@ -689,6 +726,17 @@ function restore (fn, obj) { } }
/** * Send a 405 response. * * @private */
function sendMethodNotAllowedResponse (res, methods) { res.statusCode = 405 sendOptionsResponse(res, methods) }
/** * Send an OPTIONS response. * Expand Down Expand Up @@ -728,6 +776,20 @@ function trySendOptionsResponse (res, methods, next) { } }
/** * Try to send a 405 response. * * @private */
function trySendMethodNotAllowedResponse (res, methods, next) { try { sendMethodNotAllowedResponse(res, methods) } catch (err) { next(err) } }
/** * Wrap a function * Expand Down
router.caseSensitive = opts.caseSensitive router.mergeParams = opts.mergeParams router.methodNotAllowed = opts.methodNotAllowed router.params = {} router.strict = opts.strict router.stack = [] Expand Down Expand Up @@ -155,6 +156,7 @@ Router.prototype.handle = function handle (req, res, callback) {
let idx = 0 let methods let methodNotAllowed const protohost = getProtohost(req.url) || '' let removed = '' const self = this Expand All @@ -179,6 +181,14 @@ Router.prototype.handle = function handle (req, res, callback) { done = wrap(done, generateOptionsResponder(res, methods)) }
if (self.methodNotAllowed) { methodNotAllowed = { methods: [], methodMatched: false } done = wrap(done, generateMethodNotAllowedResponder(req, res, methodNotAllowed)) }
// setup basic req values req.baseUrl = parentUrl req.originalUrl = req.originalUrl || req.url Expand Down Expand Up @@ -260,11 +270,19 @@ Router.prototype.handle = function handle (req, res, callback) { const method = req.method const hasMethod = route._handlesMethod(method)
if (methodNotAllowed && hasMethod) { methodNotAllowed.methodMatched = true }
// build up automatic options response if (!hasMethod && method === 'OPTIONS' && methods) { methods.push.apply(methods, route._methods()) }
if (!hasMethod && methodNotAllowed && method !== 'OPTIONS') { methodNotAllowed.methods.push.apply(methodNotAllowed.methods, route._methods()) }
// don't even bother matching route if (!hasMethod && method !== 'HEAD') { match = false Expand Down Expand Up @@ -468,6 +486,25 @@ function generateOptionsResponder (res, methods) { } }
/** * Generate a callback that will make a 405 response. * * @param {IncomingMessage} req * @param {OutgoingMessage} res * @param {object} methodNotAllowed * @private */
function generateMethodNotAllowedResponder (req, res, methodNotAllowed) { return function onDone (fn, err) { if (err || methodNotAllowed.methodMatched || methodNotAllowed.methods.length === 0 || req.method === 'OPTIONS') { return fn(err) }
trySendMethodNotAllowedResponse(res, methodNotAllowed.methods, fn) } }
/** * Get pathname of request. * Expand Down Expand Up @@ -689,6 +726,17 @@ function restore (fn, obj) { } }
/** * Send a 405 response. * * @private */
function sendMethodNotAllowedResponse (res, methods) { res.statusCode = 405 sendOptionsResponse(res, methods) }
/** * Send an OPTIONS response. * Expand Down Expand Up @@ -728,6 +776,20 @@ function trySendOptionsResponse (res, methods, next) { } }
/** * Try to send a 405 response. * * @private */
function trySendMethodNotAllowedResponse (res, methods, next) { try { sendMethodNotAllowedResponse(res, methods) } catch (err) { next(err) } }
/** * Wrap a function * Expand Down