koa2-router
Advanced tools
Comparing version 1.0.8 to 1.0.9
174
lib/index.js
@@ -25,2 +25,3 @@ /*! | ||
var delegates = require('delegates') | ||
var HttpError = require('http-errors') | ||
@@ -66,7 +67,11 @@ /** | ||
get: function() { return this.req.baseUrl }, | ||
set: function(baseUrl) { this.req.baseUrl = baseUrl } | ||
set: function(baseUrl) { return this.req.baseUrl = baseUrl } | ||
}, | ||
params: { | ||
get: function() { return this.req.params }, | ||
set: function(params) { this.req.params = params } | ||
set: function(params) { return this.req.params = params } | ||
}, | ||
matched: { | ||
get: function() { return this.req.matched }, | ||
set: function(matched) { return this.req.matched = matched } | ||
} | ||
@@ -77,2 +82,3 @@ }) | ||
.access('params') | ||
.access('matched') | ||
} | ||
@@ -104,2 +110,4 @@ } | ||
req.params = req.params || {} | ||
req.matched = req.matched || [] | ||
return router.handle(ctx, next) | ||
@@ -115,6 +123,24 @@ } | ||
router.mergeParams = opts.mergeParams | ||
router.strict = opts.strict | ||
router.methods = opts.methods || [ | ||
'HEAD', | ||
'OPTIONS', | ||
'GET', | ||
'PUT', | ||
'PATCH', | ||
'POST', | ||
'DELETE' | ||
] | ||
router.params = {} | ||
router.strict = opts.strict | ||
router.stack = [] | ||
if (!Array.isArray(router.methods)) { | ||
throw new TypeError('invalid options.methods, got type ' + gettype(opts.methods)) | ||
} | ||
// we should never return 501 for GET/HEAD method | ||
// so we need to ensure router.methods contains at least GET and HEAD | ||
if (!~router.methods.indexOf('GET')) router.methods.push('GET') | ||
if (!~router.methods.indexOf('HEAD')) router.methods.push('HEAD') | ||
return router | ||
@@ -201,3 +227,3 @@ } | ||
// only used if OPTIONS request | ||
var methods = [] | ||
var matched = [] | ||
@@ -207,30 +233,25 @@ // save point 1 | ||
// detect router match | ||
var notMatched = false | ||
try { | ||
// dispatch into the current router | ||
await this.dispatch(ctx, methods) | ||
} catch(e) { | ||
if (e === 'router') { | ||
// if just want to jump the current router | ||
// save point 2 | ||
var restore2 = restore(ctx, 'baseUrl', 'params', 'url') | ||
try { | ||
// restore point 1 | ||
restore1() | ||
// go upstream | ||
await upstream() | ||
} finally { | ||
// restore point 2 | ||
restore2() | ||
} | ||
} else { | ||
// any other errors just throw it out | ||
throw e | ||
} | ||
await this.dispatch(ctx, matched, function() { | ||
notMatched = true | ||
}) | ||
} finally { | ||
// restore point 1 | ||
restore1() | ||
} | ||
// for options requests, respond with a default if nothing else responds | ||
if (ctx.status === 404 && methods.length && ctx.method === 'OPTIONS') { | ||
sendOptionsResponse(ctx, methods) | ||
if (notMatched) { | ||
if (matched.length) ctx.matched = matched | ||
// save point 2 | ||
var restore2 = restore(ctx, 'baseUrl', 'params', 'url') | ||
try { | ||
// go upstream | ||
await upstream() | ||
} finally { | ||
// restore point 2 | ||
restore2() | ||
} | ||
@@ -241,8 +262,65 @@ } | ||
/** | ||
* use allowMethods to generate a middleware for | ||
* | ||
* | ||
* @public | ||
*/ | ||
Router.prototype.allowMethods = function allowMethods(options) { | ||
options = options || {} | ||
var implemented = this.methods | ||
return async function(ctx, next) { | ||
await next() | ||
if (!isResponded(ctx)) { | ||
const method = ctx.method | ||
const allowedArr = ctx.matched | ||
if (!~implemented.indexOf(method)) { | ||
// not implemented | ||
if (options.throw) { | ||
var notImplementedThrowable | ||
if (typeof options.notImplemented === 'function') { | ||
notImplementedThrowable = options.notImplemented(ctx) | ||
} else { | ||
notImplementedThrowable = new HttpError.NotImplemented() | ||
} | ||
throw notImplementedThrowable | ||
} else { | ||
ctx.status = 501 | ||
sendOptionsResponse(ctx, allowedArr) | ||
} | ||
} else if (allowedArr.length) { | ||
// matched route in this router | ||
// but method not allowed | ||
if (method === 'OPTIONS') { | ||
ctx.status = 200 | ||
sendOptionsResponse(ctx, allowedArr) | ||
} else if (!~allowedArr.indexOf(method)) { | ||
// method not allowed | ||
if (options.throw) { | ||
var notAllowedThrowable; | ||
if (typeof options.methodNotAllowed === 'function') { | ||
notAllowedThrowable = options.methodNotAllowed(ctx, allowedArr) | ||
} else { | ||
notAllowedThrowable = new HttpError.MethodNotAllowed() | ||
} | ||
throw notAllowedThrowable | ||
} else { | ||
ctx.status = 405 | ||
sendOptionsResponse(ctx, allowedArr) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
/** | ||
* dispatch koa context into this router | ||
* @param methods collection for methods it has | ||
* @param matched collection for methods it has | ||
* @private | ||
*/ | ||
Router.prototype.dispatch = function dispatch(ctx, methods) { | ||
Router.prototype.dispatch = function dispatch(ctx, matched, done) { | ||
var self = this | ||
@@ -283,3 +361,3 @@ | ||
if (idx >= stack.length) { | ||
throw 'router' | ||
return done() | ||
} | ||
@@ -291,5 +369,4 @@ | ||
if (path == null) { | ||
// layer error for this router | ||
console.error('null pathname in ctx') | ||
throw 'router' | ||
// FIXME layer error for this router | ||
return next() | ||
} | ||
@@ -320,4 +397,4 @@ | ||
// build up automatic options response | ||
if (!has_method && method === 'OPTIONS') { | ||
methods.push.apply(methods, route._methods()) | ||
if (!has_method) { | ||
matched.push.apply(matched, route._methods()) | ||
} | ||
@@ -334,3 +411,3 @@ | ||
if (match !== true) { | ||
throw 'router' | ||
return done() | ||
} | ||
@@ -355,2 +432,7 @@ | ||
return trim_prefix(layer, layerPath, path, next) | ||
}).catch(function(e) { | ||
if (e === 'router') { | ||
return done() | ||
} | ||
throw e | ||
}) | ||
@@ -463,3 +545,6 @@ } | ||
if (typeof fn !== 'function') return param() | ||
if (typeof fn !== 'function') { | ||
await param() | ||
return | ||
} | ||
@@ -678,2 +763,10 @@ try { | ||
function isResponded(ctx) { | ||
return ctx.respond === false | ||
|| ctx.headerSent | ||
|| !ctx.writable | ||
|| ctx.response._explicitStatus | ||
|| ctx.status !== 404 | ||
} | ||
/** | ||
@@ -685,3 +778,3 @@ * Send an OPTIONS response. | ||
function sendOptionsResponse(ctx, methods) { | ||
function sendOptionsResponse(ctx, matched) { | ||
if (ctx.respond !== false) { | ||
@@ -691,4 +784,4 @@ var options = Object.create(null) | ||
// build unique method map | ||
for (var i = 0; i < methods.length; i++) { | ||
options[methods[i]] = true | ||
for (var i = 0; i < matched.length; i++) { | ||
options[matched[i]] = true | ||
} | ||
@@ -699,6 +792,5 @@ | ||
ctx.set('Allow', body) | ||
if (body) ctx.set('Allow', body) | ||
ctx.set('X-Content-Type-Options', 'nosniff') | ||
ctx.body = body | ||
} | ||
} |
@@ -63,4 +63,3 @@ /*! | ||
var fn = this.handler | ||
var owner = this.owner | ||
await fn.call(owner, ctx, next) | ||
await fn(ctx, next) | ||
} | ||
@@ -67,0 +66,0 @@ |
@@ -97,2 +97,24 @@ /*! | ||
/** | ||
* handle route middleware | ||
* @private | ||
*/ | ||
Route.prototype.handle = async function handle(ctx, upstream) { | ||
if (typeof upstream !== 'function') { | ||
throw new TypeError('argument next(upstream) is required') | ||
} | ||
// detect route match | ||
var notMatched = false | ||
await this.dispatch(ctx, function() { | ||
notMatched = true | ||
}) | ||
if (notMatched) { | ||
await upstream() | ||
} | ||
} | ||
/** | ||
* dispatch koa context into this route | ||
@@ -102,3 +124,3 @@ * @private | ||
Route.prototype.dispatch = function dispatch(ctx) { | ||
Route.prototype.dispatch = function dispatch(ctx, done) { | ||
var idx = 0 | ||
@@ -108,3 +130,3 @@ var stack = this.stack | ||
if (stack.length === 0) { | ||
throw 'route' | ||
return done() | ||
} | ||
@@ -133,27 +155,11 @@ | ||
if (match !== true) { | ||
throw 'route' | ||
return done() | ||
} | ||
return layer.handle(ctx, next) | ||
} | ||
} | ||
/** | ||
* handle route middleware | ||
* @private | ||
*/ | ||
Route.prototype.handle = async function handle(ctx, upstream) { | ||
if (typeof upstream !== 'function') { | ||
throw new TypeError('argument next(upstream) is required') | ||
} | ||
try { | ||
await this.dispatch(ctx) | ||
} catch(e) { | ||
if (e === 'route') { | ||
await upstream() | ||
} else { | ||
return layer.handle(ctx, next).catch(function(e) { | ||
if (e === 'route') { | ||
return done() | ||
} | ||
throw e | ||
} | ||
}) | ||
} | ||
@@ -160,0 +166,0 @@ } |
{ | ||
"name": "koa2-router", | ||
"version": "1.0.8", | ||
"version": "1.0.9", | ||
"description": "A express-liked router component for koa2", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
30205
963
1