router
Advanced tools
Comparing version 0.5.19 to 0.6.0
304
index.js
@@ -1,266 +0,92 @@ | ||
var http = require('http'); | ||
var https = require('https'); | ||
var common = require('common'); | ||
var compile = require('./matcher'); | ||
var matcher = require('./matcher'); | ||
var formatter = require('./formatter'); | ||
var METHODS = ['get', 'post', 'put', 'del', 'head', 'options']; | ||
var HTTP_METHODS = ['GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'OPTIONS']; | ||
var METHODS = ['get', 'post', 'put', 'del' , 'delete', 'head', 'options']; | ||
var HTTP_METHODS = ['GET', 'POST', 'PUT', 'DELETE', 'DELETE', 'HEAD', 'OPTIONS']; | ||
var NOT_FOUND = function(request, response) { | ||
response.writeHead(404); | ||
response.end(); | ||
}; | ||
var noop = function() {}; | ||
var toBuffer = function(param) { | ||
if (param.cert && param.key) { | ||
param.cert = toBuffer(param.cert); | ||
param.key = toBuffer(param.key); | ||
return param; | ||
} | ||
if (Buffer.isBuffer(param)) { | ||
return param; | ||
} | ||
if (param.indexOf('\n') > -1) { | ||
return new Buffer(param); | ||
} | ||
return require('fs').readFileSync(param); | ||
var error = function(res) { | ||
return function() { | ||
res.statusCode = 404; | ||
res.end(); | ||
}; | ||
}; | ||
var router = function() { | ||
var methods = {}; | ||
var traps = {}; | ||
var Router = common.emitter(function(server, options) { | ||
var self = this; | ||
this.route = this.route.bind(this); | ||
this.router = this; | ||
this.server = server; | ||
if (server) { | ||
server.router = this; | ||
} | ||
this._methods = {}; | ||
this._servers = []; | ||
this._end = {}; | ||
this._listening = false; | ||
this.on('request', this.route); | ||
if (options && options.hang) { | ||
return; | ||
} | ||
HTTP_METHODS.forEach(function(method) { | ||
self._methods[method] = []; | ||
self._end[method] = NOT_FOUND; | ||
methods[method] = []; | ||
}); | ||
}); | ||
METHODS.concat('delete').forEach(function(method) { | ||
var httpMethod = method.replace('del', 'delete').toUpperCase(); | ||
var route = function(req, res, next) { | ||
var method = methods[req.method]; | ||
var trap = traps[req.method]; | ||
var index = req.url.indexOf('?'); | ||
var url = index === -1 ? req.url : req.url.substr(0, index); | ||
var i = 0; | ||
Router.prototype[method] = function(pattern, rewrite, fn) { | ||
var self = this; | ||
next = next || error(res); | ||
if (!method) return next(); | ||
if (Array.isArray(pattern)) { | ||
pattern.forEach(function(item) { | ||
self[method](item, rewrite, fn); | ||
}); | ||
var loop = function(err) { | ||
if (err) return next(err); | ||
while (i < method.length) { | ||
var route = method[i]; | ||
return this; | ||
} | ||
this.emit('mount', method, pattern, rewrite, fn); | ||
if (typeof pattern === 'function') { | ||
this._end[httpMethod] = pattern; | ||
return; | ||
} | ||
if (!fn && typeof rewrite === 'string') { | ||
fn = this.route; | ||
} | ||
if (!fn) { | ||
fn = rewrite; | ||
rewrite = null; | ||
} | ||
if (rewrite) { | ||
rewrite = rewrite.replace(/:(\w+)/g, '{$1}'); // normalize | ||
} | ||
pattern = compile(pattern); | ||
this._methods[httpMethod].push(function(request, a, b, c) { | ||
var next = c || b; | ||
var index = request.url.indexOf('?'); | ||
var params = request.params = pattern(index === -1 ? request.url : request.url.substring(0, index)); | ||
if (!params) { | ||
next(); | ||
i++; | ||
req.params = route.pattern(url); | ||
if (!req.params) continue; | ||
if (route.rewrite) { | ||
req.url = url = route.rewrite(req.params); | ||
} | ||
route.fn(req, res, loop); | ||
return; | ||
} | ||
if (rewrite) { | ||
request.url = common.format(rewrite, request.params) + (index === -1 ? '' : request.url.substring(index)); | ||
} | ||
if (!trap) return next(); | ||
trap(req, res, next); | ||
}; | ||
fn(request, a, b, c); | ||
}); | ||
return this; | ||
loop(); | ||
}; | ||
}); | ||
Router.prototype.detach = function() { | ||
this.removeListener('request', this.route); | ||
return this.route; | ||
}; | ||
Router.prototype.upgrade = function(fn) { | ||
this.on('upgrade', fn); | ||
return this; | ||
}; | ||
Router.prototype.all = function() { | ||
var self = this; | ||
var args = arguments; | ||
METHODS.forEach(function(method) { | ||
self[method].apply(self, args); | ||
}); | ||
return this; | ||
}; | ||
Router.prototype.route = function(request, response, next) { | ||
this._find(request, response, next); | ||
}; | ||
Router.prototype.address = function() { | ||
return this.server ? this.server.address() : {}; | ||
}; | ||
Router.prototype.listen = function(port, callback) { | ||
var server = this.server = this.server || http.createServer(); | ||
var self = this; | ||
if (this._listening) { | ||
server.listen(port); | ||
return this; | ||
} | ||
this.bind(server); | ||
this._listening = true; | ||
this.once('listening', callback || noop); | ||
server.on('error', function(err) { | ||
self.emit('error', err); | ||
}); | ||
server.on('listening', function() { | ||
self.emit('listening'); | ||
}); | ||
server.listen(port); | ||
return this; | ||
}; | ||
Router.prototype.bind = function(server, ssl) { | ||
var self = this; | ||
var notServer = typeof server === 'number' || typeof server === 'string'; | ||
if (notServer && ssl && typeof ssl === 'object') { | ||
return this.bind(https.createServer(toBuffer(ssl)).listen(server)); | ||
} | ||
if (notServer) { | ||
return this.bind(http.createServer().listen(server)); | ||
} | ||
if (this._servers.indexOf(server) > -1) { | ||
return this; | ||
} | ||
server.router = this; | ||
server.on('request', function(request, response) { | ||
self.emit('request', request, response); | ||
}); | ||
server.on('upgrade', function(request, connection, head) { | ||
if (!self.listeners('upgrade').length) { | ||
connection.destroy(); | ||
return; | ||
} | ||
self.emit('upgrade', request, connection, head); | ||
}); | ||
this.emit('bind', server); | ||
this._servers.push(server); | ||
return this; | ||
}; | ||
Router.prototype.close = function(callback) { | ||
var self = this; | ||
this.once('close', callback || noop); | ||
common.step([ | ||
function(next) { | ||
if (!self._servers.length) { | ||
next(); | ||
METHODS.forEach(function(method, i) { | ||
route[method] = function(pattern, rewrite, fn) { | ||
if (Array.isArray(pattern)) { | ||
pattern.forEach(function(item) { | ||
route[method](item, rewrite, fn); | ||
}); | ||
return; | ||
} | ||
self._servers.forEach(function(server) { | ||
var callback = common.once(next.parallel().bind(null, null)); | ||
if (!fn && !rewrite) return route[method](null, null, pattern); | ||
if (!fn && typeof rewrite === 'string') return route[method](pattern, rewrite, route); | ||
if (!fn && typeof rewrite === 'function') return route[method](pattern, null, rewrite); | ||
if (!fn) return route; | ||
server.once('close', callback); | ||
server.close(callback); | ||
}); | ||
}, | ||
function() { | ||
self.emit('close'); | ||
} | ||
]); | ||
}; | ||
(route.onmount || noop)(pattern, rewrite, fn); | ||
Router.prototype._find = function(request, response, next) { | ||
var method = request.method; | ||
var routes = this._methods[method]; | ||
var end = this._end[method]; | ||
var index = 0; | ||
if (!routes) { | ||
request.destroy(); | ||
return; | ||
} | ||
var loop = function(err) { | ||
if (err && next) { | ||
next(err); | ||
return; | ||
} | ||
if (index >= routes.length) { | ||
if (next && (!end || end === NOT_FOUND)) { | ||
next(); | ||
return; | ||
if (!pattern) { | ||
traps[HTTP_METHODS[i]] = fn; | ||
return route; | ||
} | ||
end(request, response, noop); | ||
return; | ||
} | ||
routes[index++](request, response, loop); | ||
methods[HTTP_METHODS[i]].push({ | ||
pattern:matcher(pattern), | ||
rewrite:formatter(rewrite), | ||
fn:fn | ||
}); | ||
return route; | ||
}; | ||
}); | ||
route.all = function(pattern, rewrite, fn) { | ||
METHODS.forEach(function(method) { | ||
route[method](pattern, rewrite, fn); | ||
}); | ||
return route; | ||
}; | ||
loop(); | ||
return route; | ||
}; | ||
module.exports = function(options) { | ||
if (!options) { | ||
return new Router(); | ||
} | ||
if (options.router) { | ||
return options.router; | ||
} | ||
if (typeof options.listen === 'function') { | ||
return new Router(options, {hang:true}); | ||
} | ||
if (options.cert) { | ||
return new Router(https.createServer(toBuffer(options.cert))); | ||
} | ||
return new Router(); | ||
}; | ||
module.exports.create = module.exports; | ||
module.exports = router; |
{ | ||
"name":"router", | ||
"version":"0.5.19", | ||
"description":"A lean and mean web router", | ||
"version":"0.6.0", | ||
"description":"A lean and mean http router", | ||
"keywords":["connect","middleware","router","route","http"], | ||
"repository": {"type": "git", "url": "git://github.com/gett/router.git"}, | ||
"contributors": [ | ||
@@ -9,4 +11,3 @@ "Mathias Buus Madsen <m@ge.tt>", | ||
], | ||
"main":"./index.js", | ||
"dependencies": {"common":">=0.1.0"} | ||
"dependencies": {} | ||
} |
# Router | ||
A lean and mean web router for [node.js](http://nodejs.org). | ||
A lean and mean http router for [node.js](http://nodejs.org). | ||
It is available through npm: | ||
@@ -7,14 +8,17 @@ | ||
The router routes using the method and a [.net](http://msdn.microsoft.com/en-us/library/cc668201.aspx) inspired pattern | ||
## Usage | ||
Router does one thing and one thing only - route http requests. | ||
``` js | ||
var http = require('http'); | ||
var router = require('router'); | ||
var server = router(); | ||
var route = router(); | ||
server.get('/', function(request, response) { | ||
response.writeHead(200); | ||
response.end('hello index page'); | ||
route.get('/', function(req, res) { | ||
res.writeHead(200); | ||
res.end('hello index page'); | ||
}); | ||
server.listen(8080); // start the server on port 8080 | ||
http.createServer(route).listen(8080); // start the server on port 8080 | ||
``` | ||
@@ -25,4 +29,4 @@ | ||
``` js | ||
server.get('/{base}', function(request, response) { | ||
var base = request.params.base; // ex: if the path is /foo/bar, then base = foo | ||
route.get('/{base}', function(req, res) { | ||
var base = req.params.base; // ex: if the path is /foo/bar, then base = foo | ||
}); | ||
@@ -34,4 +38,4 @@ ``` | ||
``` js | ||
server.get('/{x}x{y}', function(request, response) { | ||
// if the path was /200x200, then request.params = {x:'200', y:'200'} | ||
route.get('/{x}x{y}', function(req, res) { | ||
// if the path was /200x200, then req.params = {x:'200', y:'200'} | ||
}); | ||
@@ -43,3 +47,3 @@ ``` | ||
``` js | ||
server.get('/{prefix}?/{top}', function(request, response) { | ||
route.get('/{prefix}?/{top}', function(req, res) { | ||
// matches both '/a/b' and '/b' | ||
@@ -52,5 +56,5 @@ }); | ||
``` js | ||
server.get('/{prefix}/*', function(request, response) { | ||
route.get('/{prefix}/*', function(req, res) { | ||
// matches both '/a/', '/a/b', 'a/b/c' and so on. | ||
// the value of the wildcard is available through request.params.wildcard | ||
// the value of the wildcard is available through req.params.wildcard | ||
}); | ||
@@ -62,3 +66,3 @@ ``` | ||
``` js | ||
server.get('/{digits}([0-9]+)', function(request, response) { | ||
route.get('/{digits}([0-9]+)', function(req, res) { | ||
// matches both '/24' and '/424' but not '/abefest' and so on. | ||
@@ -71,8 +75,37 @@ }); | ||
``` js | ||
server.get(/^\/foo\/(\w+)/, function(request, response) { | ||
var group = request.params[1]; // if path is /foo/bar, then group is bar | ||
route.get(/^\/foo\/(\w+)/, function(req, res) { | ||
var group = req.params[1]; // if path is /foo/bar, then group is bar | ||
}); | ||
``` | ||
Besides `get` the avaiable methods are `options`, `post`, `put`, `head`, `del`, `all` and `upgrade`. | ||
`all` matches all the standard http methods and `upgrade` is usually used for websockets. | ||
## Methods | ||
* `route.get`: Match `GET` requests | ||
* `route.post`: Match `POST` requests | ||
* `route.put`: Match `PUT` requests | ||
* `route.head`: Match `HEAD` requests | ||
* `route.del`: Match `DELETE` requests | ||
* `route.options`: Match `OPTIONS` requests | ||
* `route.all`: Match all above request methods. | ||
## Error handling | ||
By default Router will return 404 if you no route matched. If you want to do your own thing you can give it a callback: | ||
``` js | ||
route(req, res, function() { | ||
// no route was matched | ||
res.writeHead(404); | ||
res.end(); | ||
}); | ||
``` | ||
You can also provide a catch-all to a given route that is called if no route was matched: | ||
``` js | ||
route.get(function(req, res) { | ||
// called if no other get route matched | ||
res.writeHead(404); | ||
res.end('no GET handler found'); | ||
}); | ||
``` |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 2 instances in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
13917
0
16
377
104
1
- Removedcommon@>=0.1.0
- Removedcommon@0.2.5(transitive)