mirror of
https://github.com/expressjs/express.git
synced 2026-02-26 18:57:43 +00:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8afb905a43 | ||
|
|
53667728a8 | ||
|
|
5f0a854e29 | ||
|
|
e9ef3dd9cd | ||
|
|
f702884704 | ||
|
|
0cb866845d | ||
|
|
26483029db | ||
|
|
d2adcbdf67 | ||
|
|
d2f963db2a | ||
|
|
fc2bc1362f | ||
|
|
6ae45d0fd3 |
@@ -1,4 +1,11 @@
|
||||
|
||||
2.3.3 / 2011-05-03
|
||||
==================
|
||||
|
||||
* Added "case sensitive routes" option.
|
||||
* Changed; split methods supported per rfc [slaskis]
|
||||
* Fixed route-specific middleware when using the same callback function several times
|
||||
|
||||
2.3.2 / 2011-04-27
|
||||
==================
|
||||
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
|
||||
$ npm install express
|
||||
|
||||
or to access the `express(1)` executable install globally:
|
||||
|
||||
$ npm install -g express
|
||||
|
||||
## Features
|
||||
|
||||
* Robust routing
|
||||
|
||||
@@ -11,7 +11,7 @@ var fs = require('fs')
|
||||
* Framework version.
|
||||
*/
|
||||
|
||||
var version = '2.3.2';
|
||||
var version = '2.3.3';
|
||||
|
||||
/**
|
||||
* Add session support.
|
||||
|
||||
@@ -83,6 +83,7 @@ Express supports the following settings out of the box:
|
||||
* _view engine_ Default view engine name for views rendered without extensions
|
||||
* _view options_ An object specifying global view options
|
||||
* _view cache_ Enable view caching (enabled in production)
|
||||
* _case sensitive routes_ Enable case-sensitive routing
|
||||
|
||||
### Routing
|
||||
|
||||
@@ -319,6 +320,8 @@ Commonly used "stacks" of middleware can be passed as an array (_applied recursi
|
||||
|
||||
For this example in full, view the [route middleware example](http://github.com/visionmedia/express/blob/master/examples/route-middleware/app.js) in the repository.
|
||||
|
||||
There are times when we may want to "skip" passed remaining route middleware, but continue matching subsequent routes. To do this we invoke `next()` with the string "route" `next('route')`. If no remaining routes match the request url then Express will respond with 404 Not Found.
|
||||
|
||||
### HTTP Methods
|
||||
|
||||
We have seen _app.get()_ a few times, however Express also exposes other familiar HTTP verbs in the same manor, such as _app.post()_, _app.del()_, etc.
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
@@ -15,7 +14,7 @@ app.set('views', __dirname + '/views');
|
||||
// set default layout, usually "layout"
|
||||
app.set('view options', { layout: 'layouts/default' });
|
||||
|
||||
// Set our default template engine to "jade"
|
||||
// Set our default template engine to "ejs"
|
||||
// which prevents the need for extensions
|
||||
// (although you can still mix and match)
|
||||
app.set('view engine', 'ejs');
|
||||
|
||||
@@ -28,7 +28,7 @@ var exports = module.exports = connect.middleware;
|
||||
* Framework version.
|
||||
*/
|
||||
|
||||
exports.version = '2.3.2';
|
||||
exports.version = '2.3.3';
|
||||
|
||||
/**
|
||||
* Shortcut for `new Server(...)`.
|
||||
|
||||
@@ -87,7 +87,7 @@ app.init = function(middleware){
|
||||
if (middleware) middleware.forEach(self.use.bind(self));
|
||||
|
||||
// use router, expose as app.get(), etc
|
||||
var fn = router(function(app){ self.routes = app; });
|
||||
var fn = router(function(app){ self.routes = app; }, this);
|
||||
this.__defineGetter__('router', function(){
|
||||
this.__usedRouter = true;
|
||||
return fn;
|
||||
|
||||
@@ -34,7 +34,7 @@ exports.methods = _methods;
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function router(fn){
|
||||
function router(fn, app){
|
||||
var self = this
|
||||
, methods = {}
|
||||
, routes = {}
|
||||
@@ -79,12 +79,12 @@ function router(fn){
|
||||
middleware = utils.flatten(middleware);
|
||||
}
|
||||
|
||||
fn.middleware = middleware;
|
||||
|
||||
if (!path) throw new Error(name + ' route requires a path');
|
||||
if (!fn) throw new Error(name + ' route ' + path + ' requires a callback');
|
||||
|
||||
var route = new Route(name, path, fn);
|
||||
var options = { sensitive: app.enabled('case sensitive routes') };
|
||||
var route = new Route(name, path, fn, options);
|
||||
route.middleware = middleware;
|
||||
localRoutes.push(route);
|
||||
return self;
|
||||
};
|
||||
@@ -128,7 +128,7 @@ function router(fn){
|
||||
// route middleware
|
||||
i = 0;
|
||||
(function nextMiddleware(err){
|
||||
var fn = route.callback.middleware[i++];
|
||||
var fn = route.middleware[i++];
|
||||
if ('route' == err) {
|
||||
pass(req._route_index + 1);
|
||||
} else if (err) {
|
||||
|
||||
@@ -6,26 +6,65 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Supported HTTP / WebDAV methods.
|
||||
* Hypertext Transfer Protocol -- HTTP/1.1
|
||||
* http://www.ietf.org/rfc/rfc2616.txt
|
||||
*/
|
||||
|
||||
module.exports = [
|
||||
'get'
|
||||
, 'post'
|
||||
, 'put'
|
||||
, 'delete'
|
||||
, 'connect'
|
||||
, 'options'
|
||||
, 'trace'
|
||||
, 'copy'
|
||||
, 'lock'
|
||||
, 'mkcol'
|
||||
, 'move'
|
||||
, 'propfind'
|
||||
, 'proppatch'
|
||||
, 'unlock'
|
||||
, 'report'
|
||||
, 'mkactivity'
|
||||
, 'checkout'
|
||||
, 'merge'
|
||||
];
|
||||
var RFC2616 = ['OPTIONS', 'GET', 'POST', 'PUT', 'DELETE', 'TRACE', 'CONNECT'];
|
||||
|
||||
/**
|
||||
* HTTP Extensions for Distributed Authoring -- WEBDAV
|
||||
* http://www.ietf.org/rfc/rfc2518.txt
|
||||
*/
|
||||
|
||||
var RFC2518 = ['PROPFIND', 'PROPPATCH', 'MKCOL', 'COPY', 'MOVE', 'LOCK', 'UNLOCK'];
|
||||
|
||||
/**
|
||||
* Versioning Extensions to WebDAV
|
||||
* http://www.ietf.org/rfc/rfc3253.txt
|
||||
*/
|
||||
|
||||
var RFC3253 = ['VERSION-CONTROL', 'REPORT', 'CHECKOUT', 'CHECKIN', 'UNCHECKOUT', 'MKWORKSPACE', 'UPDATE', 'LABEL', 'MERGE', 'BASELINE-CONTROL', 'MKACTIVITY'];
|
||||
|
||||
/**
|
||||
* Ordered Collections Protocol (WebDAV)
|
||||
* http://www.ietf.org/rfc/rfc3648.txt
|
||||
*/
|
||||
|
||||
var RFC3648 = ['ORDERPATCH'];
|
||||
|
||||
/**
|
||||
* Web Distributed Authoring and Versioning (WebDAV) Access Control Protocol
|
||||
* http://www.ietf.org/rfc/rfc3744.txt
|
||||
*/
|
||||
|
||||
var RFC3744 = ['ACL'];
|
||||
|
||||
/**
|
||||
* Web Distributed Authoring and Versioning (WebDAV) SEARCH
|
||||
* http://www.ietf.org/rfc/rfc5323.txt
|
||||
*/
|
||||
|
||||
var RFC5323 = ['SEARCH'];
|
||||
|
||||
/**
|
||||
* PATCH Method for HTTP
|
||||
* http://www.ietf.org/rfc/rfc5789.txt
|
||||
*/
|
||||
|
||||
var RFC5789 = ['PATCH'];
|
||||
|
||||
/**
|
||||
* Expose the methods.
|
||||
*/
|
||||
|
||||
module.exports = [].concat(
|
||||
RFC2616
|
||||
, RFC2518
|
||||
, RFC3253
|
||||
, RFC3648
|
||||
, RFC3744
|
||||
, RFC5323
|
||||
, RFC5789).map(function(method){
|
||||
return method.toLowerCase();
|
||||
});
|
||||
|
||||
@@ -13,18 +13,24 @@ module.exports = Route;
|
||||
|
||||
/**
|
||||
* Initialize `Route` with the given HTTP `method`, `path`,
|
||||
* and callback `fn`.
|
||||
* and callback `fn` and `options`.
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - `sensitive` enable case-sensitive routes
|
||||
*
|
||||
* @param {String} method
|
||||
* @param {String} path
|
||||
* @param {Function} fn
|
||||
* @param {Object} options.
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function Route(method, path, fn) {
|
||||
function Route(method, path, fn, options) {
|
||||
options = options || {};
|
||||
this.callback = fn;
|
||||
this.path = path;
|
||||
this.regexp = normalize(path, this.keys = []);
|
||||
this.regexp = normalize(path, this.keys = [], options.sensitive);
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
@@ -39,11 +45,12 @@ function Route(method, path, fn) {
|
||||
*
|
||||
* @param {String|RegExp} path
|
||||
* @param {Array} keys
|
||||
* @param {Boolean} sensitive
|
||||
* @return {RegExp}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function normalize(path, keys) {
|
||||
function normalize(path, keys, sensitive) {
|
||||
if (path instanceof RegExp) return path;
|
||||
path = path
|
||||
.concat('/?')
|
||||
@@ -60,5 +67,5 @@ function normalize(path, keys) {
|
||||
})
|
||||
.replace(/([\/.])/g, '\\$1')
|
||||
.replace(/\*/g, '(.+)');
|
||||
return new RegExp('^' + path + '$', 'i');
|
||||
return new RegExp('^' + path + '$', sensitive ? '' : 'i');
|
||||
}
|
||||
@@ -49,7 +49,7 @@ function View(view, options) {
|
||||
this.name = this.basename.replace(this.extension, '');
|
||||
this.path = this.resolvePath();
|
||||
this.dirname = dirname(this.path);
|
||||
options.attempts.push(this.path);
|
||||
if (options.attempts) options.attempts.push(this.path);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "express",
|
||||
"description": "Sinatra inspired web development framework",
|
||||
"version": "2.3.2",
|
||||
"version": "2.3.3",
|
||||
"author": "TJ Holowaychuk <tj@vision-media.ca>",
|
||||
"contributors": [
|
||||
{ "name": "TJ Holowaychuk", "email": "tj@vision-media.ca" },
|
||||
|
||||
@@ -435,5 +435,31 @@ module.exports = {
|
||||
{ url: '/' },
|
||||
{ body: 'restored' }
|
||||
);
|
||||
},
|
||||
|
||||
'test routes with same callback': function(){
|
||||
function handle(req, res) {
|
||||
res.send('got ' + req.string);
|
||||
}
|
||||
|
||||
var app = express.createServer();
|
||||
|
||||
app.get('/', function(req, res, next){
|
||||
req.string = '/';
|
||||
next();
|
||||
}, handle);
|
||||
|
||||
app.get('/another', function(req, res, next){
|
||||
req.string = '/another';
|
||||
next();
|
||||
}, handle);
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/' },
|
||||
{ body: 'got /' });
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/another' },
|
||||
{ body: 'got /another' });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -241,5 +241,27 @@ module.exports = {
|
||||
app.match.get('/').should.have.be.empty;
|
||||
app.match.all('/user/123').should.have.length(3);
|
||||
app.match('/user/123').should.have.length(3);
|
||||
},
|
||||
|
||||
'test "case sensitive routes" setting': function(){
|
||||
var app = express.createServer();
|
||||
|
||||
app.enable('case sensitive routes');
|
||||
|
||||
app.get('/account', function(req, res){
|
||||
res.send('account');
|
||||
});
|
||||
|
||||
app.get('/Account', function(req, res){
|
||||
res.send('Account');
|
||||
});
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/account' },
|
||||
{ body: 'account' });
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/Account' },
|
||||
{ body: 'Account' });
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user