Comparar commits
64 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| f8b954bcd9 | |||
| caa25b506d | |||
| 6911815171 | |||
| 0719e5f402 | |||
| 07b731add0 | |||
| d42d8f5b07 | |||
| 143e72dd85 | |||
| 6835289564 | |||
| 1396e0855d | |||
| 6a7363e4ae | |||
| 9bc63d92a0 | |||
| 6b05f60bad | |||
| 25e6629bcc | |||
| 0796c1d2d2 | |||
| aac1d52c4f | |||
| f41d09a3cf | |||
| 4bf9cfd477 | |||
| 08cbc442f5 | |||
| a02dd201e6 | |||
| a5f7dcee04 | |||
| 0ddd761904 | |||
| 991c2a9d05 | |||
| 4983c38298 | |||
| 337ab24899 | |||
| 63c6a9c5ad | |||
| 718e68ffae | |||
| f56a5f01c4 | |||
| b77ffe0228 | |||
| fd6439bb36 | |||
| 121f8d02f3 | |||
| 5ddbb6965f | |||
| a3b5f6d07f | |||
| ac2cbef8be | |||
| dff22e9d09 | |||
| 7282b50ad0 | |||
| 8c059469fd | |||
| 8c3f153dd4 | |||
| 185b526e60 | |||
| 38996b30b1 | |||
| 827dfed7c2 | |||
| 28af21baeb | |||
| 951c70496b | |||
| a36eeb96f3 | |||
| 7018d3d0e6 | |||
| 3f14b4de1f | |||
| 26c0be4c4e | |||
| cec0c06a70 | |||
| 476f8deb07 | |||
| dc5932d177 | |||
| cfd93b7529 | |||
| 8b2208f394 | |||
| 00a3b01f39 | |||
| 3baca251f0 | |||
| 72daae1d92 | |||
| fcbe53ddb5 | |||
| e9851672eb | |||
| 9a45f7bd3d | |||
| 85834fd146 | |||
| a0c1ac7b45 | |||
| 7b0dca0f9c | |||
| 34c83d7d29 | |||
| 7c6882234e | |||
| 2e68ddbae9 | |||
| c6c71abf4d |
+1
-2
@@ -1,4 +1,3 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- "0.8"
|
||||
- "0.10"
|
||||
- "0.10"
|
||||
|
||||
@@ -1,3 +1,34 @@
|
||||
4.0.0 /
|
||||
==================
|
||||
|
||||
* remove:
|
||||
- express(1) - moved to [express-generator](https://github.com/expressjs/generator)
|
||||
- `express.createServer()` - it has been deprecated for a long time. Use `express()`
|
||||
- `app.configure` - use logic in your own app code
|
||||
- `app.router` - is removed
|
||||
- `req.accepted*` - use `req.accepts*()` instead
|
||||
- `res.location` - relative URL resolution is removed
|
||||
- all bundled middleware except `static`
|
||||
* change:
|
||||
- `app.route` -> `app.mountpath` when mounting an express app in another express app
|
||||
- `json spaces` no longer enabled by default in development
|
||||
- `req.accepts*` -> `req.accepts*s` - i.e. `req.acceptsEncoding` -> `req.acceptsEncodings`
|
||||
- `req.params` is now an object instead of an array
|
||||
- `res.locals` is no longer a function. It is a plain js object. Treat it as such.
|
||||
- `res.headerSent` -> `res.headersSent` to match node.js ServerResponse object
|
||||
* refactor:
|
||||
- `req.accepts*` with [accepts](https://github.com/expressjs/accepts)
|
||||
- `req.is` with [type-is](https://github.com/expressjs/type-is)
|
||||
* add:
|
||||
- `app.router()` - returns the app Router instance
|
||||
- `app.route()` - Proxy to the app's `Router#route()` method to create a new route
|
||||
- Router & Route - public API
|
||||
|
||||
3.4.7 / 2013-12-10
|
||||
==================
|
||||
|
||||
* update connect
|
||||
|
||||
3.4.6 / 2013-12-01
|
||||
==================
|
||||
|
||||
|
||||
+3
-3
@@ -24,11 +24,11 @@ test-cov: lib-cov
|
||||
lib-cov:
|
||||
@jscoverage lib lib-cov
|
||||
|
||||
benchmark:
|
||||
@./support/bench
|
||||
bench:
|
||||
@$(MAKE) -C benchmarks
|
||||
|
||||
clean:
|
||||
rm -f coverage.html
|
||||
rm -fr lib-cov
|
||||
|
||||
.PHONY: test test-unit test-acceptance benchmark clean
|
||||
.PHONY: test test-unit test-acceptance bench clean
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
|
||||
all:
|
||||
@./run 1 middleware
|
||||
@./run 5 middleware
|
||||
@./run 10 middleware
|
||||
@./run 15 middleware
|
||||
@./run 20 middleware
|
||||
@./run 30 middleware
|
||||
@./run 50 middleware
|
||||
@./run 100 middleware
|
||||
@echo
|
||||
|
||||
.PHONY: all
|
||||
@@ -0,0 +1,23 @@
|
||||
|
||||
var http = require('http');
|
||||
var express = require('..');
|
||||
var app = express();
|
||||
|
||||
// number of middleware
|
||||
|
||||
var n = parseInt(process.env.MW || '1', 10);
|
||||
console.log(' %s middleware', n);
|
||||
|
||||
while (n--) {
|
||||
app.use(function(req, res, next){
|
||||
next();
|
||||
});
|
||||
}
|
||||
|
||||
var body = new Buffer('Hello World');
|
||||
|
||||
app.use(function(req, res, next){
|
||||
res.send(body);
|
||||
});
|
||||
|
||||
app.listen(3333);
|
||||
Arquivo executável
+16
@@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
echo
|
||||
MW=$1 node $2 &
|
||||
pid=$!
|
||||
|
||||
sleep 2
|
||||
|
||||
wrk 'http://localhost:3333/?foo[bar]=baz' \
|
||||
-d 3 \
|
||||
-c 50 \
|
||||
-t 8 \
|
||||
| grep 'Requests/sec' \
|
||||
| awk '{ print " " $2 }'
|
||||
|
||||
kill $pid
|
||||
-423
@@ -1,423 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var program = require('commander')
|
||||
, mkdirp = require('mkdirp')
|
||||
, pkg = require('../package.json')
|
||||
, version = pkg.version
|
||||
, os = require('os')
|
||||
, fs = require('fs');
|
||||
|
||||
// CLI
|
||||
|
||||
program
|
||||
.version(version)
|
||||
.usage('[options] [dir]')
|
||||
.option('-s, --sessions', 'add session support')
|
||||
.option('-e, --ejs', 'add ejs engine support (defaults to jade)')
|
||||
.option('-J, --jshtml', 'add jshtml engine support (defaults to jade)')
|
||||
.option('-H, --hogan', 'add hogan.js engine support')
|
||||
.option('-c, --css <engine>', 'add stylesheet <engine> support (less|stylus) (defaults to plain css)')
|
||||
.option('-f, --force', 'force on non-empty directory')
|
||||
.parse(process.argv);
|
||||
|
||||
// Path
|
||||
|
||||
var path = program.args.shift() || '.';
|
||||
|
||||
// end-of-line code
|
||||
|
||||
var eol = os.EOL
|
||||
|
||||
// Template engine
|
||||
|
||||
program.template = 'jade';
|
||||
if (program.ejs) program.template = 'ejs';
|
||||
if (program.jshtml) program.template = 'jshtml';
|
||||
if (program.hogan) program.template = 'hjs';
|
||||
|
||||
/**
|
||||
* Routes index template.
|
||||
*/
|
||||
|
||||
var index = [
|
||||
''
|
||||
, '/*'
|
||||
, ' * GET home page.'
|
||||
, ' */'
|
||||
, ''
|
||||
, 'exports.index = function(req, res){'
|
||||
, ' res.render(\'index\', { title: \'Express\' });'
|
||||
, '};'
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* Routes users template.
|
||||
*/
|
||||
|
||||
var users = [
|
||||
''
|
||||
, '/*'
|
||||
, ' * GET users listing.'
|
||||
, ' */'
|
||||
, ''
|
||||
, 'exports.list = function(req, res){'
|
||||
, ' res.send("respond with a resource");'
|
||||
, '};'
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* Jade layout template.
|
||||
*/
|
||||
|
||||
var jadeLayout = [
|
||||
'doctype 5'
|
||||
, 'html'
|
||||
, ' head'
|
||||
, ' title= title'
|
||||
, ' link(rel=\'stylesheet\', href=\'/stylesheets/style.css\')'
|
||||
, ' body'
|
||||
, ' block content'
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* Jade index template.
|
||||
*/
|
||||
|
||||
var jadeIndex = [
|
||||
'extends layout'
|
||||
, ''
|
||||
, 'block content'
|
||||
, ' h1= title'
|
||||
, ' p Welcome to #{title}'
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* EJS index template.
|
||||
*/
|
||||
|
||||
var ejsIndex = [
|
||||
'<!DOCTYPE html>'
|
||||
, '<html>'
|
||||
, ' <head>'
|
||||
, ' <title><%= title %></title>'
|
||||
, ' <link rel=\'stylesheet\' href=\'/stylesheets/style.css\' />'
|
||||
, ' </head>'
|
||||
, ' <body>'
|
||||
, ' <h1><%= title %></h1>'
|
||||
, ' <p>Welcome to <%= title %></p>'
|
||||
, ' </body>'
|
||||
, '</html>'
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* JSHTML layout template.
|
||||
*/
|
||||
|
||||
var jshtmlLayout = [
|
||||
'<!DOCTYPE html>'
|
||||
, '<html>'
|
||||
, ' <head>'
|
||||
, ' <title> @write(title) </title>'
|
||||
, ' <link rel=\'stylesheet\' href=\'/stylesheets/style.css\' />'
|
||||
, ' </head>'
|
||||
, ' <body>'
|
||||
, ' @write(body)'
|
||||
, ' </body>'
|
||||
, '</html>'
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* JSHTML index template.
|
||||
*/
|
||||
|
||||
var jshtmlIndex = [
|
||||
'<h1>@write(title)</h1>'
|
||||
, '<p>Welcome to @write(title)</p>'
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* Hogan.js index template.
|
||||
*/
|
||||
var hoganIndex = [
|
||||
'<!DOCTYPE html>'
|
||||
, '<html>'
|
||||
, ' <head>'
|
||||
, ' <title>{{ title }}</title>'
|
||||
, ' <link rel=\'stylesheet\' href=\'/stylesheets/style.css\' />'
|
||||
, ' </head>'
|
||||
, ' <body>'
|
||||
, ' <h1>{{ title }}</h1>'
|
||||
, ' <p>Welcome to {{ title }}</p>'
|
||||
, ' </body>'
|
||||
, '</html>'
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* Default css template.
|
||||
*/
|
||||
|
||||
var css = [
|
||||
'body {'
|
||||
, ' padding: 50px;'
|
||||
, ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;'
|
||||
, '}'
|
||||
, ''
|
||||
, 'a {'
|
||||
, ' color: #00B7FF;'
|
||||
, '}'
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* Default less template.
|
||||
*/
|
||||
|
||||
var less = [
|
||||
'body {'
|
||||
, ' padding: 50px;'
|
||||
, ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;'
|
||||
, '}'
|
||||
, ''
|
||||
, 'a {'
|
||||
, ' color: #00B7FF;'
|
||||
, '}'
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* Default stylus template.
|
||||
*/
|
||||
|
||||
var stylus = [
|
||||
'body'
|
||||
, ' padding: 50px'
|
||||
, ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif'
|
||||
, 'a'
|
||||
, ' color: #00B7FF'
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* App template.
|
||||
*/
|
||||
|
||||
var app = [
|
||||
''
|
||||
, '/**'
|
||||
, ' * Module dependencies.'
|
||||
, ' */'
|
||||
, ''
|
||||
, 'var express = require(\'express\');'
|
||||
, 'var routes = require(\'./routes\');'
|
||||
, 'var user = require(\'./routes/user\');'
|
||||
, 'var http = require(\'http\');'
|
||||
, 'var path = require(\'path\');'
|
||||
, ''
|
||||
, 'var app = express();'
|
||||
, ''
|
||||
, '// all environments'
|
||||
, 'app.set(\'port\', process.env.PORT || 3000);'
|
||||
, 'app.set(\'views\', path.join(__dirname, \'views\'));'
|
||||
, 'app.set(\'view engine\', \':TEMPLATE\');'
|
||||
, 'app.use(express.favicon());'
|
||||
, 'app.use(express.logger(\'dev\'));'
|
||||
, 'app.use(express.json());'
|
||||
, 'app.use(express.urlencoded());'
|
||||
, 'app.use(express.methodOverride());{sess}'
|
||||
, 'app.use(app.router);{css}'
|
||||
, 'app.use(express.static(path.join(__dirname, \'public\')));'
|
||||
, ''
|
||||
, '// development only'
|
||||
, 'if (\'development\' == app.get(\'env\')) {'
|
||||
, ' app.use(express.errorHandler());'
|
||||
, '}'
|
||||
, ''
|
||||
, 'app.get(\'/\', routes.index);'
|
||||
, 'app.get(\'/users\', user.list);'
|
||||
, ''
|
||||
, 'http.createServer(app).listen(app.get(\'port\'), function(){'
|
||||
, ' console.log(\'Express server listening on port \' + app.get(\'port\'));'
|
||||
, '});'
|
||||
, ''
|
||||
].join(eol);
|
||||
|
||||
// Generate application
|
||||
|
||||
(function createApplication(path) {
|
||||
emptyDirectory(path, function(empty){
|
||||
if (empty || program.force) {
|
||||
createApplicationAt(path);
|
||||
} else {
|
||||
program.confirm('destination is not empty, continue? ', function(ok){
|
||||
if (ok) {
|
||||
process.stdin.destroy();
|
||||
createApplicationAt(path);
|
||||
} else {
|
||||
abort('aborting');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
})(path);
|
||||
|
||||
/**
|
||||
* Create application at the given directory `path`.
|
||||
*
|
||||
* @param {String} path
|
||||
*/
|
||||
|
||||
function createApplicationAt(path) {
|
||||
console.log();
|
||||
process.on('exit', function(){
|
||||
console.log();
|
||||
console.log(' install dependencies:');
|
||||
console.log(' $ cd %s && npm install', path);
|
||||
console.log();
|
||||
console.log(' run the app:');
|
||||
console.log(' $ node app');
|
||||
console.log();
|
||||
});
|
||||
|
||||
mkdir(path, function(){
|
||||
mkdir(path + '/public');
|
||||
mkdir(path + '/public/javascripts');
|
||||
mkdir(path + '/public/images');
|
||||
mkdir(path + '/public/stylesheets', function(){
|
||||
switch (program.css) {
|
||||
case 'less':
|
||||
write(path + '/public/stylesheets/style.less', less);
|
||||
break;
|
||||
case 'stylus':
|
||||
write(path + '/public/stylesheets/style.styl', stylus);
|
||||
break;
|
||||
default:
|
||||
write(path + '/public/stylesheets/style.css', css);
|
||||
}
|
||||
});
|
||||
|
||||
mkdir(path + '/routes', function(){
|
||||
write(path + '/routes/index.js', index);
|
||||
write(path + '/routes/user.js', users);
|
||||
});
|
||||
|
||||
mkdir(path + '/views', function(){
|
||||
switch (program.template) {
|
||||
case 'ejs':
|
||||
write(path + '/views/index.ejs', ejsIndex);
|
||||
break;
|
||||
case 'jade':
|
||||
write(path + '/views/layout.jade', jadeLayout);
|
||||
write(path + '/views/index.jade', jadeIndex);
|
||||
break;
|
||||
case 'jshtml':
|
||||
write(path + '/views/layout.jshtml', jshtmlLayout);
|
||||
write(path + '/views/index.jshtml', jshtmlIndex);
|
||||
break;
|
||||
case 'hjs':
|
||||
write(path + '/views/index.hjs', hoganIndex);
|
||||
break;
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
// CSS Engine support
|
||||
switch (program.css) {
|
||||
case 'less':
|
||||
app = app.replace('{css}', eol + 'app.use(require(\'less-middleware\')({ src: path.join(__dirname, \'public\') }));');
|
||||
break;
|
||||
case 'stylus':
|
||||
app = app.replace('{css}', eol + 'app.use(require(\'stylus\').middleware(path.join(__dirname, \'public\')));');
|
||||
break;
|
||||
default:
|
||||
app = app.replace('{css}', '');
|
||||
}
|
||||
|
||||
// Session support
|
||||
app = app.replace('{sess}', program.sessions
|
||||
? eol + 'app.use(express.cookieParser(\'your secret here\'));' + eol + 'app.use(express.session());'
|
||||
: '');
|
||||
|
||||
// Template support
|
||||
app = app.replace(':TEMPLATE', program.template);
|
||||
|
||||
// package.json
|
||||
var pkg = {
|
||||
name: 'application-name'
|
||||
, version: '0.0.1'
|
||||
, private: true
|
||||
, scripts: { start: 'node app.js' }
|
||||
, dependencies: {
|
||||
express: version
|
||||
}
|
||||
}
|
||||
|
||||
if (program.template) pkg.dependencies[program.template] = '*';
|
||||
|
||||
// CSS Engine support
|
||||
switch (program.css) {
|
||||
case 'less':
|
||||
pkg.dependencies['less-middleware'] = '*';
|
||||
break;
|
||||
default:
|
||||
if (program.css) {
|
||||
pkg.dependencies[program.css] = '*';
|
||||
}
|
||||
}
|
||||
|
||||
write(path + '/package.json', JSON.stringify(pkg, null, 2));
|
||||
write(path + '/app.js', app);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given directory `path` is empty.
|
||||
*
|
||||
* @param {String} path
|
||||
* @param {Function} fn
|
||||
*/
|
||||
|
||||
function emptyDirectory(path, fn) {
|
||||
fs.readdir(path, function(err, files){
|
||||
if (err && 'ENOENT' != err.code) throw err;
|
||||
fn(!files || !files.length);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* echo str > path.
|
||||
*
|
||||
* @param {String} path
|
||||
* @param {String} str
|
||||
*/
|
||||
|
||||
function write(path, str) {
|
||||
fs.writeFile(path, str);
|
||||
console.log(' \x1b[36mcreate\x1b[0m : ' + path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mkdir -p.
|
||||
*
|
||||
* @param {String} path
|
||||
* @param {Function} fn
|
||||
*/
|
||||
|
||||
function mkdir(path, fn) {
|
||||
mkdirp(path, 0755, function(err){
|
||||
if (err) throw err;
|
||||
console.log(' \033[36mcreate\033[0m : ' + path);
|
||||
fn && fn();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Exit with the given `str`.
|
||||
*
|
||||
* @param {String} str
|
||||
*/
|
||||
|
||||
function abort(str) {
|
||||
console.error(str);
|
||||
process.exit(1);
|
||||
}
|
||||
@@ -3,7 +3,10 @@
|
||||
*/
|
||||
|
||||
var express = require('../..')
|
||||
, hash = require('./pass').hash;
|
||||
, hash = require('./pass').hash
|
||||
, bodyParser = require('body-parser')
|
||||
, cookieParser = require('cookie-parser')
|
||||
, session = require('express-session')
|
||||
|
||||
var app = module.exports = express();
|
||||
|
||||
@@ -14,9 +17,9 @@ app.set('views', __dirname + '/views');
|
||||
|
||||
// middleware
|
||||
|
||||
app.use(express.bodyParser());
|
||||
app.use(express.cookieParser('shhhh, very secret'));
|
||||
app.use(express.session());
|
||||
app.use(bodyParser());
|
||||
app.use(cookieParser('shhhh, very secret'));
|
||||
app.use(session());
|
||||
|
||||
// Session-persisted message middleware
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
|
||||
var express = require('../..')
|
||||
, logger = require('morgan')
|
||||
, app = express();
|
||||
|
||||
app.set('views', __dirname);
|
||||
@@ -14,11 +15,11 @@ while (n--) {
|
||||
pets.push({ name: 'Jane', age: 6, species: 'ferret' });
|
||||
}
|
||||
|
||||
app.use(express.logger('dev'));
|
||||
app.use(logger('dev'));
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.render('pets', { pets: pets });
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express listening on port 3000');
|
||||
console.log('Express listening on port 3000');
|
||||
|
||||
@@ -4,17 +4,19 @@
|
||||
*/
|
||||
|
||||
var express = require('../../');
|
||||
var favicon = require('static-favicon');
|
||||
var cookie-parser = require('cookie-parser');
|
||||
|
||||
var app = module.exports = express();
|
||||
|
||||
// ignore GET /favicon.ico
|
||||
app.use(express.favicon());
|
||||
app.use(favicon());
|
||||
|
||||
// pass a secret to cookieParser() for signed cookies
|
||||
app.use(express.cookieParser('manny is cool'));
|
||||
app.use(cookieParser('manny is cool'));
|
||||
|
||||
// add req.session cookie support
|
||||
app.use(express.cookieSession());
|
||||
app.use(cookieSession());
|
||||
|
||||
// do something with the session
|
||||
app.use(count);
|
||||
@@ -29,4 +31,4 @@ function count(req, res) {
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express server listening on port 3000');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,11 @@
|
||||
*/
|
||||
|
||||
var express = require('../../')
|
||||
, app = module.exports = express();
|
||||
, app = module.exports = express()
|
||||
, favicon = require('static-favicon')
|
||||
, logger = require('morgan')
|
||||
, cookieParser = require('cookie-parser')
|
||||
, bodyParser = require('body-parser')
|
||||
|
||||
|
||||
// add favicon() before logger() so
|
||||
@@ -12,20 +16,20 @@ var express = require('../../')
|
||||
// logged, because this middleware
|
||||
// reponds to /favicon.ico and does not
|
||||
// call next()
|
||||
app.use(express.favicon());
|
||||
app.use(favicon());
|
||||
|
||||
// custom log format
|
||||
if ('test' != process.env.NODE_ENV)
|
||||
app.use(express.logger(':method :url'));
|
||||
app.use(logger(':method :url'));
|
||||
|
||||
// parses request cookies, populating
|
||||
// req.cookies and req.signedCookies
|
||||
// when the secret is passed, used
|
||||
// when the secret is passed, used
|
||||
// for signing the cookies.
|
||||
app.use(express.cookieParser('my secret here'));
|
||||
app.use(cookieParser('my secret here'));
|
||||
|
||||
// parses json, x-www-form-urlencoded, and multipart/form-data
|
||||
app.use(express.bodyParser());
|
||||
app.use(bodyParser());
|
||||
|
||||
app.get('/', function(req, res){
|
||||
if (req.cookies.remember) {
|
||||
@@ -51,4 +55,4 @@ app.post('/', function(req, res){
|
||||
if (!module.parent){
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
*/
|
||||
|
||||
var express = require('../..')
|
||||
, logger = require('morgan')
|
||||
, app = express()
|
||||
, bodyParser = require('body-parser')
|
||||
, api = express();
|
||||
|
||||
// app middleware
|
||||
@@ -12,8 +14,8 @@ app.use(express.static(__dirname + '/public'));
|
||||
|
||||
// api middleware
|
||||
|
||||
api.use(express.logger('dev'));
|
||||
api.use(express.bodyParser());
|
||||
api.use(logger('dev'));
|
||||
api.use(bodyParser());
|
||||
|
||||
/**
|
||||
* CORS support.
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
var express = require('../../')
|
||||
, app = module.exports = express()
|
||||
, logger = require('morgan')
|
||||
, favicon = require('static-favicon')
|
||||
, silent = 'test' == process.env.NODE_ENV;
|
||||
|
||||
// general config
|
||||
@@ -21,18 +23,36 @@ if ('production' == app.settings.env) {
|
||||
app.disable('verbose errors');
|
||||
}
|
||||
|
||||
app.use(express.favicon());
|
||||
app.use(favicon());
|
||||
|
||||
silent || app.use(express.logger('dev'));
|
||||
silent || app.use(logger('dev'));
|
||||
|
||||
// "app.router" positions our routes
|
||||
// above the middleware defined below,
|
||||
// this means that Express will attempt
|
||||
// to match & call routes _before_ continuing
|
||||
// on, at which point we assume it's a 404 because
|
||||
// no route has handled the request.
|
||||
// Routes
|
||||
|
||||
app.use(app.router);
|
||||
app.get('/', function(req, res){
|
||||
res.render('index.jade');
|
||||
});
|
||||
|
||||
app.get('/404', function(req, res, next){
|
||||
// trigger a 404 since no other middleware
|
||||
// will match /404 after this one, and we're not
|
||||
// responding here
|
||||
next();
|
||||
});
|
||||
|
||||
app.get('/403', function(req, res, next){
|
||||
// trigger a 403 error
|
||||
var err = new Error('not allowed!');
|
||||
err.status = 403;
|
||||
next(err);
|
||||
});
|
||||
|
||||
app.get('/500', function(req, res, next){
|
||||
// trigger a generic (500) error
|
||||
next(new Error('keyboard cat!'));
|
||||
});
|
||||
|
||||
// Error handlers
|
||||
|
||||
// Since this is the last non-error-handling
|
||||
// middleware use()d, we assume 404, as nothing else
|
||||
@@ -44,7 +64,7 @@ app.use(app.router);
|
||||
|
||||
app.use(function(req, res, next){
|
||||
res.status(404);
|
||||
|
||||
|
||||
// respond with html page
|
||||
if (req.accepts('html')) {
|
||||
res.render('404', { url: req.url });
|
||||
@@ -81,32 +101,8 @@ app.use(function(err, req, res, next){
|
||||
res.render('500', { error: err });
|
||||
});
|
||||
|
||||
// Routes
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.render('index.jade');
|
||||
});
|
||||
|
||||
app.get('/404', function(req, res, next){
|
||||
// trigger a 404 since no other middleware
|
||||
// will match /404 after this one, and we're not
|
||||
// responding here
|
||||
next();
|
||||
});
|
||||
|
||||
app.get('/403', function(req, res, next){
|
||||
// trigger a 403 error
|
||||
var err = new Error('not allowed!');
|
||||
err.status = 403;
|
||||
next(err);
|
||||
});
|
||||
|
||||
app.get('/500', function(req, res, next){
|
||||
// trigger a generic (500) error
|
||||
next(new Error('keyboard cat!'));
|
||||
});
|
||||
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
silent || console.log('Express started on port 3000');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,17 +4,11 @@
|
||||
*/
|
||||
|
||||
var express = require('../../')
|
||||
, logger = require('morgan')
|
||||
, app = module.exports = express()
|
||||
, test = app.get('env') == 'test';
|
||||
|
||||
if (!test) app.use(express.logger('dev'));
|
||||
app.use(app.router);
|
||||
|
||||
// the error handler is strategically
|
||||
// placed *below* the app.router; if it
|
||||
// were above it would not receive errors
|
||||
// from app.get() etc
|
||||
app.use(error);
|
||||
if (!test) app.use(logger('dev'));
|
||||
|
||||
// error handling middleware have an arity of 4
|
||||
// instead of the typical (req, res, next),
|
||||
@@ -42,7 +36,12 @@ app.get('/next', function(req, res, next){
|
||||
});
|
||||
});
|
||||
|
||||
// the error handler is placed after routes
|
||||
// if it were above it would not receive errors
|
||||
// from app.get() etc
|
||||
app.use(error);
|
||||
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
|
||||
var express = require('../..')
|
||||
, logger = require('morgan')
|
||||
, app = express();
|
||||
|
||||
app.set('view engine', 'jade');
|
||||
@@ -23,7 +24,7 @@ User.prototype.toJSON = function(){
|
||||
}
|
||||
};
|
||||
|
||||
app.use(express.logger('dev'));
|
||||
app.use(logger('dev'));
|
||||
|
||||
// earlier on expose an object
|
||||
// that we can tack properties on.
|
||||
@@ -57,4 +58,4 @@ app.get('/user', function(req, res){
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('app listening on port 3000');
|
||||
console.log('app listening on port 3000');
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
!!! 5
|
||||
doctype html
|
||||
html
|
||||
include header
|
||||
body
|
||||
block content
|
||||
block content
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
var express = require('../..');
|
||||
var logger = require('morgan');
|
||||
var session = require('express-session');
|
||||
var cookieParser = require('cookie-parser');
|
||||
var bodyParser = require('body-parser');
|
||||
|
||||
var app = module.exports = express();
|
||||
|
||||
@@ -25,20 +29,17 @@ app.response.message = function(msg){
|
||||
};
|
||||
|
||||
// log
|
||||
if (!module.parent) app.use(express.logger('dev'));
|
||||
if (!module.parent) app.use(logger('dev'));
|
||||
|
||||
// serve static files
|
||||
app.use(express.static(__dirname + '/public'));
|
||||
|
||||
// session support
|
||||
app.use(express.cookieParser('some secret here'));
|
||||
app.use(express.session());
|
||||
app.use(cookieParser('some secret here'));
|
||||
app.use(session());
|
||||
|
||||
// parse request bodies (req.body)
|
||||
app.use(express.bodyParser());
|
||||
|
||||
// support _method (PUT in forms etc)
|
||||
app.use(express.methodOverride());
|
||||
app.use(bodyParser());
|
||||
|
||||
// expose the "messages" local variable when views are rendered
|
||||
app.use(function(req, res, next){
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
|
||||
var express = require('../..')
|
||||
, app = express()
|
||||
, logger = require('morgan')
|
||||
, cookieParser = require('cookie-parser')
|
||||
, bodyParser = require('body-parser')
|
||||
, site = require('./site')
|
||||
, post = require('./post')
|
||||
, user = require('./user');
|
||||
@@ -13,10 +16,9 @@ var express = require('../..')
|
||||
|
||||
app.set('view engine', 'jade');
|
||||
app.set('views', __dirname + '/views');
|
||||
app.use(express.logger('dev'));
|
||||
app.use(express.cookieParser());
|
||||
app.use(express.bodyParser());
|
||||
app.use(express.methodOverride());
|
||||
app.use(logger('dev'));
|
||||
app.use(cookieParser());
|
||||
app.use(bodyParser());
|
||||
app.use(express.static(__dirname + '/public'));
|
||||
|
||||
// General
|
||||
|
||||
@@ -7,8 +7,6 @@ var express = require('../..');
|
||||
|
||||
var app = express();
|
||||
|
||||
app.use(express.logger('dev'));
|
||||
|
||||
// Required by session() middleware
|
||||
// pass the secret for signed cookies
|
||||
// (required by session())
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
|
||||
var express = require('../..');
|
||||
var logger = require('morgan');
|
||||
var app = express();
|
||||
|
||||
// log requests
|
||||
app.use(express.logger('dev'));
|
||||
app.use(logger('dev'));
|
||||
|
||||
// express on its own has no notion
|
||||
// of a "file". The express.static()
|
||||
@@ -41,4 +42,4 @@ console.log('listening on port 3000');
|
||||
console.log('try:');
|
||||
console.log(' GET /hello.txt');
|
||||
console.log(' GET /js/app.js');
|
||||
console.log(' GET /css/style.css');
|
||||
console.log(' GET /css/style.css');
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*/
|
||||
|
||||
var express = require('../..');
|
||||
var logger = require('morgan');
|
||||
|
||||
/*
|
||||
edit /etc/hosts:
|
||||
@@ -16,7 +17,7 @@ edit /etc/hosts:
|
||||
|
||||
var main = express();
|
||||
|
||||
main.use(express.logger('dev'));
|
||||
main.use(logger('dev'));
|
||||
|
||||
main.get('/', function(req, res){
|
||||
res.send('Hello from main app!')
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
doctype 5
|
||||
doctype html
|
||||
html
|
||||
head
|
||||
title= title
|
||||
|
||||
@@ -40,29 +40,6 @@ app.use('/api', function(req, res, next){
|
||||
next();
|
||||
});
|
||||
|
||||
// position our routes above the error handling middleware,
|
||||
// and below our API middleware, since we want the API validation
|
||||
// to take place BEFORE our routes
|
||||
app.use(app.router);
|
||||
|
||||
// middleware with an arity of 4 are considered
|
||||
// error handling middleware. When you next(err)
|
||||
// it will be passed through the defined middleware
|
||||
// in order, but ONLY those with an arity of 4, ignoring
|
||||
// regular middleware.
|
||||
app.use(function(err, req, res, next){
|
||||
// whatever you want here, feel free to populate
|
||||
// properties on `err` to treat it differently in here.
|
||||
res.send(err.status || 500, { error: err.message });
|
||||
});
|
||||
|
||||
// our custom JSON 404 middleware. Since it's placed last
|
||||
// it will be the last middleware called, if all others
|
||||
// invoke next() and do not respond.
|
||||
app.use(function(req, res){
|
||||
res.send(404, { error: "Lame, can't find that" });
|
||||
});
|
||||
|
||||
// map of valid api keys, typically mapped to
|
||||
// account info with some sort of database like redis.
|
||||
// api keys do _not_ serve as authentication, merely to
|
||||
@@ -104,12 +81,30 @@ app.get('/api/repos', function(req, res, next){
|
||||
app.get('/api/user/:name/repos', function(req, res, next){
|
||||
var name = req.params.name
|
||||
, user = userRepos[name];
|
||||
|
||||
|
||||
if (user) res.send(user);
|
||||
else next();
|
||||
});
|
||||
|
||||
// middleware with an arity of 4 are considered
|
||||
// error handling middleware. When you next(err)
|
||||
// it will be passed through the defined middleware
|
||||
// in order, but ONLY those with an arity of 4, ignoring
|
||||
// regular middleware.
|
||||
app.use(function(err, req, res, next){
|
||||
// whatever you want here, feel free to populate
|
||||
// properties on `err` to treat it differently in here.
|
||||
res.send(err.status || 500, { error: err.message });
|
||||
});
|
||||
|
||||
// our custom JSON 404 middleware. Since it's placed last
|
||||
// it will be the last middleware called, if all others
|
||||
// invoke next() and do not respond.
|
||||
app.use(function(req, res){
|
||||
res.send(404, { error: "Lame, can't find that" });
|
||||
});
|
||||
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express server listening on port 3000');
|
||||
}
|
||||
}
|
||||
|
||||
+149
-142
@@ -2,14 +2,14 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var connect = require('connect')
|
||||
var mixin = require('utils-merge')
|
||||
, escapeHtml = require('escape-html')
|
||||
, Router = require('./router')
|
||||
, methods = require('methods')
|
||||
, middleware = require('./middleware')
|
||||
, middleware = require('./middleware/init')
|
||||
, query = require('./middleware/query')
|
||||
, debug = require('debug')('express:application')
|
||||
, locals = require('./utils').locals
|
||||
, View = require('./view')
|
||||
, utils = connect.utils
|
||||
, http = require('http');
|
||||
|
||||
/**
|
||||
@@ -45,13 +45,11 @@ app.defaultConfiguration = function(){
|
||||
// default settings
|
||||
this.enable('x-powered-by');
|
||||
this.enable('etag');
|
||||
this.set('env', process.env.NODE_ENV || 'development');
|
||||
var env = process.env.NODE_ENV || 'development';
|
||||
this.set('env', env);
|
||||
this.set('subdomain offset', 2);
|
||||
debug('booting in %s mode', this.get('env'));
|
||||
|
||||
// implicit middleware
|
||||
this.use(connect.query());
|
||||
this.use(middleware.init(this));
|
||||
debug('booting in %s mode', env);
|
||||
|
||||
// inherit protos
|
||||
this.on('mount', function(parent){
|
||||
@@ -61,18 +59,11 @@ app.defaultConfiguration = function(){
|
||||
this.settings.__proto__ = parent.settings;
|
||||
});
|
||||
|
||||
// router
|
||||
this._router = new Router(this);
|
||||
this.routes = this._router.map;
|
||||
this.__defineGetter__('router', function(){
|
||||
this._usedRouter = true;
|
||||
this._router.caseSensitive = this.enabled('case sensitive routing');
|
||||
this._router.strict = this.enabled('strict routing');
|
||||
return this._router.middleware;
|
||||
});
|
||||
|
||||
// setup locals
|
||||
this.locals = locals(this);
|
||||
this.locals = Object.create(null);
|
||||
|
||||
// top-most app is mounted at /
|
||||
this.mountpath = '/';
|
||||
|
||||
// default locals
|
||||
this.locals.settings = this.settings;
|
||||
@@ -82,18 +73,94 @@ app.defaultConfiguration = function(){
|
||||
this.set('views', process.cwd() + '/views');
|
||||
this.set('jsonp callback name', 'callback');
|
||||
|
||||
this.configure('development', function(){
|
||||
this.set('json spaces', 2);
|
||||
});
|
||||
|
||||
this.configure('production', function(){
|
||||
if (env === 'production') {
|
||||
this.enable('view cache');
|
||||
}
|
||||
|
||||
Object.defineProperty(this, 'router', {
|
||||
get: function() {
|
||||
throw new Error('\'app.router\' is deprecated!\nPlease see the 3.x to 4.x migration guide for details on how to update your app.');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Proxy `connect#use()` to apply settings to
|
||||
* mounted applications.
|
||||
* lazily adds the base router if it has not yet been added.
|
||||
*
|
||||
* We cannot add the base router in the defaultConfiguration because
|
||||
* it reads app settings which might be set after that has run.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
app.lazyrouter = function() {
|
||||
if (!this._router) {
|
||||
this._router = new Router({
|
||||
caseSensitive: this.enabled('case sensitive routing'),
|
||||
strict: this.enabled('strict routing')
|
||||
});
|
||||
|
||||
this._router.use(query());
|
||||
this._router.use(middleware.init(this));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Dispatch a req, res pair into the application. Starts pipeline processing.
|
||||
*
|
||||
* If no _done_ callback is provided, then default error handlers will respond
|
||||
* in the event of an error bubbling through the stack.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
app.handle = function(req, res, done) {
|
||||
var env = this.get('env');
|
||||
|
||||
this._router.handle(req, res, function(err) {
|
||||
if (done) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
// unhandled error
|
||||
if (err) {
|
||||
// default to 500
|
||||
if (res.statusCode < 400) res.statusCode = 500;
|
||||
debug('default %s', res.statusCode);
|
||||
|
||||
// respect err.status
|
||||
if (err.status) res.statusCode = err.status;
|
||||
|
||||
// production gets a basic error message
|
||||
var msg = 'production' == env
|
||||
? http.STATUS_CODES[res.statusCode]
|
||||
: err.stack || err.toString();
|
||||
msg = escapeHtml(msg);
|
||||
|
||||
// log to stderr in a non-test env
|
||||
if ('test' != env) console.error(err.stack || err.toString());
|
||||
if (res.headersSent) return req.socket.destroy();
|
||||
res.setHeader('Content-Type', 'text/html');
|
||||
res.setHeader('Content-Length', Buffer.byteLength(msg));
|
||||
if ('HEAD' == req.method) return res.end();
|
||||
res.end(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
// 404
|
||||
debug('default 404');
|
||||
res.statusCode = 404;
|
||||
res.setHeader('Content-Type', 'text/html');
|
||||
if ('HEAD' == req.method) return res.end();
|
||||
res.end('Cannot ' + escapeHtml(req.method) + ' ' + escapeHtml(req.originalUrl) + '\n');
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Proxy `Router#use()` to add middleware to the app router.
|
||||
* See Router#use() documentation for details.
|
||||
*
|
||||
* If the _fn_ parameter is an express app, then it will be
|
||||
* mounted at the _route_ specified.
|
||||
*
|
||||
* @param {String|Function|Server} route
|
||||
* @param {Function|Server} fn
|
||||
@@ -102,20 +169,21 @@ app.defaultConfiguration = function(){
|
||||
*/
|
||||
|
||||
app.use = function(route, fn){
|
||||
var app;
|
||||
var mount_app;
|
||||
|
||||
// default route to '/'
|
||||
if ('string' != typeof route) fn = route, route = '/';
|
||||
|
||||
// express app
|
||||
if (fn.handle && fn.set) app = fn;
|
||||
if (fn.handle && fn.set) mount_app = fn;
|
||||
|
||||
// restore .app property on req and res
|
||||
if (app) {
|
||||
app.route = route;
|
||||
if (mount_app) {
|
||||
debug('.use app under %s', route);
|
||||
mount_app.mountpath = route;
|
||||
fn = function(req, res, next) {
|
||||
var orig = req.app;
|
||||
app.handle(req, res, function(err){
|
||||
mount_app.handle(req, res, function(err) {
|
||||
req.__proto__ = orig.request;
|
||||
res.__proto__ = orig.response;
|
||||
next(err);
|
||||
@@ -123,17 +191,33 @@ app.use = function(route, fn){
|
||||
};
|
||||
}
|
||||
|
||||
connect.proto.use.call(this, route, fn);
|
||||
this.lazyrouter();
|
||||
this._router.use(route, fn);
|
||||
|
||||
// mounted an app
|
||||
if (app) {
|
||||
app.parent = this;
|
||||
app.emit('mount', this);
|
||||
if (mount_app) {
|
||||
mount_app.parent = this;
|
||||
mount_app.emit('mount', this);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Proxy to the app `Router#route()`
|
||||
* Returns a new `Route` instance for the _path_.
|
||||
*
|
||||
* Routes are isolated middleware stacks for specific paths.
|
||||
* See the Route api docs for details.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.route = function(path){
|
||||
this.lazyrouter();
|
||||
return this._router.route(path);
|
||||
};
|
||||
|
||||
/**
|
||||
* Register the given template engine callback `fn`
|
||||
* as `ext`.
|
||||
@@ -176,30 +260,10 @@ app.engine = function(ext, fn){
|
||||
};
|
||||
|
||||
/**
|
||||
* Map the given param placeholder `name`(s) to the given callback(s).
|
||||
* Proxy to `Router#param()` with one added api feature. The _name_ parameter
|
||||
* can be an array of names.
|
||||
*
|
||||
* Parameter mapping is used to provide pre-conditions to routes
|
||||
* which use normalized placeholders. For example a _:user_id_ parameter
|
||||
* could automatically load a user's information from the database without
|
||||
* any additional code,
|
||||
*
|
||||
* The callback uses the same signature as middleware, the only difference
|
||||
* being that the value of the placeholder is passed, in this case the _id_
|
||||
* of the user. Once the `next()` function is invoked, just like middleware
|
||||
* it will continue on to execute the route, or subsequent parameter functions.
|
||||
*
|
||||
* app.param('user_id', function(req, res, next, id){
|
||||
* User.find(id, function(err, user){
|
||||
* if (err) {
|
||||
* next(err);
|
||||
* } else if (user) {
|
||||
* req.user = user;
|
||||
* next();
|
||||
* } else {
|
||||
* next(new Error('failed to load user'));
|
||||
* }
|
||||
* });
|
||||
* });
|
||||
* See the Router#param() docs for more details.
|
||||
*
|
||||
* @param {String|Array} name
|
||||
* @param {Function} fn
|
||||
@@ -208,27 +272,17 @@ app.engine = function(ext, fn){
|
||||
*/
|
||||
|
||||
app.param = function(name, fn){
|
||||
var self = this
|
||||
, fns = [].slice.call(arguments, 1);
|
||||
var self = this;
|
||||
self.lazyrouter();
|
||||
|
||||
// array
|
||||
if (Array.isArray(name)) {
|
||||
name.forEach(function(name){
|
||||
fns.forEach(function(fn){
|
||||
self.param(name, fn);
|
||||
});
|
||||
});
|
||||
// param logic
|
||||
} else if ('function' == typeof name) {
|
||||
this._router.param(name);
|
||||
// single
|
||||
} else {
|
||||
if (':' == name[0]) name = name.substr(1);
|
||||
fns.forEach(function(fn){
|
||||
self._router.param(name, fn);
|
||||
name.forEach(function(key) {
|
||||
self.param(key, fn);
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
self._router.param(name, fn);
|
||||
return this;
|
||||
};
|
||||
|
||||
@@ -242,7 +296,7 @@ app.param = function(name, fn){
|
||||
* Mounted servers inherit their parent server's settings.
|
||||
*
|
||||
* @param {String} setting
|
||||
* @param {String} val
|
||||
* @param {*} [val]
|
||||
* @return {Server} for chaining
|
||||
* @api public
|
||||
*/
|
||||
@@ -272,7 +326,7 @@ app.set = function(setting, val){
|
||||
|
||||
app.path = function(){
|
||||
return this.parent
|
||||
? this.parent.path() + this.route
|
||||
? this.parent.path() + this.mountpath
|
||||
: '';
|
||||
};
|
||||
|
||||
@@ -338,60 +392,6 @@ app.disable = function(setting){
|
||||
return this.set(setting, false);
|
||||
};
|
||||
|
||||
/**
|
||||
* Configure callback for zero or more envs,
|
||||
* when no `env` is specified that callback will
|
||||
* be invoked for all environments. Any combination
|
||||
* can be used multiple times, in any order desired.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* app.configure(function(){
|
||||
* // executed for all envs
|
||||
* });
|
||||
*
|
||||
* app.configure('stage', function(){
|
||||
* // executed staging env
|
||||
* });
|
||||
*
|
||||
* app.configure('stage', 'production', function(){
|
||||
* // executed for stage and production
|
||||
* });
|
||||
*
|
||||
* Note:
|
||||
*
|
||||
* These callbacks are invoked immediately, and
|
||||
* are effectively sugar for the following:
|
||||
*
|
||||
* var env = process.env.NODE_ENV || 'development';
|
||||
*
|
||||
* switch (env) {
|
||||
* case 'development':
|
||||
* ...
|
||||
* break;
|
||||
* case 'stage':
|
||||
* ...
|
||||
* break;
|
||||
* case 'production':
|
||||
* ...
|
||||
* break;
|
||||
* }
|
||||
*
|
||||
* @param {String} env...
|
||||
* @param {Function} fn
|
||||
* @return {app} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.configure = function(env, fn){
|
||||
var envs = 'all'
|
||||
, args = [].slice.call(arguments);
|
||||
fn = args.pop();
|
||||
if (args.length) envs = args;
|
||||
if ('all' == envs || ~envs.indexOf(this.settings.env)) fn.call(this);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Delegate `.VERB(...)` calls to `router.VERB(...)`.
|
||||
*/
|
||||
@@ -400,16 +400,17 @@ methods.forEach(function(method){
|
||||
app[method] = function(path){
|
||||
if ('get' == method && 1 == arguments.length) return this.set(path);
|
||||
|
||||
this.lazyrouter();
|
||||
|
||||
// deprecated
|
||||
if (Array.isArray(path)) {
|
||||
console.trace('passing an array to app.VERB() is deprecated and will be removed in 4.0');
|
||||
}
|
||||
|
||||
// if no router attached yet, attach the router
|
||||
if (!this._usedRouter) this.use(this.router);
|
||||
|
||||
// setup route
|
||||
this._router[method].apply(this._router, arguments);
|
||||
var route = this._router.route(path);
|
||||
for (var i=1 ; i<arguments.length ; ++i) {
|
||||
route[method](arguments[i]);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
});
|
||||
@@ -425,10 +426,16 @@ methods.forEach(function(method){
|
||||
*/
|
||||
|
||||
app.all = function(path){
|
||||
this.lazyrouter();
|
||||
|
||||
var route = this._router.route(path);
|
||||
var args = arguments;
|
||||
methods.forEach(function(method){
|
||||
app[method].apply(this, args);
|
||||
}, this);
|
||||
for (var i=1 ; i<args.length ; ++i) {
|
||||
route[method](args[i]);
|
||||
}
|
||||
});
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
@@ -465,13 +472,13 @@ app.render = function(name, options, fn){
|
||||
}
|
||||
|
||||
// merge app.locals
|
||||
utils.merge(opts, this.locals);
|
||||
mixin(opts, this.locals);
|
||||
|
||||
// merge options._locals
|
||||
if (options._locals) utils.merge(opts, options._locals);
|
||||
if (options._locals) mixin(opts, options._locals);
|
||||
|
||||
// merge options
|
||||
utils.merge(opts, options);
|
||||
mixin(opts, options);
|
||||
|
||||
// set .cache unless explicitly provided
|
||||
opts.cache = null == opts.cache
|
||||
@@ -490,7 +497,7 @@ app.render = function(name, options, fn){
|
||||
});
|
||||
|
||||
if (!view.path) {
|
||||
var err = new Error('Failed to lookup view "' + name + '"');
|
||||
var err = new Error('Failed to lookup view "' + name + '" in views directory "' + view.root + '"');
|
||||
err.view = view;
|
||||
return fn(err);
|
||||
}
|
||||
|
||||
+20
-41
@@ -2,13 +2,19 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var connect = require('connect')
|
||||
, proto = require('./application')
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
|
||||
var merge = require('merge-descriptors')
|
||||
, mixin = require('utils-merge')
|
||||
|
||||
var proto = require('./application')
|
||||
, Route = require('./router/route')
|
||||
, Router = require('./router')
|
||||
, req = require('./request')
|
||||
, res = require('./response')
|
||||
, utils = connect.utils;
|
||||
|
||||
// monkey patch ServerResponse methods
|
||||
require('./patch')
|
||||
|
||||
/**
|
||||
* Expose `createApplication()`.
|
||||
@@ -16,12 +22,6 @@ var connect = require('connect')
|
||||
|
||||
exports = module.exports = createApplication;
|
||||
|
||||
/**
|
||||
* Expose mime.
|
||||
*/
|
||||
|
||||
exports.mime = connect.mime;
|
||||
|
||||
/**
|
||||
* Create an express application.
|
||||
*
|
||||
@@ -30,41 +30,19 @@ exports.mime = connect.mime;
|
||||
*/
|
||||
|
||||
function createApplication() {
|
||||
var app = connect();
|
||||
utils.merge(app, proto);
|
||||
var app = function(req, res, next) {
|
||||
app.handle(req, res, next);
|
||||
};
|
||||
|
||||
mixin(app, proto);
|
||||
mixin(app, EventEmitter.prototype);
|
||||
|
||||
app.request = { __proto__: req, app: app };
|
||||
app.response = { __proto__: res, app: app };
|
||||
app.init();
|
||||
return app;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expose connect.middleware as express.*
|
||||
* for example `express.logger` etc.
|
||||
*/
|
||||
|
||||
for (var key in connect.middleware) {
|
||||
Object.defineProperty(
|
||||
exports
|
||||
, key
|
||||
, Object.getOwnPropertyDescriptor(connect.middleware, key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Error on createServer().
|
||||
*/
|
||||
|
||||
exports.createServer = function(){
|
||||
console.warn('Warning: express.createServer() is deprecated, express');
|
||||
console.warn('applications no longer inherit from http.Server,');
|
||||
console.warn('please use:');
|
||||
console.warn('');
|
||||
console.warn(' var express = require("express");');
|
||||
console.warn(' var app = express();');
|
||||
console.warn('');
|
||||
return createApplication();
|
||||
};
|
||||
|
||||
/**
|
||||
* Expose the prototypes.
|
||||
*/
|
||||
@@ -80,7 +58,8 @@ exports.response = res;
|
||||
exports.Route = Route;
|
||||
exports.Router = Router;
|
||||
|
||||
// Error handler title
|
||||
|
||||
exports.errorHandler.title = 'Express';
|
||||
/**
|
||||
* Expose middleware
|
||||
*/
|
||||
|
||||
exports.static = require('./middleware/static');
|
||||
|
||||
@@ -1,10 +1,3 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var utils = require('./utils');
|
||||
|
||||
/**
|
||||
* Initialization middleware, exposing the
|
||||
* request and response to eachother, as well
|
||||
@@ -25,8 +18,9 @@ exports.init = function(app){
|
||||
req.__proto__ = app.request;
|
||||
res.__proto__ = app.response;
|
||||
|
||||
res.locals = res.locals || utils.locals(res);
|
||||
res.locals = res.locals || Object.create(null);
|
||||
|
||||
next();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
var qs = require('qs');
|
||||
var parseUrl = require('../utils').parseUrl;
|
||||
|
||||
/**
|
||||
* Query:
|
||||
*
|
||||
* Automatically parse the query-string when available,
|
||||
* populating the `req.query` object using
|
||||
* [qs](https://github.com/visionmedia/node-querystring).
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* .use(connect.query())
|
||||
* .use(function(req, res){
|
||||
* res.end(JSON.stringify(req.query));
|
||||
* });
|
||||
*
|
||||
* The `options` passed are provided to qs.parse function.
|
||||
*
|
||||
* @param {Object} options
|
||||
* @return {Function}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
module.exports = function query(options){
|
||||
return function query(req, res, next){
|
||||
if (!req.query) {
|
||||
req.query = ~req.url.indexOf('?')
|
||||
? qs.parse(parseUrl(req).query, options)
|
||||
: {};
|
||||
}
|
||||
|
||||
next();
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,87 @@
|
||||
/*!
|
||||
* Connect - static
|
||||
* Copyright(c) 2010 Sencha Inc.
|
||||
* Copyright(c) 2011 TJ Holowaychuk
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var send = require('send')
|
||||
, utils = require('../utils')
|
||||
, parse = utils.parseUrl
|
||||
, url = require('url');
|
||||
|
||||
/**
|
||||
* Static:
|
||||
*
|
||||
* Static file server with the given `root` path.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* var oneDay = 86400000;
|
||||
*
|
||||
* connect()
|
||||
* .use(connect.static(__dirname + '/public'))
|
||||
*
|
||||
* connect()
|
||||
* .use(connect.static(__dirname + '/public', { maxAge: oneDay }))
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - `maxAge` Browser cache maxAge in milliseconds. defaults to 0
|
||||
* - `hidden` Allow transfer of hidden files. defaults to false
|
||||
* - `redirect` Redirect to trailing "/" when the pathname is a dir. defaults to true
|
||||
* - `index` Default file name, defaults to 'index.html'
|
||||
*
|
||||
* @param {String} root
|
||||
* @param {Object} options
|
||||
* @return {Function}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports = module.exports = function(root, options){
|
||||
options = options || {};
|
||||
|
||||
// root required
|
||||
if (!root) throw new Error('static() root path required');
|
||||
|
||||
// default redirect
|
||||
var redirect = false !== options.redirect;
|
||||
|
||||
return function staticMiddleware(req, res, next) {
|
||||
if ('GET' != req.method && 'HEAD' != req.method) return next();
|
||||
var originalUrl = url.parse(req.originalUrl);
|
||||
var path = parse(req).pathname;
|
||||
|
||||
if (path == '/' && originalUrl.pathname[originalUrl.pathname.length - 1] != '/') {
|
||||
return directory();
|
||||
}
|
||||
|
||||
function directory() {
|
||||
if (!redirect) return next();
|
||||
var target;
|
||||
originalUrl.pathname += '/';
|
||||
target = url.format(originalUrl);
|
||||
res.statusCode = 303;
|
||||
res.setHeader('Location', target);
|
||||
res.end('Redirecting to ' + utils.escape(target));
|
||||
}
|
||||
|
||||
function error(err) {
|
||||
if (404 == err.status) return next();
|
||||
next(err);
|
||||
}
|
||||
|
||||
send(req, path)
|
||||
.maxage(options.maxAge || 0)
|
||||
.root(root)
|
||||
.index(options.index || 'index.html')
|
||||
.hidden(options.hidden)
|
||||
.on('error', error)
|
||||
.on('directory', directory)
|
||||
.pipe(res);
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,54 @@
|
||||
/*!
|
||||
* Connect
|
||||
* Copyright(c) 2011 TJ Holowaychuk
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var http = require('http');
|
||||
var ServerResponse = http.ServerResponse;
|
||||
|
||||
// apply only once
|
||||
if (ServerResponse.prototype._hasConnectPatch) {
|
||||
return;
|
||||
}
|
||||
|
||||
// original methods
|
||||
var setHeader = ServerResponse.prototype.setHeader;
|
||||
var writeHead = ServerResponse.prototype.writeHead;
|
||||
|
||||
/**
|
||||
* Set header `field` to `val`, special-casing
|
||||
* the `Set-Cookie` field for multiple support.
|
||||
*
|
||||
* @param {String} field
|
||||
* @param {String} val
|
||||
* @api public
|
||||
*/
|
||||
|
||||
ServerResponse.prototype.setHeader = function(field, val){
|
||||
var key = field.toLowerCase();
|
||||
|
||||
if ('content-type' == key && this.charset) {
|
||||
val += '; charset=' + this.charset;
|
||||
}
|
||||
|
||||
return setHeader.call(this, field, val);
|
||||
};
|
||||
|
||||
ServerResponse.prototype.writeHead = function(statusCode, reasonPhrase, headers){
|
||||
if (typeof reasonPhrase === 'object') headers = reasonPhrase;
|
||||
if (typeof headers === 'object') {
|
||||
Object.keys(headers).forEach(function(key){
|
||||
this.setHeader(key, headers[key]);
|
||||
}, this);
|
||||
}
|
||||
if (!this._emittedHeader) this.emit('header');
|
||||
this._emittedHeader = true;
|
||||
return writeHead.call(this, statusCode, reasonPhrase);
|
||||
};
|
||||
|
||||
ServerResponse.prototype._hasConnectPatch = true;
|
||||
+28
-124
@@ -3,13 +3,13 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var accepts = require('accepts');
|
||||
var typeis = require('type-is');
|
||||
var http = require('http')
|
||||
, utils = require('./utils')
|
||||
, connect = require('connect')
|
||||
, fresh = require('fresh')
|
||||
, parseRange = require('range-parser')
|
||||
, parse = connect.utils.parseUrl
|
||||
, mime = connect.mime;
|
||||
, parse = utils.parseUrl
|
||||
|
||||
/**
|
||||
* Request prototype.
|
||||
@@ -56,6 +56,8 @@ req.header = function(name){
|
||||
};
|
||||
|
||||
/**
|
||||
* To do: update docs.
|
||||
*
|
||||
* Check if the given `type(s)` is acceptable, returning
|
||||
* the best match when true, otherwise `undefined`, in which
|
||||
* case you should respond with 406 "Not Acceptable".
|
||||
@@ -99,9 +101,9 @@ req.header = function(name){
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.accepts = function(type){
|
||||
var args = arguments.length > 1 ? [].slice.apply(arguments) : type;
|
||||
return utils.accepts(args, this.get('Accept'));
|
||||
req.accepts = function(){
|
||||
var accept = accepts(this);
|
||||
return accept.types.apply(accept, arguments);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -112,11 +114,15 @@ req.accepts = function(type){
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.acceptsEncoding = function(encoding){
|
||||
return !! ~this.acceptedEncodings.indexOf(encoding);
|
||||
req.acceptsEncoding = // backwards compatibility
|
||||
req.acceptsEncodings = function(){
|
||||
var accept = accepts(this);
|
||||
return accept.encodings.apply(accept, arguments);
|
||||
};
|
||||
|
||||
/**
|
||||
* To do: update docs.
|
||||
*
|
||||
* Check if the given `charset` is acceptable,
|
||||
* otherwise you should respond with 406 "Not Acceptable".
|
||||
*
|
||||
@@ -125,14 +131,15 @@ req.acceptsEncoding = function(encoding){
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.acceptsCharset = function(charset){
|
||||
var accepted = this.acceptedCharsets;
|
||||
return accepted.length
|
||||
? !! ~accepted.indexOf(charset)
|
||||
: true;
|
||||
req.acceptsCharset = // backwards compatibility
|
||||
req.acceptsCharsets = function(){
|
||||
var accept = accepts(this);
|
||||
return accept.charsets.apply(accept, arguments);
|
||||
};
|
||||
|
||||
/**
|
||||
* To do: update docs.
|
||||
*
|
||||
* Check if the given `lang` is acceptable,
|
||||
* otherwise you should respond with 406 "Not Acceptable".
|
||||
*
|
||||
@@ -141,11 +148,10 @@ req.acceptsCharset = function(charset){
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.acceptsLanguage = function(lang){
|
||||
var accepted = this.acceptedLanguages;
|
||||
return accepted.length
|
||||
? !! ~accepted.indexOf(lang)
|
||||
: true;
|
||||
req.acceptsLanguage = // backwards compatibility
|
||||
req.acceptsLanguages = function(lang){
|
||||
var accept = accepts(this);
|
||||
return accept.languages.apply(accept, arguments);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -174,98 +180,6 @@ req.range = function(size){
|
||||
return parseRange(size, range);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return an array of encodings.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* ['gzip', 'deflate']
|
||||
*
|
||||
* @return {Array}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.__defineGetter__('acceptedEncodings', function(){
|
||||
var accept = this.get('Accept-Encoding');
|
||||
return accept
|
||||
? accept.trim().split(/ *, */)
|
||||
: [];
|
||||
});
|
||||
|
||||
/**
|
||||
* Return an array of Accepted media types
|
||||
* ordered from highest quality to lowest.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* [ { value: 'application/json',
|
||||
* quality: 1,
|
||||
* type: 'application',
|
||||
* subtype: 'json' },
|
||||
* { value: 'text/html',
|
||||
* quality: 0.5,
|
||||
* type: 'text',
|
||||
* subtype: 'html' } ]
|
||||
*
|
||||
* @return {Array}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.__defineGetter__('accepted', function(){
|
||||
var accept = this.get('Accept');
|
||||
return accept
|
||||
? utils.parseAccept(accept)
|
||||
: [];
|
||||
});
|
||||
|
||||
/**
|
||||
* Return an array of Accepted languages
|
||||
* ordered from highest quality to lowest.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* Accept-Language: en;q=.5, en-us
|
||||
* ['en-us', 'en']
|
||||
*
|
||||
* @return {Array}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.__defineGetter__('acceptedLanguages', function(){
|
||||
var accept = this.get('Accept-Language');
|
||||
return accept
|
||||
? utils
|
||||
.parseParams(accept)
|
||||
.map(function(obj){
|
||||
return obj.value;
|
||||
})
|
||||
: [];
|
||||
});
|
||||
|
||||
/**
|
||||
* Return an array of Accepted charsets
|
||||
* ordered from highest quality to lowest.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* Accept-Charset: iso-8859-5;q=.2, unicode-1-1;q=0.8
|
||||
* ['unicode-1-1', 'iso-8859-5']
|
||||
*
|
||||
* @return {Array}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.__defineGetter__('acceptedCharsets', function(){
|
||||
var accept = this.get('Accept-Charset');
|
||||
return accept
|
||||
? utils
|
||||
.parseParams(accept)
|
||||
.map(function(obj){
|
||||
return obj.value;
|
||||
})
|
||||
: [];
|
||||
});
|
||||
|
||||
/**
|
||||
* Return the value of param `name` when present or `defaultValue`.
|
||||
*
|
||||
@@ -275,7 +189,7 @@ req.__defineGetter__('acceptedCharsets', function(){
|
||||
*
|
||||
* To utilize request bodies, `req.body`
|
||||
* should be an object. This can be done by using
|
||||
* the `connect.bodyParser()` middleware.
|
||||
* the `bodyParser()` middleware.
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {Mixed} [defaultValue]
|
||||
@@ -319,19 +233,9 @@ req.param = function(name, defaultValue){
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.is = function(type){
|
||||
var ct = this.get('Content-Type');
|
||||
if (!ct) return false;
|
||||
ct = ct.split(';')[0];
|
||||
if (!~type.indexOf('/')) type = mime.lookup(type);
|
||||
if (~type.indexOf('*')) {
|
||||
type = type.split('/');
|
||||
ct = ct.split('/');
|
||||
if ('*' == type[0] && type[1] == ct[1]) return true;
|
||||
if ('*' == type[1] && type[0] == ct[0]) return true;
|
||||
return false;
|
||||
}
|
||||
return !! ~ct.indexOf(type);
|
||||
req.is = function(types){
|
||||
if (!Array.isArray(types)) types = [].slice.call(arguments);
|
||||
return typeis(this, types);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
+25
-43
@@ -4,8 +4,8 @@
|
||||
|
||||
var http = require('http')
|
||||
, path = require('path')
|
||||
, connect = require('connect')
|
||||
, utils = connect.utils
|
||||
, mixin = require('utils-merge')
|
||||
, escapeHtml = require('escape-html')
|
||||
, sign = require('cookie-signature').sign
|
||||
, normalizeType = require('./utils').normalizeType
|
||||
, normalizeTypes = require('./utils').normalizeTypes
|
||||
@@ -13,10 +13,10 @@ var http = require('http')
|
||||
, statusCodes = http.STATUS_CODES
|
||||
, cookie = require('cookie')
|
||||
, send = require('send')
|
||||
, mime = connect.mime
|
||||
, resolve = require('url').resolve
|
||||
, basename = path.basename
|
||||
, extname = path.extname;
|
||||
, extname = path.extname
|
||||
, mime = send.mime
|
||||
|
||||
/**
|
||||
* Response prototype.
|
||||
@@ -311,13 +311,13 @@ res.sendfile = function(path, options, fn){
|
||||
|
||||
// clean up
|
||||
cleanup();
|
||||
if (!self.headerSent) self.removeHeader('Content-Disposition');
|
||||
if (!self.headersSent) self.removeHeader('Content-Disposition');
|
||||
|
||||
// callback available
|
||||
if (fn) return fn(err);
|
||||
|
||||
// list in limbo if there's no callback
|
||||
if (self.headerSent) return;
|
||||
if (self.headersSent) return;
|
||||
|
||||
// delegate
|
||||
next(err);
|
||||
@@ -352,7 +352,7 @@ res.sendfile = function(path, options, fn){
|
||||
* Optionally providing an alternate attachment `filename`,
|
||||
* and optional callback `fn(err)`. The callback is invoked
|
||||
* when the data transfer is complete, or when an error has
|
||||
* ocurred. Be sure to check `res.headerSent` if you plan to respond.
|
||||
* ocurred. Be sure to check `res.headersSent` if you plan to respond.
|
||||
*
|
||||
* This method uses `res.sendfile()`.
|
||||
*
|
||||
@@ -557,7 +557,7 @@ res.get = function(field){
|
||||
res.clearCookie = function(name, options){
|
||||
var opts = { expires: new Date(1), path: '/' };
|
||||
return this.cookie(name, '', options
|
||||
? utils.merge(opts, options)
|
||||
? mixin(opts, options)
|
||||
: opts);
|
||||
};
|
||||
|
||||
@@ -585,10 +585,10 @@ res.clearCookie = function(name, options){
|
||||
*/
|
||||
|
||||
res.cookie = function(name, val, options){
|
||||
options = utils.merge({}, options);
|
||||
options = mixin({}, options);
|
||||
var secret = this.req.secret;
|
||||
var signed = options.signed;
|
||||
if (signed && !secret) throw new Error('connect.cookieParser("secret") required for signed cookies');
|
||||
if (signed && !secret) throw new Error('cookieParser("secret") required for signed cookies');
|
||||
if ('number' == typeof val) val = val.toString();
|
||||
if ('object' == typeof val) val = 'j:' + JSON.stringify(val);
|
||||
if (signed) val = 's:' + sign(val, secret);
|
||||
@@ -597,7 +597,18 @@ res.cookie = function(name, val, options){
|
||||
options.maxAge /= 1000;
|
||||
}
|
||||
if (null == options.path) options.path = '/';
|
||||
this.set('Set-Cookie', cookie.serialize(name, String(val), options));
|
||||
var headerVal = cookie.serialize(name, String(val), options);
|
||||
|
||||
// supports multiple 'res.cookie' calls by getting previous value
|
||||
var prev = this.get('Set-Cookie');
|
||||
if (prev) {
|
||||
if (Array.isArray(prev)) {
|
||||
headerVal = prev.concat(headerVal);
|
||||
} else {
|
||||
headerVal = [prev, headerVal];
|
||||
}
|
||||
}
|
||||
this.set('Set-Cookie', headerVal);
|
||||
return this;
|
||||
};
|
||||
|
||||
@@ -612,47 +623,18 @@ res.cookie = function(name, val, options){
|
||||
*
|
||||
* res.location('/foo/bar').;
|
||||
* res.location('http://example.com');
|
||||
* res.location('../login'); // /blog/post/1 -> /blog/login
|
||||
*
|
||||
* Mounting:
|
||||
*
|
||||
* When an application is mounted and `res.location()`
|
||||
* is given a path that does _not_ lead with "/" it becomes
|
||||
* relative to the mount-point. For example if the application
|
||||
* is mounted at "/blog", the following would become "/blog/login".
|
||||
*
|
||||
* res.location('login');
|
||||
*
|
||||
* While the leading slash would result in a location of "/login":
|
||||
*
|
||||
* res.location('/login');
|
||||
* res.location('../login');
|
||||
*
|
||||
* @param {String} url
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.location = function(url){
|
||||
var app = this.app
|
||||
, req = this.req
|
||||
, path;
|
||||
var req = this.req;
|
||||
|
||||
// "back" is an alias for the referrer
|
||||
if ('back' == url) url = req.get('Referrer') || '/';
|
||||
|
||||
// relative
|
||||
if (!~url.indexOf('://') && 0 != url.indexOf('//')) {
|
||||
// relative to path
|
||||
if ('.' == url[0]) {
|
||||
path = req.originalUrl.split('?')[0];
|
||||
path = path + ('/' == path[path.length - 1] ? '' : '/');
|
||||
url = resolve(path, url);
|
||||
// relative to mount-point
|
||||
} else if ('/' != url[0]) {
|
||||
path = app.path();
|
||||
url = path + '/' + url;
|
||||
}
|
||||
}
|
||||
|
||||
// Respond
|
||||
this.set('Location', url);
|
||||
return this;
|
||||
@@ -705,7 +687,7 @@ res.redirect = function(url){
|
||||
},
|
||||
|
||||
html: function(){
|
||||
var u = utils.escape(url);
|
||||
var u = escapeHtml(url);
|
||||
body = '<p>' + statusCodes[status] + '. Redirecting to <a href="' + u + '">' + u + '</a></p>';
|
||||
},
|
||||
|
||||
|
||||
+301
-221
@@ -3,47 +3,74 @@
|
||||
*/
|
||||
|
||||
var Route = require('./route')
|
||||
, Layer = require('./layer')
|
||||
, utils = require('../utils')
|
||||
, methods = require('methods')
|
||||
, debug = require('debug')('express:router')
|
||||
, parse = require('connect').utils.parseUrl;
|
||||
|
||||
/**
|
||||
* Expose `Router` constructor.
|
||||
*/
|
||||
|
||||
exports = module.exports = Router;
|
||||
, parseUrl = utils.parseUrl;
|
||||
|
||||
/**
|
||||
* Initialize a new `Router` with the given `options`.
|
||||
*
|
||||
* @param {Object} options
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function Router(options) {
|
||||
options = options || {};
|
||||
var self = this;
|
||||
this.map = {};
|
||||
this.params = {};
|
||||
this._params = [];
|
||||
this.caseSensitive = options.caseSensitive;
|
||||
this.strict = options.strict;
|
||||
this.middleware = function router(req, res, next){
|
||||
self._dispatch(req, res, next);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a param callback `fn` for the given `name`.
|
||||
*
|
||||
* @param {String|Function} name
|
||||
* @param {Function} fn
|
||||
* @return {Router} for chaining
|
||||
* @return {Router} which is an callable function
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Router.prototype.param = function(name, fn){
|
||||
var proto = module.exports = function(options) {
|
||||
options = options || {};
|
||||
|
||||
function router(req, res, next) {
|
||||
router.handle(req, res, next);
|
||||
};
|
||||
|
||||
// mixin Router class functions
|
||||
router.__proto__ = proto;
|
||||
|
||||
router.params = {};
|
||||
router._params = [];
|
||||
router.caseSensitive = options.caseSensitive;
|
||||
router.strict = options.strict;
|
||||
router.stack = [];
|
||||
|
||||
return router;
|
||||
};
|
||||
|
||||
/**
|
||||
* Map the given param placeholder `name`(s) to the given callback.
|
||||
*
|
||||
* Parameter mapping is used to provide pre-conditions to routes
|
||||
* which use normalized placeholders. For example a _:user_id_ parameter
|
||||
* could automatically load a user's information from the database without
|
||||
* any additional code,
|
||||
*
|
||||
* The callback uses the same signature as middleware, the only difference
|
||||
* being that the value of the placeholder is passed, in this case the _id_
|
||||
* of the user. Once the `next()` function is invoked, just like middleware
|
||||
* it will continue on to execute the route, or subsequent parameter functions.
|
||||
*
|
||||
* Just like in middleware, you must either respond to the request or call next
|
||||
* to avoid stalling the request.
|
||||
*
|
||||
* app.param('user_id', function(req, res, next, id){
|
||||
* User.find(id, function(err, user){
|
||||
* if (err) {
|
||||
* return next(err);
|
||||
* } else if (!user) {
|
||||
* return next(new Error('failed to load user'));
|
||||
* }
|
||||
* req.user = user;
|
||||
* next();
|
||||
* });
|
||||
* });
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {Function} fn
|
||||
* @return {app} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
proto.param = function(name, fn){
|
||||
// param logic
|
||||
if ('function' == typeof name) {
|
||||
this._params.push(name);
|
||||
@@ -55,6 +82,10 @@ Router.prototype.param = function(name, fn){
|
||||
, len = params.length
|
||||
, ret;
|
||||
|
||||
if (name[0] === ':') {
|
||||
name = name.substr(1);
|
||||
}
|
||||
|
||||
for (var i = 0; i < len; ++i) {
|
||||
if (ret = params[i](name, fn)) {
|
||||
fn = ret;
|
||||
@@ -72,249 +103,298 @@ Router.prototype.param = function(name, fn){
|
||||
};
|
||||
|
||||
/**
|
||||
* Route dispatcher aka the route "middleware".
|
||||
* Dispatch a req, res into the router.
|
||||
*
|
||||
* @param {IncomingMessage} req
|
||||
* @param {ServerResponse} res
|
||||
* @param {Function} next
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Router.prototype._dispatch = function(req, res, next){
|
||||
var params = this.params
|
||||
, self = this;
|
||||
proto.handle = function(req, res, done) {
|
||||
var self = this;
|
||||
|
||||
debug('dispatching %s %s (%s)', req.method, req.url, req.originalUrl);
|
||||
debug('dispatching %s %s', req.method, req.url);
|
||||
|
||||
// route dispatch
|
||||
(function pass(i, err){
|
||||
var paramCallbacks
|
||||
, paramIndex = 0
|
||||
, paramVal
|
||||
, route
|
||||
, keys
|
||||
, key;
|
||||
var method = req.method.toLowerCase();
|
||||
|
||||
// match next route
|
||||
function nextRoute(err) {
|
||||
pass(req._route_index + 1, err);
|
||||
}
|
||||
var search = 1 + req.url.indexOf('?');
|
||||
var pathlength = search ? search - 1 : req.url.length;
|
||||
var fqdn = 1 + req.url.substr(0, pathlength).indexOf('://');
|
||||
var protohost = fqdn ? req.url.substr(0, req.url.indexOf('/', 2 + fqdn)) : '';
|
||||
var idx = 0;
|
||||
var removed = '';
|
||||
var slashAdded = false;
|
||||
|
||||
// match route
|
||||
req.route = route = self.matchRequest(req, i);
|
||||
// store options for OPTIONS request
|
||||
// only used if OPTIONS request
|
||||
var options = [];
|
||||
|
||||
// implied OPTIONS
|
||||
if (!route && 'OPTIONS' == req.method) return self._options(req, res);
|
||||
// middleware and routes
|
||||
var stack = self.stack;
|
||||
|
||||
// no route
|
||||
if (!route) return next(err);
|
||||
debug('matched %s %s', route.method, route.path);
|
||||
// for options requests, respond with a default if nothing else responds
|
||||
if (method === 'options') {
|
||||
var old = done;
|
||||
done = function(err) {
|
||||
if (err || options.length === 0) return old(err);
|
||||
|
||||
// we have a route
|
||||
// start at param 0
|
||||
req.params = route.params;
|
||||
keys = route.keys;
|
||||
i = 0;
|
||||
|
||||
// param callbacks
|
||||
function param(err) {
|
||||
paramIndex = 0;
|
||||
key = keys[i++];
|
||||
paramVal = key && req.params[key.name];
|
||||
paramCallbacks = key && params[key.name];
|
||||
|
||||
try {
|
||||
if ('route' == err) {
|
||||
nextRoute();
|
||||
} else if (err) {
|
||||
i = 0;
|
||||
callbacks(err);
|
||||
} else if (paramCallbacks && undefined !== paramVal) {
|
||||
paramCallback();
|
||||
} else if (key) {
|
||||
param();
|
||||
} else {
|
||||
i = 0;
|
||||
callbacks();
|
||||
}
|
||||
} catch (err) {
|
||||
param(err);
|
||||
}
|
||||
var body = options.join(',');
|
||||
return res.set('Allow', body).send(body);
|
||||
};
|
||||
}
|
||||
|
||||
param(err);
|
||||
|
||||
// single param callbacks
|
||||
function paramCallback(err) {
|
||||
var fn = paramCallbacks[paramIndex++];
|
||||
if (err || !fn) return param(err);
|
||||
fn(req, res, paramCallback, paramVal, key.name);
|
||||
(function next(err) {
|
||||
if (err === 'route') {
|
||||
err = undefined;
|
||||
}
|
||||
|
||||
// invoke route callbacks
|
||||
function callbacks(err) {
|
||||
var fn = route.callbacks[i++];
|
||||
try {
|
||||
if ('route' == err) {
|
||||
nextRoute();
|
||||
} else if (err && fn) {
|
||||
if (fn.length < 4) return callbacks(err);
|
||||
fn(err, req, res, callbacks);
|
||||
} else if (fn) {
|
||||
if (fn.length < 4) return fn(req, res, callbacks);
|
||||
callbacks();
|
||||
} else {
|
||||
nextRoute(err);
|
||||
var layer = stack[idx++];
|
||||
if (!layer) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
if (slashAdded) {
|
||||
req.url = req.url.substr(1);
|
||||
slashAdded = false;
|
||||
}
|
||||
|
||||
req.url = protohost + removed + req.url.substr(protohost.length);
|
||||
req.originalUrl = req.originalUrl || req.url;
|
||||
removed = '';
|
||||
|
||||
try {
|
||||
var path = parseUrl(req).pathname;
|
||||
if (undefined == path) path = '/';
|
||||
|
||||
if (!layer.match(path)) return next(err);
|
||||
|
||||
// route object and not middleware
|
||||
var route = layer.route;
|
||||
|
||||
// if final route, then we support options
|
||||
if (route) {
|
||||
// we don't run any routs with error first
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
req.route = route;
|
||||
|
||||
// we can now dispatch to the route
|
||||
if (method === 'options' && !route.methods['options']) {
|
||||
options.push.apply(options, route._options());
|
||||
}
|
||||
} catch (err) {
|
||||
callbacks(err);
|
||||
}
|
||||
|
||||
req.params = layer.params;
|
||||
|
||||
// this should be done for the layer
|
||||
return self.process_params(layer, req, res, function(err) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
if (route) {
|
||||
return layer.handle(req, res, next);
|
||||
}
|
||||
|
||||
trim_prefix();
|
||||
});
|
||||
|
||||
return next(err);
|
||||
|
||||
function trim_prefix() {
|
||||
var c = path[layer.path.length];
|
||||
if (c && '/' != c && '.' != c) return next(err);
|
||||
|
||||
// Trim off the part of the url that matches the route
|
||||
// middleware (.use stuff) needs to have the path stripped
|
||||
debug('trim prefix (%s) from url %s', removed, req.url);
|
||||
removed = layer.path;
|
||||
req.url = protohost + req.url.substr(protohost.length + removed.length);
|
||||
|
||||
// Ensure leading slash
|
||||
if (!fqdn && '/' != req.url[0]) {
|
||||
req.url = '/' + req.url;
|
||||
slashAdded = true;
|
||||
}
|
||||
|
||||
debug('%s %s : %s', layer.handle.name || 'anonymous', layer.path, req.originalUrl);
|
||||
var arity = layer.handle.length;
|
||||
if (err) {
|
||||
if (arity === 4) {
|
||||
layer.handle(err, req, res, next);
|
||||
} else {
|
||||
next(err);
|
||||
}
|
||||
} else if (arity < 4) {
|
||||
layer.handle(req, res, next);
|
||||
} else {
|
||||
next(err);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
})(0);
|
||||
})();
|
||||
};
|
||||
|
||||
/**
|
||||
* Respond to __OPTIONS__ method.
|
||||
* Process any parameters for the route.
|
||||
*
|
||||
* @param {IncomingMessage} req
|
||||
* @param {ServerResponse} res
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Router.prototype._options = function(req, res){
|
||||
var path = parse(req).pathname
|
||||
, body = this._optionsFor(path).join(',');
|
||||
res.set('Allow', body).send(body);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return an array of HTTP verbs or "options" for `path`.
|
||||
*
|
||||
* @param {String} path
|
||||
* @return {Array}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Router.prototype._optionsFor = function(path){
|
||||
proto.process_params = function(route, req, res, done) {
|
||||
var self = this;
|
||||
return methods.filter(function(method){
|
||||
var routes = self.map[method];
|
||||
if (!routes || 'options' == method) return;
|
||||
for (var i = 0, len = routes.length; i < len; ++i) {
|
||||
if (routes[i].match(path)) return true;
|
||||
}
|
||||
}).map(function(method){
|
||||
return method.toUpperCase();
|
||||
});
|
||||
};
|
||||
var params = this.params;
|
||||
|
||||
/**
|
||||
* Attempt to match a route for `req`
|
||||
* with optional starting index of `i`
|
||||
* defaulting to 0.
|
||||
*
|
||||
* @param {IncomingMessage} req
|
||||
* @param {Number} i
|
||||
* @return {Route}
|
||||
* @api private
|
||||
*/
|
||||
// captured parameters from the route, keys and values
|
||||
var keys = route.keys || [];
|
||||
|
||||
Router.prototype.matchRequest = function(req, i, head){
|
||||
var method = req.method.toLowerCase()
|
||||
, url = parse(req)
|
||||
, path = url.pathname
|
||||
, routes = this.map
|
||||
, i = i || 0
|
||||
, route;
|
||||
|
||||
// HEAD support
|
||||
if (!head && 'head' == method) {
|
||||
route = this.matchRequest(req, i, true);
|
||||
if (route) return route;
|
||||
method = 'get';
|
||||
// fast track
|
||||
if (keys.length === 0) {
|
||||
return done();
|
||||
}
|
||||
|
||||
// routes for this method
|
||||
if (routes = routes[method]) {
|
||||
var i = 0;
|
||||
var paramIndex = 0;
|
||||
var key;
|
||||
var paramVal;
|
||||
var paramCallbacks;
|
||||
|
||||
// matching routes
|
||||
for (var len = routes.length; i < len; ++i) {
|
||||
route = routes[i];
|
||||
if (route.match(path)) {
|
||||
req._route_index = i;
|
||||
return route;
|
||||
// process params in order
|
||||
// param callbacks can be async
|
||||
function param(err) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
if (i >= keys.length ) {
|
||||
return done();
|
||||
}
|
||||
|
||||
paramIndex = 0;
|
||||
key = keys[i++];
|
||||
paramVal = key && req.params[key.name];
|
||||
paramCallbacks = key && params[key.name];
|
||||
|
||||
try {
|
||||
if (paramCallbacks && undefined !== paramVal) {
|
||||
return paramCallback();
|
||||
} else if (key) {
|
||||
return param();
|
||||
}
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
|
||||
done();
|
||||
};
|
||||
|
||||
// single param callbacks
|
||||
function paramCallback(err) {
|
||||
var fn = paramCallbacks[paramIndex++];
|
||||
if (err || !fn) return param(err);
|
||||
fn(req, res, paramCallback, paramVal, key.name);
|
||||
}
|
||||
|
||||
param();
|
||||
};
|
||||
|
||||
/**
|
||||
* Attempt to match a route for `method`
|
||||
* and `url` with optional starting
|
||||
* index of `i` defaulting to 0.
|
||||
* Use the given middleware function, with optional path, defaulting to "/".
|
||||
*
|
||||
* @param {String} method
|
||||
* @param {String} url
|
||||
* @param {Number} i
|
||||
* @return {Route}
|
||||
* @api private
|
||||
* Use (like `.all`) will run for any http METHOD, but it will not add
|
||||
* handlers for those methods so OPTIONS requests will not consider `.use`
|
||||
* functions even if they could respond.
|
||||
*
|
||||
* The other difference is that _route_ path is stripped and not visible
|
||||
* to the handler function. The main effect of this feature is that mounted
|
||||
* handlers can operate without any code changes regardless of the "prefix"
|
||||
* pathname.
|
||||
*
|
||||
* @param {String|Function} route
|
||||
* @param {Function} fn
|
||||
* @return {app} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Router.prototype.match = function(method, url, i, head){
|
||||
var req = { method: method, url: url };
|
||||
return this.matchRequest(req, i, head);
|
||||
};
|
||||
proto.use = function(route, fn){
|
||||
|
||||
/**
|
||||
* Route `method`, `path`, and one or more callbacks.
|
||||
*
|
||||
* @param {String} method
|
||||
* @param {String} path
|
||||
* @param {Function} callback...
|
||||
* @return {Router} for chaining
|
||||
* @api private
|
||||
*/
|
||||
// default route to '/'
|
||||
if ('string' != typeof route) {
|
||||
fn = route;
|
||||
route = '/';
|
||||
}
|
||||
|
||||
Router.prototype.route = function(method, path, callbacks){
|
||||
var method = method.toLowerCase()
|
||||
, callbacks = utils.flatten([].slice.call(arguments, 2));
|
||||
// strip trailing slash
|
||||
if ('/' == route[route.length - 1]) {
|
||||
route = route.slice(0, -1);
|
||||
}
|
||||
|
||||
// ensure path was given
|
||||
if (!path) throw new Error('Router#' + method + '() requires a path');
|
||||
|
||||
// ensure all callbacks are functions
|
||||
callbacks.forEach(function(fn){
|
||||
if ('function' == typeof fn) return;
|
||||
var type = {}.toString.call(fn);
|
||||
var msg = '.' + method + '() requires callback functions but got a ' + type;
|
||||
throw new Error(msg);
|
||||
});
|
||||
|
||||
// create the route
|
||||
debug('defined %s %s', method, path);
|
||||
var route = new Route(method, path, callbacks, {
|
||||
var layer = Layer(route, {
|
||||
sensitive: this.caseSensitive,
|
||||
strict: this.strict
|
||||
});
|
||||
strict: this.strict,
|
||||
end: false
|
||||
}, fn);
|
||||
|
||||
// add it
|
||||
(this.map[method] = this.map[method] || []).push(route);
|
||||
// add the middleware
|
||||
debug('use %s %s', route || '/', fn.name || 'anonymous');
|
||||
|
||||
this.stack.push(layer);
|
||||
return this;
|
||||
};
|
||||
|
||||
Router.prototype.all = function(path) {
|
||||
var self = this;
|
||||
var args = [].slice.call(arguments);
|
||||
/**
|
||||
* Create a new Route for the given path.
|
||||
*
|
||||
* Each route contains a separate middleware stack and VERB handlers.
|
||||
*
|
||||
* See the Route api documentation for details on adding handlers
|
||||
* and middleware to routes.
|
||||
*
|
||||
* @param {String} path
|
||||
* @return {Route}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
proto.route = function(path){
|
||||
var route = new Route(path);
|
||||
|
||||
var layer = Layer(path, {
|
||||
sensitive: this.caseSensitive,
|
||||
strict: this.strict,
|
||||
end: true
|
||||
}, route.dispatch.bind(route));
|
||||
|
||||
layer.route = route;
|
||||
|
||||
this.stack.push(layer);
|
||||
return route;
|
||||
};
|
||||
|
||||
/**
|
||||
* Special-cased "all" method, applying the given route `path`,
|
||||
* middleware, and callback to _every_ HTTP method.
|
||||
*
|
||||
* @param {String} path
|
||||
* @param {Function} ...
|
||||
* @return {app} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
proto.all = function(path, fn) {
|
||||
var route = this.route(path);
|
||||
methods.forEach(function(method){
|
||||
self.route.apply(self, [method].concat(args));
|
||||
route[method](fn);
|
||||
});
|
||||
return this;
|
||||
};
|
||||
|
||||
// create Router#VERB functions
|
||||
methods.forEach(function(method){
|
||||
Router.prototype[method] = function(path){
|
||||
var args = [method].concat([].slice.call(arguments));
|
||||
this.route.apply(this, args);
|
||||
return this;
|
||||
proto[method] = function(path, fn){
|
||||
var self = this;
|
||||
self.route(path)[method](fn);
|
||||
return self;
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
var utils = require('../utils')
|
||||
, debug = require('debug')('express:router:layer')
|
||||
|
||||
function Layer(path, options, fn) {
|
||||
if (!(this instanceof Layer)) {
|
||||
return new Layer(path, options, fn);
|
||||
}
|
||||
|
||||
debug('new %s', path);
|
||||
options = options || {};
|
||||
this.path = path;
|
||||
this.params = {};
|
||||
this.regexp = utils.pathRegexp(path
|
||||
, this.keys = []
|
||||
, options.sensitive
|
||||
, options.strict
|
||||
, options.end);
|
||||
this.handle = fn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this route matches `path`, if so
|
||||
* populate `.params`.
|
||||
*
|
||||
* @param {String} path
|
||||
* @return {Boolean}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Layer.prototype.match = function(path){
|
||||
var keys = this.keys
|
||||
, params = this.params = {}
|
||||
, m = this.regexp.exec(path)
|
||||
, n = 0;
|
||||
|
||||
if (!m) return false;
|
||||
|
||||
for (var i = 1, len = m.length; i < len; ++i) {
|
||||
var key = keys[i - 1];
|
||||
|
||||
try {
|
||||
var val = 'string' == typeof m[i]
|
||||
? decodeURIComponent(m[i])
|
||||
: m[i];
|
||||
} catch(e) {
|
||||
var err = new Error("Failed to decode param '" + m[i] + "'");
|
||||
err.status = 400;
|
||||
throw err;
|
||||
}
|
||||
|
||||
if (key) {
|
||||
params[key.name] = val;
|
||||
} else {
|
||||
params[n++] = val;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
module.exports = Layer;
|
||||
+133
-41
@@ -3,7 +3,8 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var utils = require('../utils');
|
||||
var debug = require('debug')('express:router:route')
|
||||
, methods = require('methods')
|
||||
|
||||
/**
|
||||
* Expose `Route`.
|
||||
@@ -12,61 +13,152 @@ var utils = require('../utils');
|
||||
module.exports = Route;
|
||||
|
||||
/**
|
||||
* Initialize `Route` with the given HTTP `method`, `path`,
|
||||
* and an array of `callbacks` and `options`.
|
||||
* Initialize `Route` with the given `path`,
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - `sensitive` enable case-sensitive routes
|
||||
* - `strict` enable strict matching for trailing slashes
|
||||
*
|
||||
* @param {String} method
|
||||
* @param {String} path
|
||||
* @param {Array} callbacks
|
||||
* @param {Object} options.
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function Route(method, path, callbacks, options) {
|
||||
options = options || {};
|
||||
function Route(path) {
|
||||
debug('new %s', path);
|
||||
this.path = path;
|
||||
this.method = method;
|
||||
this.callbacks = callbacks;
|
||||
this.regexp = utils.pathRegexp(path
|
||||
, this.keys = []
|
||||
, options.sensitive
|
||||
, options.strict);
|
||||
this.stack = undefined;
|
||||
|
||||
// route handlers for various http methods
|
||||
this.methods = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this route matches `path`, if so
|
||||
* populate `.params`.
|
||||
*
|
||||
* @param {String} path
|
||||
* @return {Boolean}
|
||||
* @return {Array} supported HTTP methods
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Route.prototype.match = function(path){
|
||||
var keys = this.keys
|
||||
, params = this.params = []
|
||||
, m = this.regexp.exec(path);
|
||||
Route.prototype._options = function(){
|
||||
return Object.keys(this.methods).map(function(method) {
|
||||
return method.toUpperCase();
|
||||
});
|
||||
};
|
||||
|
||||
if (!m) return false;
|
||||
/**
|
||||
* dispatch req, res into this route
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
for (var i = 1, len = m.length; i < len; ++i) {
|
||||
var key = keys[i - 1];
|
||||
Route.prototype.dispatch = function(req, res, done){
|
||||
var self = this;
|
||||
var method = req.method.toLowerCase();
|
||||
|
||||
var val = 'string' == typeof m[i]
|
||||
? utils.decode(m[i])
|
||||
: m[i];
|
||||
|
||||
if (key) {
|
||||
params[key.name] = val;
|
||||
} else {
|
||||
params.push(val);
|
||||
}
|
||||
if (method === 'head' && !this.methods['head']) {
|
||||
method = 'get';
|
||||
}
|
||||
|
||||
return true;
|
||||
req.route = self;
|
||||
|
||||
// single middleware route case
|
||||
if (typeof this.stack === 'function') {
|
||||
this.stack(req, res, done);
|
||||
return;
|
||||
}
|
||||
|
||||
var stack = self.stack;
|
||||
if (!stack) {
|
||||
return done();
|
||||
}
|
||||
|
||||
var idx = 0;
|
||||
(function next_layer(err) {
|
||||
if (err && err === 'route') {
|
||||
return done();
|
||||
}
|
||||
|
||||
var layer = stack[idx++];
|
||||
if (!layer) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
if (layer.method && layer.method !== method) {
|
||||
return next_layer(err);
|
||||
}
|
||||
|
||||
var arity = layer.handle.length;
|
||||
if (err) {
|
||||
if (arity < 4) {
|
||||
return next_layer(err);
|
||||
}
|
||||
|
||||
return layer.handle(err, req, res, next_layer);
|
||||
}
|
||||
|
||||
if (arity > 3) {
|
||||
return next_layer();
|
||||
}
|
||||
|
||||
layer.handle(req, res, next_layer);
|
||||
})();
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a handler for all HTTP verbs to this route.
|
||||
*
|
||||
* Behaves just like middleware and can respond or call `next`
|
||||
* to continue processing.
|
||||
*
|
||||
* You can use multiple `.all` call to add multiple handlers.
|
||||
*
|
||||
* function check_something(req, res, next){
|
||||
* next();
|
||||
* };
|
||||
*
|
||||
* function validate_user(req, res, next){
|
||||
* next();
|
||||
* };
|
||||
*
|
||||
* route
|
||||
* .all(validate_user)
|
||||
* .all(check_something)
|
||||
* .get(function(req, res, next){
|
||||
* res.send('hello world');
|
||||
* });
|
||||
*
|
||||
* @param {function} handler
|
||||
* @return {Route} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Route.prototype.all = function(fn){
|
||||
if (typeof fn !== 'function') {
|
||||
var type = {}.toString.call(fn);
|
||||
var msg = 'Route.use() requires callback functions but got a ' + type;
|
||||
throw new Error(msg);
|
||||
}
|
||||
|
||||
if (!this.stack) {
|
||||
this.stack = fn;
|
||||
}
|
||||
else if (typeof this.stack === 'function') {
|
||||
this.stack = [{ handle: this.stack }, { handle: fn }];
|
||||
}
|
||||
else {
|
||||
this.stack.push({ handle: fn });
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
methods.forEach(function(method){
|
||||
Route.prototype[method] = function(fn){
|
||||
debug('%s %s', method, this.path);
|
||||
|
||||
if (!this.methods[method]) {
|
||||
this.methods[method] = true;
|
||||
}
|
||||
|
||||
if (!this.stack) {
|
||||
this.stack = [];
|
||||
}
|
||||
|
||||
this.stack.push({ method: method, handle: fn })
|
||||
return this;
|
||||
};
|
||||
});
|
||||
|
||||
+23
-172
@@ -3,8 +3,9 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var mime = require('connect').mime
|
||||
, crc32 = require('buffer-crc32');
|
||||
var mime = require('send').mime;
|
||||
var crc32 = require('buffer-crc32');
|
||||
var parse = require('url').parse;
|
||||
|
||||
/**
|
||||
* toString ref.
|
||||
@@ -24,25 +25,6 @@ exports.etag = function(body){
|
||||
return '"' + crc32.signed(body) + '"';
|
||||
};
|
||||
|
||||
/**
|
||||
* Make `locals()` bound to the given `obj`.
|
||||
*
|
||||
* This is used for `app.locals` and `res.locals`.
|
||||
*
|
||||
* @param {Object} obj
|
||||
* @return {Function}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.locals = function(){
|
||||
function locals(obj){
|
||||
for (var key in obj) locals[key] = obj[key];
|
||||
return obj;
|
||||
};
|
||||
|
||||
return locals;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if `path` looks absolute.
|
||||
*
|
||||
@@ -110,127 +92,6 @@ exports.normalizeTypes = function(types){
|
||||
return ret;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the acceptable type in `types`, if any.
|
||||
*
|
||||
* @param {Array} types
|
||||
* @param {String} str
|
||||
* @return {String}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.acceptsArray = function(types, str){
|
||||
// accept anything when Accept is not present
|
||||
if (!str) return types[0];
|
||||
|
||||
// parse
|
||||
var accepted = exports.parseAccept(str)
|
||||
, normalized = exports.normalizeTypes(types)
|
||||
, len = accepted.length;
|
||||
|
||||
for (var i = 0; i < len; ++i) {
|
||||
for (var j = 0, jlen = types.length; j < jlen; ++j) {
|
||||
if (exports.accept(normalized[j], accepted[i])) {
|
||||
return types[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if `type(s)` are acceptable based on
|
||||
* the given `str`.
|
||||
*
|
||||
* @param {String|Array} type(s)
|
||||
* @param {String} str
|
||||
* @return {Boolean|String}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.accepts = function(type, str){
|
||||
if ('string' == typeof type) type = type.split(/ *, */);
|
||||
return exports.acceptsArray(type, str);
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if `type` array is acceptable for `other`.
|
||||
*
|
||||
* @param {Object} type
|
||||
* @param {Object} other
|
||||
* @return {Boolean}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.accept = function(type, other){
|
||||
var t = type.value.split('/');
|
||||
return (t[0] == other.type || '*' == other.type)
|
||||
&& (t[1] == other.subtype || '*' == other.subtype)
|
||||
&& paramsEqual(type.params, other.params);
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if accept params are equal.
|
||||
*
|
||||
* @param {Object} a
|
||||
* @param {Object} b
|
||||
* @return {Boolean}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function paramsEqual(a, b){
|
||||
return !Object.keys(a).some(function(k) {
|
||||
return a[k] != b[k];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse accept `str`, returning
|
||||
* an array objects containing
|
||||
* `.type` and `.subtype` along
|
||||
* with the values provided by
|
||||
* `parseQuality()`.
|
||||
*
|
||||
* @param {Type} name
|
||||
* @return {Type}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.parseAccept = function(str){
|
||||
return exports
|
||||
.parseParams(str)
|
||||
.map(function(obj){
|
||||
var parts = obj.value.split('/');
|
||||
obj.type = parts[0];
|
||||
obj.subtype = parts[1];
|
||||
return obj;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse quality `str`, returning an
|
||||
* array of objects with `.value`,
|
||||
* `.quality` and optional `.params`
|
||||
*
|
||||
* @param {String} str
|
||||
* @return {Array}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.parseParams = function(str){
|
||||
return str
|
||||
.split(/ *, */)
|
||||
.map(acceptParams)
|
||||
.filter(function(obj){
|
||||
return obj.quality;
|
||||
})
|
||||
.sort(function(a, b){
|
||||
if (a.quality === b.quality) {
|
||||
return a.originalIndex - b.originalIndex;
|
||||
} else {
|
||||
return b.quality - a.quality;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse accept params `str` returning an
|
||||
@@ -258,22 +119,6 @@ function acceptParams(str, index) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape special characters in the given string of html.
|
||||
*
|
||||
* @param {String} html
|
||||
* @return {String}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.escape = function(html) {
|
||||
return String(html)
|
||||
.replace(/&/g, '&')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>');
|
||||
};
|
||||
|
||||
/**
|
||||
* Normalize the given path string,
|
||||
* returning a regular expression.
|
||||
@@ -287,11 +132,12 @@ exports.escape = function(html) {
|
||||
* @param {Array} keys
|
||||
* @param {Boolean} sensitive
|
||||
* @param {Boolean} strict
|
||||
* @param {Boolean} end (whether to append $ to regex)
|
||||
* @return {RegExp}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.pathRegexp = function(path, keys, sensitive, strict) {
|
||||
exports.pathRegexp = function(path, keys, sensitive, strict, end) {
|
||||
if (toString.call(path) == '[object RegExp]') return path;
|
||||
if (Array.isArray(path)) path = '(' + path.join('|') + ')';
|
||||
path = path
|
||||
@@ -310,24 +156,29 @@ exports.pathRegexp = function(path, keys, sensitive, strict) {
|
||||
})
|
||||
.replace(/([\/.])/g, '\\$1')
|
||||
.replace(/\*/g, '(.*)');
|
||||
return new RegExp('^' + path + '$', sensitive ? '' : 'i');
|
||||
return new RegExp('^' + path + ((end) ? '$' : ''), sensitive ? '' : 'i');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Decodes a URI component. Returns
|
||||
* the original string if the component
|
||||
* is malformed.
|
||||
* Parse the `req` url with memoization.
|
||||
*
|
||||
* @param {String} str
|
||||
* @return {String}
|
||||
* @param {ServerRequest} req
|
||||
* @return {Object}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.decode = function(str) {
|
||||
try {
|
||||
return decodeURIComponent(str);
|
||||
} catch (e) {
|
||||
return str;
|
||||
exports.parseUrl = function(req){
|
||||
var parsed = req._parsedUrl;
|
||||
if (parsed && parsed.href == req.url) {
|
||||
return parsed;
|
||||
} else {
|
||||
parsed = parse(req.url);
|
||||
|
||||
if (parsed.auth && !parsed.protocol && ~parsed.href.indexOf('//')) {
|
||||
// This parses pathnames, and a strange pathname like //r@e should work
|
||||
parsed = parse(req.url.replace(/@/g, '%40'));
|
||||
}
|
||||
|
||||
return req._parsedUrl = parsed;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
+21
-16
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "express",
|
||||
"description": "Sinatra inspired web development framework",
|
||||
"version": "3.4.6",
|
||||
"version": "3.4.7",
|
||||
"author": "TJ Holowaychuk <tj@vision-media.ca>",
|
||||
"contributors": [
|
||||
{
|
||||
@@ -22,28 +22,36 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"connect": "2.11.2",
|
||||
"commander": "1.3.2",
|
||||
"range-parser": "0.0.4",
|
||||
"mkdirp": "0.3.5",
|
||||
"accepts": "1.0.0",
|
||||
"type-is": "1.0.0",
|
||||
"range-parser": "1.0.0",
|
||||
"cookie": "0.1.0",
|
||||
"buffer-crc32": "0.2.1",
|
||||
"fresh": "0.2.0",
|
||||
"fresh": "0.2.2",
|
||||
"methods": "0.1.0",
|
||||
"send": "0.1.4",
|
||||
"cookie-signature": "1.0.1",
|
||||
"send": "0.2.0",
|
||||
"cookie-signature": "1.0.3",
|
||||
"merge-descriptors": "0.0.2",
|
||||
"utils-merge": "1.0.0",
|
||||
"escape-html": "1.0.1",
|
||||
"qs": "0.6.6",
|
||||
"debug": ">= 0.7.3 < 1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"ejs": "~0.8.4",
|
||||
"mocha": "~1.14.0",
|
||||
"mocha": "~1.15.1",
|
||||
"jade": "~0.30.0",
|
||||
"hjs": "~0.0.6",
|
||||
"stylus": "~0.40.0",
|
||||
"should": "~2.0.2",
|
||||
"should": "~2.1.1",
|
||||
"connect-redis": "~1.4.5",
|
||||
"marked": "0.2.10",
|
||||
"supertest": "~0.8.1"
|
||||
"supertest": "~0.8.1",
|
||||
"body-parser": "1.0.0",
|
||||
"cookie-parser": "1.0.1",
|
||||
"static-favicon": "1.0.0",
|
||||
"express-session": "1.0.1",
|
||||
"morgan": "1.0.0"
|
||||
},
|
||||
"keywords": [
|
||||
"express",
|
||||
@@ -57,15 +65,12 @@
|
||||
"api"
|
||||
],
|
||||
"repository": "git://github.com/visionmedia/express",
|
||||
"main": "index",
|
||||
"bin": {
|
||||
"express": "./bin/express"
|
||||
},
|
||||
"scripts": {
|
||||
"prepublish": "npm prune",
|
||||
"test": "make test"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"license": "MIT"
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ var app = express()
|
||||
, blog = express()
|
||||
, admin = express();
|
||||
|
||||
// app.use(express.logger('dev'))
|
||||
blog.use('/admin', admin);
|
||||
app.use('/blog', blog);
|
||||
app.set('views', __dirname + '/views');
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
NODE_ENV=production node ./support/app &
|
||||
pid=$!
|
||||
|
||||
bench() {
|
||||
ab -n 5000 -c 50 -k -q http://127.0.0.1:8000$1 \
|
||||
| grep "Requests per" \
|
||||
| cut -d ' ' -f 7 \
|
||||
| xargs echo "$2:"
|
||||
}
|
||||
|
||||
bench_conditional() {
|
||||
ab -n 5000 -c 50 -H "If-None-Match: $3" -k -q http://127.0.0.1:8000$1 \
|
||||
| grep "Requests per" \
|
||||
| cut -d ' ' -f 7 \
|
||||
| xargs echo "$2:"
|
||||
}
|
||||
|
||||
sleep .5
|
||||
bench / "Hello World"
|
||||
bench /blog "Mounted Hello World"
|
||||
bench /blog/admin "Mounted 2 Hello World"
|
||||
bench /middleware "Middleware"
|
||||
bench /match "Router"
|
||||
bench /render "Render"
|
||||
bench /json "JSON tiny"
|
||||
bench /json/15 "JSON small"
|
||||
bench /json/50 "JSON medium"
|
||||
bench /json/150 "JSON large"
|
||||
|
||||
kill -9 $pid
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
|
||||
var express = require('../')
|
||||
, Route = express.Route
|
||||
, methods = require('methods')
|
||||
, assert = require('assert');
|
||||
|
||||
describe('Route', function(){
|
||||
|
||||
describe('.all', function(){
|
||||
it('should add handler', function(done){
|
||||
var route = new Route('/foo');
|
||||
|
||||
route.all(function(req, res, next) {
|
||||
assert.equal(req.a, 1);
|
||||
assert.equal(res.b, 2);
|
||||
next();
|
||||
});
|
||||
|
||||
route.dispatch({ a:1, method: 'GET' }, { b:2 }, done);
|
||||
})
|
||||
|
||||
it('should handle VERBS', function(done) {
|
||||
var route = new Route('/foo');
|
||||
|
||||
var count = 0;
|
||||
route.all(function(req, res, next) {
|
||||
count++;
|
||||
});
|
||||
|
||||
methods.forEach(function testMethod(method) {
|
||||
route.dispatch({ method: method }, {});
|
||||
});
|
||||
|
||||
assert.equal(count, methods.length);
|
||||
done();
|
||||
})
|
||||
|
||||
it('should stack', function(done) {
|
||||
var route = new Route('/foo');
|
||||
|
||||
var count = 0;
|
||||
route.all(function(req, res, next) {
|
||||
count++;
|
||||
next();
|
||||
});
|
||||
|
||||
route.all(function(req, res, next) {
|
||||
count++;
|
||||
next();
|
||||
});
|
||||
|
||||
route.dispatch({ method: 'GET' }, {}, function(err) {
|
||||
assert.ifError(err);
|
||||
count++;
|
||||
});
|
||||
|
||||
assert.equal(count, 3);
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
describe('.VERB', function(){
|
||||
it('should support .get', function(done){
|
||||
var route = new Route('');
|
||||
|
||||
var count = 0;
|
||||
route.get(function(req, res, next) {
|
||||
count++;
|
||||
})
|
||||
|
||||
route.dispatch({ method: 'GET' }, {});
|
||||
assert(count);
|
||||
done();
|
||||
})
|
||||
|
||||
it('should limit to just .VERB', function(done){
|
||||
var route = new Route('');
|
||||
|
||||
route.get(function(req, res, next) {
|
||||
assert(false);
|
||||
done();
|
||||
})
|
||||
|
||||
route.post(function(req, res, next) {
|
||||
assert(true);
|
||||
})
|
||||
|
||||
route.dispatch({ method: 'post' }, {});
|
||||
done();
|
||||
})
|
||||
|
||||
it('should allow fallthrough', function(done){
|
||||
var route = new Route('');
|
||||
|
||||
var order = '';
|
||||
route.get(function(req, res, next) {
|
||||
order += 'a';
|
||||
next();
|
||||
})
|
||||
|
||||
route.all(function(req, res, next) {
|
||||
order += 'b';
|
||||
next();
|
||||
});
|
||||
|
||||
route.get(function(req, res, next) {
|
||||
order += 'c';
|
||||
})
|
||||
|
||||
route.dispatch({ method: 'get' }, {});
|
||||
assert.equal(order, 'abc');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
describe('errors', function(){
|
||||
it('should handle errors via arity 4 functions', function(done){
|
||||
var route = new Route('');
|
||||
|
||||
var order = '';
|
||||
route.all(function(req, res, next){
|
||||
next(new Error('foobar'));
|
||||
});
|
||||
|
||||
route.all(function(req, res, next){
|
||||
order += '0';
|
||||
next();
|
||||
});
|
||||
|
||||
route.all(function(err, req, res, next){
|
||||
order += 'a';
|
||||
next(err);
|
||||
});
|
||||
|
||||
route.all(function(err, req, res, next){
|
||||
assert.equal(err.message, 'foobar');
|
||||
assert.equal(order, 'a');
|
||||
done();
|
||||
});
|
||||
|
||||
route.dispatch({ method: 'get' }, {});
|
||||
})
|
||||
})
|
||||
})
|
||||
+105
-70
@@ -1,121 +1,156 @@
|
||||
|
||||
var express = require('../')
|
||||
, Router = express.Router
|
||||
, request = require('./support/http')
|
||||
, methods = require('methods')
|
||||
, assert = require('assert');
|
||||
|
||||
describe('Router', function(){
|
||||
var router, app;
|
||||
|
||||
beforeEach(function(){
|
||||
router = new Router;
|
||||
app = express();
|
||||
})
|
||||
it('should return a function with router methods', function() {
|
||||
var router = Router();
|
||||
assert(typeof router == 'function');
|
||||
|
||||
describe('.match(method, url, i)', function(){
|
||||
it('should match based on index', function(){
|
||||
router.route('get', '/foo', function(){});
|
||||
router.route('get', '/foob?', function(){});
|
||||
router.route('get', '/bar', function(){});
|
||||
var router = new Router();
|
||||
assert(typeof router == 'function');
|
||||
|
||||
var method = 'GET';
|
||||
var url = '/foo?bar=baz';
|
||||
assert(typeof router.get == 'function');
|
||||
assert(typeof router.handle == 'function');
|
||||
assert(typeof router.use == 'function');
|
||||
});
|
||||
|
||||
var route = router.match(method, url, 0);
|
||||
route.constructor.name.should.equal('Route');
|
||||
route.method.should.equal('get');
|
||||
route.path.should.equal('/foo');
|
||||
it('should support .use of other routers', function(done) {
|
||||
var router = Router();
|
||||
var another = Router();
|
||||
|
||||
var route = router.match(method, url, 1);
|
||||
route.path.should.equal('/foob?');
|
||||
another.get('/bar', function(req, res) {
|
||||
res.done();
|
||||
});
|
||||
router.use('/foo', another);
|
||||
|
||||
var route = router.match(method, url, 2);
|
||||
assert(!route);
|
||||
router.handle({ url: '/foo/bar', method: 'GET' }, { done: done });
|
||||
});
|
||||
|
||||
url = '/bar';
|
||||
var route = router.match(method, url);
|
||||
route.path.should.equal('/bar');
|
||||
})
|
||||
})
|
||||
|
||||
describe('.matchRequest(req, i)', function(){
|
||||
it('should match based on index', function(){
|
||||
router.route('get', '/foo', function(){});
|
||||
router.route('get', '/foob?', function(){});
|
||||
router.route('get', '/bar', function(){});
|
||||
var req = { method: 'GET', url: '/foo?bar=baz' };
|
||||
|
||||
var route = router.matchRequest(req, 0);
|
||||
route.constructor.name.should.equal('Route');
|
||||
route.method.should.equal('get');
|
||||
route.path.should.equal('/foo');
|
||||
|
||||
var route = router.matchRequest(req, 1);
|
||||
req._route_index.should.equal(1);
|
||||
route.path.should.equal('/foob?');
|
||||
|
||||
var route = router.matchRequest(req, 2);
|
||||
assert(!route);
|
||||
|
||||
req.url = '/bar';
|
||||
var route = router.matchRequest(req);
|
||||
route.path.should.equal('/bar');
|
||||
})
|
||||
})
|
||||
|
||||
describe('.middleware', function(){
|
||||
describe('.handle', function(){
|
||||
it('should dispatch', function(done){
|
||||
router.route('get', '/foo', function(req, res){
|
||||
var router = new Router();
|
||||
|
||||
router.route('/foo').get(function(req, res){
|
||||
res.send('foo');
|
||||
});
|
||||
|
||||
app.use(router.middleware);
|
||||
|
||||
request(app)
|
||||
.get('/foo')
|
||||
.expect('foo', done);
|
||||
var res = {
|
||||
send: function(val) {
|
||||
val.should.equal('foo');
|
||||
done();
|
||||
}
|
||||
}
|
||||
router.handle({ url: '/foo', method: 'GET' }, res);
|
||||
})
|
||||
})
|
||||
|
||||
describe('.multiple callbacks', function(){
|
||||
it('should throw if a callback is null', function(){
|
||||
assert.throws(function () {
|
||||
router.route('get', '/foo', null, function(){});
|
||||
var router = new Router();
|
||||
router.route('/foo').all(null);
|
||||
})
|
||||
})
|
||||
|
||||
it('should throw if a callback is undefined', function(){
|
||||
assert.throws(function () {
|
||||
router.route('get', '/foo', undefined, function(){});
|
||||
var router = new Router();
|
||||
router.route('/foo').all(undefined);
|
||||
})
|
||||
})
|
||||
|
||||
it('should throw if a callback is not a function', function(){
|
||||
assert.throws(function () {
|
||||
router.route('get', '/foo', 'not a function', function(){});
|
||||
var router = new Router();
|
||||
router.route('/foo').all('not a function');
|
||||
})
|
||||
})
|
||||
|
||||
it('should not throw if all callbacks are functions', function(){
|
||||
router.route('get', '/foo', function(){}, function(){});
|
||||
var router = new Router();
|
||||
router.route('/foo').all(function(){}).all(function(){});
|
||||
})
|
||||
})
|
||||
|
||||
describe('.all', function() {
|
||||
it('should support using .all to capture all http verbs', function() {
|
||||
describe('error', function(){
|
||||
it('should skip non error middleware', function(done){
|
||||
var router = new Router();
|
||||
|
||||
router.all('/foo', function(){});
|
||||
router.get('/foo', function(req, res, next){
|
||||
next(new Error('foo'));
|
||||
});
|
||||
|
||||
router.get('/bar', function(req, res, next){
|
||||
next(new Error('bar'));
|
||||
});
|
||||
|
||||
router.use(function(req, res, next){
|
||||
assert(false);
|
||||
});
|
||||
|
||||
router.use(function(err, req, res, next){
|
||||
assert.equal(err.message, 'foo');
|
||||
done();
|
||||
});
|
||||
|
||||
router.handle({ url: '/foo', method: 'GET' }, {}, done);
|
||||
});
|
||||
})
|
||||
|
||||
describe('.all', function() {
|
||||
it('should support using .all to capture all http verbs', function(done){
|
||||
var router = new Router();
|
||||
|
||||
var count = 0;
|
||||
router.all('/foo', function(){ count++; });
|
||||
|
||||
var url = '/foo?bar=baz';
|
||||
|
||||
methods.forEach(function testMethod(method) {
|
||||
var route = router.match(method, url);
|
||||
route.constructor.name.should.equal('Route');
|
||||
route.method.should.equal(method);
|
||||
route.path.should.equal('/foo');
|
||||
router.handle({ url: url, method: method }, {}, function() {});
|
||||
});
|
||||
|
||||
assert.equal(count, methods.length);
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
describe('.param', function() {
|
||||
it('should call param function when routing VERBS', function(done) {
|
||||
var router = new Router();
|
||||
|
||||
router.param('id', function(req, res, next, id) {
|
||||
assert.equal(id, '123');
|
||||
next();
|
||||
});
|
||||
|
||||
router.get('/foo/:id/bar', function(req, res, next) {
|
||||
assert.equal(req.params.id, '123');
|
||||
next();
|
||||
});
|
||||
|
||||
router.handle({ url: '/foo/123/bar', method: 'get' }, {}, done);
|
||||
});
|
||||
|
||||
it('should call param function when routing middleware', function(done) {
|
||||
var router = new Router();
|
||||
|
||||
router.param('id', function(req, res, next, id) {
|
||||
assert.equal(id, '123');
|
||||
next();
|
||||
});
|
||||
|
||||
router.use('/foo/:id/bar', function(req, res, next) {
|
||||
assert.equal(req.params.id, '123');
|
||||
assert.equal(req.url, '/baz');
|
||||
next();
|
||||
});
|
||||
|
||||
router.handle({ url: '/foo/123/bar/baz', method: 'get' }, {}, done);
|
||||
});
|
||||
});
|
||||
})
|
||||
|
||||
@@ -18,7 +18,7 @@ describe('auth', function(){
|
||||
it('should redirect to /login', function(done){
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(redirects(/\/login$/, done))
|
||||
.end(redirects(/login$/, done))
|
||||
})
|
||||
})
|
||||
|
||||
@@ -26,7 +26,7 @@ describe('auth', function(){
|
||||
it('should redirect to /login', function(done){
|
||||
request(app)
|
||||
.get('/restricted')
|
||||
.end(redirects(/\/login$/,done))
|
||||
.end(redirects(/login$/,done))
|
||||
})
|
||||
})
|
||||
|
||||
@@ -36,7 +36,7 @@ describe('auth', function(){
|
||||
.post('/login')
|
||||
.type('urlencoded')
|
||||
.send('username=not-tj&password=foobar')
|
||||
.end(redirects(/\/login$/, done))
|
||||
.end(redirects(/login$/, done))
|
||||
})
|
||||
})
|
||||
})
|
||||
+17
-5
@@ -25,7 +25,7 @@ describe('app.parent', function(){
|
||||
})
|
||||
})
|
||||
|
||||
describe('app.route', function(){
|
||||
describe('app.mountpath', function(){
|
||||
it('should return the mounted path', function(){
|
||||
var app = express()
|
||||
, blog = express()
|
||||
@@ -34,9 +34,21 @@ describe('app.route', function(){
|
||||
app.use('/blog', blog);
|
||||
blog.use('/admin', blogAdmin);
|
||||
|
||||
app.route.should.equal('/');
|
||||
blog.route.should.equal('/blog');
|
||||
blogAdmin.route.should.equal('/admin');
|
||||
app.mountpath.should.equal('/');
|
||||
blog.mountpath.should.equal('/blog');
|
||||
blogAdmin.mountpath.should.equal('/admin');
|
||||
})
|
||||
})
|
||||
|
||||
describe('app.router', function(){
|
||||
it('should throw with notice', function(done){
|
||||
var app = express()
|
||||
|
||||
try {
|
||||
app.router;
|
||||
} catch(err) {
|
||||
done();
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@@ -71,4 +83,4 @@ describe('in production', function(){
|
||||
app.enabled('view cache').should.be.true;
|
||||
process.env.NODE_ENV = 'test';
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -7,8 +7,8 @@ describe('app', function(){
|
||||
it('should merge locals', function(){
|
||||
var app = express();
|
||||
Object.keys(app.locals).should.eql(['settings']);
|
||||
app.locals({ user: 'tobi', age: 1 });
|
||||
app.locals({ age: 2 });
|
||||
app.locals.user = 'tobi';
|
||||
app.locals.age = 2;
|
||||
Object.keys(app.locals).should.eql(['settings', 'user', 'age']);
|
||||
app.locals.user.should.equal('tobi');
|
||||
app.locals.age.should.equal(2);
|
||||
|
||||
+25
-1
@@ -15,6 +15,30 @@ describe('OPTIONS', function(){
|
||||
.expect('GET,PUT')
|
||||
.expect('Allow', 'GET,PUT', done);
|
||||
})
|
||||
|
||||
it('should not respond if the path is not defined', function(done){
|
||||
var app = express();
|
||||
|
||||
app.get('/users', function(req, res){});
|
||||
|
||||
request(app)
|
||||
.options('/other')
|
||||
.expect(404, done);
|
||||
})
|
||||
|
||||
it('should forward requests down the middleware chain', function(done){
|
||||
var app = express();
|
||||
var router = new express.Router();
|
||||
|
||||
router.get('/users', function(req, res){});
|
||||
app.use(router);
|
||||
app.get('/other', function(req, res){});
|
||||
|
||||
request(app)
|
||||
.options('/other')
|
||||
.expect('GET')
|
||||
.expect('Allow', 'GET', done);
|
||||
})
|
||||
})
|
||||
|
||||
describe('app.options()', function(){
|
||||
@@ -34,4 +58,4 @@ describe('app.options()', function(){
|
||||
.expect('GET')
|
||||
.expect('Allow', 'GET', done);
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -59,7 +59,7 @@ describe('app', function(){
|
||||
var app = express();
|
||||
app.set('views', __dirname + '/fixtures');
|
||||
app.render('rawr.jade', function(err){
|
||||
err.message.should.equal('Failed to lookup view "rawr.jade"');
|
||||
err.message.should.equal('Failed to lookup view "rawr.jade" in views directory "' + __dirname + '/fixtures"');
|
||||
done();
|
||||
});
|
||||
})
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
var express = require('../')
|
||||
, request = require('./support/http')
|
||||
|
||||
describe('app.route', function(){
|
||||
it('should return a new route', function(done){
|
||||
var app = express();
|
||||
|
||||
app.route('/foo')
|
||||
.get(function(req, res) {
|
||||
res.send('get');
|
||||
})
|
||||
.post(function(req, res) {
|
||||
res.send('post');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.post('/foo')
|
||||
.expect('post', done);
|
||||
});
|
||||
});
|
||||
+43
-45
@@ -7,6 +7,8 @@ var express = require('../')
|
||||
describe('app.router', function(){
|
||||
describe('methods supported', function(){
|
||||
methods.forEach(function(method){
|
||||
if (method === 'connect') return;
|
||||
|
||||
it('should include ' + method.toUpperCase(), function(done){
|
||||
if (method == 'delete') method = 'del';
|
||||
var app = express();
|
||||
@@ -27,61 +29,57 @@ describe('app.router', function(){
|
||||
});
|
||||
})
|
||||
|
||||
it('should decode params', function(done){
|
||||
var app = express();
|
||||
describe('decode querystring', function(){
|
||||
it('should decode correct params', function(done){
|
||||
var app = express();
|
||||
|
||||
app.get('/:name', function(req, res, next){
|
||||
res.send(req.params.name);
|
||||
});
|
||||
app.get('/:name', function(req, res, next){
|
||||
res.send(req.params.name);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/foo%2Fbar')
|
||||
.expect('foo/bar', done);
|
||||
})
|
||||
request(app)
|
||||
.get('/foo%2Fbar')
|
||||
.expect('foo/bar', done);
|
||||
})
|
||||
|
||||
it('should accept params in malformed paths', function(done) {
|
||||
var app = express();
|
||||
it('should not accept params in malformed paths', function(done) {
|
||||
var app = express();
|
||||
|
||||
app.get('/:name', function(req, res, next){
|
||||
res.send(req.params.name);
|
||||
});
|
||||
app.get('/:name', function(req, res, next){
|
||||
res.send(req.params.name);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/%foobar')
|
||||
.expect('%foobar', done);
|
||||
})
|
||||
request(app)
|
||||
.get('/%foobar')
|
||||
.expect(400, done);
|
||||
})
|
||||
|
||||
it('should be .use()able', function(done){
|
||||
var app = express();
|
||||
it('should not decode spaces', function(done) {
|
||||
var app = express();
|
||||
|
||||
var calls = [];
|
||||
app.get('/:name', function(req, res, next){
|
||||
res.send(req.params.name);
|
||||
});
|
||||
|
||||
app.use(function(req, res, next){
|
||||
calls.push('before');
|
||||
next();
|
||||
});
|
||||
request(app)
|
||||
.get('/foo+bar')
|
||||
.expect('foo+bar', done);
|
||||
})
|
||||
|
||||
app.use(app.router);
|
||||
it('should work with unicode', function(done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res, next){
|
||||
calls.push('after');
|
||||
res.end();
|
||||
});
|
||||
app.get('/:name', function(req, res, next){
|
||||
res.send(req.params.name);
|
||||
});
|
||||
|
||||
app.get('/', function(req, res, next){
|
||||
calls.push('GET /')
|
||||
next();
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(function(res){
|
||||
calls.should.eql(['before', 'GET /', 'after'])
|
||||
done();
|
||||
request(app)
|
||||
.get('/%ce%b1')
|
||||
.expect('\u03b1', done);
|
||||
})
|
||||
})
|
||||
|
||||
it('should be auto .use()d on the first app.VERB() call', function(done){
|
||||
it('should be .use()able', function(done){
|
||||
var app = express();
|
||||
|
||||
var calls = [];
|
||||
@@ -126,8 +124,8 @@ describe('app.router', function(){
|
||||
var app = express();
|
||||
|
||||
app.get(/^\/user\/([0-9]+)\/(view|edit)?$/, function(req, res){
|
||||
var id = req.params.shift()
|
||||
, op = req.params.shift();
|
||||
var id = req.params[0]
|
||||
, op = req.params[1];
|
||||
res.end(op + 'ing user ' + id);
|
||||
});
|
||||
|
||||
@@ -302,8 +300,8 @@ describe('app.router', function(){
|
||||
var app = express();
|
||||
|
||||
app.get('/api/*.*', function(req, res){
|
||||
var resource = req.params.shift()
|
||||
, format = req.params.shift();
|
||||
var resource = req.params[0]
|
||||
, format = req.params[1];
|
||||
res.end(resource + ' as ' + format);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
|
||||
var express = require('../')
|
||||
, assert = require('assert')
|
||||
, request = require('./support/http');
|
||||
|
||||
describe('app.routes', function(){
|
||||
it('should be initialized', function(){
|
||||
var app = express();
|
||||
app.routes.should.eql({});
|
||||
})
|
||||
|
||||
it('should be populated with routes', function(){
|
||||
var app = express();
|
||||
|
||||
app.get('/', function(req, res){});
|
||||
app.get('/user/:id', function(req, res){});
|
||||
|
||||
var get = app.routes.get;
|
||||
get.should.have.length(2);
|
||||
|
||||
get[0].path.should.equal('/');
|
||||
get[0].method.should.equal('get');
|
||||
get[0].regexp.toString().should.equal('/^\\/\\/?$/i');
|
||||
|
||||
get[1].path.should.equal('/user/:id');
|
||||
get[1].method.should.equal('get');
|
||||
})
|
||||
|
||||
it('should be mutable', function(done){
|
||||
var app = express();
|
||||
|
||||
app.get('/', function(req, res){});
|
||||
app.get('/user/:id', function(req, res){});
|
||||
|
||||
var get = app.routes.get;
|
||||
get.should.have.length(2);
|
||||
|
||||
get[0].path.should.equal('/');
|
||||
get[0].method.should.equal('get');
|
||||
get[0].regexp.toString().should.equal('/^\\/\\/?$/i');
|
||||
|
||||
get.splice(1);
|
||||
|
||||
request(app)
|
||||
.get('/user/12')
|
||||
.expect(404, done);
|
||||
})
|
||||
})
|
||||
@@ -1,96 +0,0 @@
|
||||
|
||||
var express = require('../');
|
||||
|
||||
describe('config', function(){
|
||||
describe('.configure()', function(){
|
||||
describe('when no env is given', function(){
|
||||
it('should always execute', function(){
|
||||
var app = express();
|
||||
var calls = [];
|
||||
|
||||
app.configure(function(){
|
||||
calls.push('all');
|
||||
});
|
||||
|
||||
app.configure('test', function(){
|
||||
calls.push('test');
|
||||
});
|
||||
|
||||
app.configure('test', function(){
|
||||
calls.push('test 2');
|
||||
});
|
||||
|
||||
calls.should.eql(['all', 'test', 'test 2'])
|
||||
})
|
||||
})
|
||||
|
||||
describe('when an env is given', function(){
|
||||
it('should only execute the matching env', function(){
|
||||
var app = express();
|
||||
var calls = [];
|
||||
|
||||
app.set('env', 'development');
|
||||
|
||||
app.configure('development', function(){
|
||||
calls.push('dev');
|
||||
});
|
||||
|
||||
app.configure('test', function(){
|
||||
calls.push('test');
|
||||
});
|
||||
|
||||
calls.should.eql(['dev']);
|
||||
})
|
||||
})
|
||||
|
||||
describe('when several envs are given', function(){
|
||||
it('should execute when matching one', function(){
|
||||
var app = express();
|
||||
var calls = [];
|
||||
|
||||
app.set('env', 'development');
|
||||
|
||||
app.configure('development', function(){
|
||||
calls.push('dev');
|
||||
});
|
||||
|
||||
app.configure('test', 'development', function(){
|
||||
calls.push('dev 2');
|
||||
});
|
||||
|
||||
app.configure('development', 'test', function(){
|
||||
calls.push('dev 3');
|
||||
});
|
||||
|
||||
app.configure('test', function(){
|
||||
calls.push('dev 3');
|
||||
});
|
||||
|
||||
calls.should.eql(['dev', 'dev 2', 'dev 3']);
|
||||
})
|
||||
})
|
||||
|
||||
it('should execute in order as defined', function(){
|
||||
var app = express();
|
||||
var calls = [];
|
||||
|
||||
app.configure(function(){
|
||||
calls.push('all');
|
||||
});
|
||||
|
||||
app.configure('test', function(){
|
||||
calls.push('test');
|
||||
});
|
||||
|
||||
app.configure(function(){
|
||||
calls.push('all 2');
|
||||
});
|
||||
|
||||
app.configure('test', function(){
|
||||
calls.push('test 2');
|
||||
});
|
||||
|
||||
calls.should.eql(['all', 'test', 'all 2', 'test 2'])
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -4,16 +4,6 @@ var express = require('../')
|
||||
, assert = require('assert');
|
||||
|
||||
describe('exports', function(){
|
||||
it('should expose connect middleware', function(){
|
||||
express.should.have.property('bodyParser');
|
||||
express.should.have.property('session');
|
||||
express.should.have.property('static');
|
||||
})
|
||||
|
||||
it('should expose .mime', function(){
|
||||
assert(express.mime == require('connect').mime, 'express.mime should be connect.mime');
|
||||
})
|
||||
|
||||
it('should expose Router', function(){
|
||||
express.Router.should.be.a.Function;
|
||||
})
|
||||
|
||||
externo
+1
@@ -0,0 +1 @@
|
||||
p= name
|
||||
@@ -1,37 +0,0 @@
|
||||
|
||||
var express = require('../')
|
||||
, request = require('./support/http');
|
||||
|
||||
describe('req', function(){
|
||||
describe('.accepted', function(){
|
||||
it('should return an array of accepted media types', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
req.accepted[0].value.should.equal('application/json');
|
||||
req.accepted[1].value.should.equal('text/html');
|
||||
res.end();
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Accept', 'text/html;q=.5, application/json')
|
||||
.expect(200, done);
|
||||
})
|
||||
|
||||
describe('when Accept is not present', function(){
|
||||
it('should default to []', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
req.accepted.should.have.length(0);
|
||||
res.end();
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(200, done);
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,37 +0,0 @@
|
||||
|
||||
var express = require('../')
|
||||
, request = require('./support/http');
|
||||
|
||||
describe('req', function(){
|
||||
describe('.acceptedCharsets', function(){
|
||||
it('should return an array of accepted charsets', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
req.acceptedCharsets[0].should.equal('unicode-1-1');
|
||||
req.acceptedCharsets[1].should.equal('iso-8859-5');
|
||||
res.end();
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Accept-Charset', 'iso-8859-5;q=.2, unicode-1-1;q=0.8')
|
||||
.expect(200, done);
|
||||
})
|
||||
|
||||
describe('when Accept-Charset is not present', function(){
|
||||
it('should default to []', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
req.acceptedCharsets.should.have.length(0);
|
||||
res.end();
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(200, done);
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,37 +0,0 @@
|
||||
|
||||
var express = require('../')
|
||||
, request = require('./support/http');
|
||||
|
||||
describe('req', function(){
|
||||
describe('.acceptedEncodings', function(){
|
||||
it('should return an array of accepted encodings', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
req.acceptedEncodings.should.eql(['gzip', 'deflate']);
|
||||
res.end();
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Accept-Encoding', ' gzip, deflate')
|
||||
.expect(200, done);
|
||||
})
|
||||
|
||||
describe('when Accept-Encoding is not present', function(){
|
||||
it('should default to []', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
req.acceptedEncodings.should.have.length(0);
|
||||
res.end();
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Accept-Encoding', '')
|
||||
.expect(200, done);
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,37 +0,0 @@
|
||||
|
||||
var express = require('../')
|
||||
, request = require('./support/http');
|
||||
|
||||
describe('req', function(){
|
||||
describe('.acceptedLanguages', function(){
|
||||
it('should return an array of accepted languages', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
req.acceptedLanguages[0].should.equal('en-us');
|
||||
req.acceptedLanguages[1].should.equal('en');
|
||||
res.end();
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Accept-Language', 'en;q=.5, en-us')
|
||||
.expect(200, done);
|
||||
})
|
||||
|
||||
describe('when Accept-Language is not present', function(){
|
||||
it('should default to []', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
req.acceptedLanguages.should.have.length(0);
|
||||
res.end();
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(200, done);
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -43,19 +43,6 @@ describe('req', function(){
|
||||
})
|
||||
})
|
||||
|
||||
it('should accept a comma-delimited list of types', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res, next){
|
||||
res.end(req.accepts('json, html'));
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Accept', 'text/html')
|
||||
.expect('html', done);
|
||||
})
|
||||
|
||||
it('should accept an argument list of type names', function(done){
|
||||
var app = express();
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ describe('req', function(){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res, next){
|
||||
res.end(req.acceptsCharset('utf-8') ? 'yes' : 'no');
|
||||
res.end(req.acceptsCharsets('utf-8') ? 'yes' : 'no');
|
||||
});
|
||||
|
||||
request(app)
|
||||
@@ -23,7 +23,7 @@ describe('req', function(){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res, next){
|
||||
res.end(req.acceptsCharset('utf-8') ? 'yes' : 'no');
|
||||
res.end(req.acceptsCharsets('utf-8') ? 'yes' : 'no');
|
||||
});
|
||||
|
||||
request(app)
|
||||
@@ -36,7 +36,7 @@ describe('req', function(){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res, next){
|
||||
res.end(req.acceptsCharset('utf-8') ? 'yes' : 'no');
|
||||
res.end(req.acceptsCharsets('utf-8') ? 'yes' : 'no');
|
||||
});
|
||||
|
||||
request(app)
|
||||
|
||||
+12
-9
@@ -4,8 +4,11 @@ var express = require('../')
|
||||
|
||||
function req(ct) {
|
||||
var req = {
|
||||
headers: { 'content-type': ct }
|
||||
, __proto__: express.request
|
||||
headers: {
|
||||
'content-type': ct,
|
||||
'transfer-encoding': 'chunked'
|
||||
},
|
||||
__proto__: express.request
|
||||
};
|
||||
|
||||
return req;
|
||||
@@ -15,7 +18,7 @@ describe('req.is()', function(){
|
||||
it('should ignore charset', function(){
|
||||
req('application/json; charset=utf-8')
|
||||
.is('json')
|
||||
.should.be.true;
|
||||
.should.equal('json');
|
||||
})
|
||||
|
||||
describe('when content-type is not present', function(){
|
||||
@@ -30,7 +33,7 @@ describe('req.is()', function(){
|
||||
it('should lookup the mime type', function(){
|
||||
req('application/json')
|
||||
.is('json')
|
||||
.should.be.true;
|
||||
.should.equal('json');
|
||||
|
||||
req('text/html')
|
||||
.is('json')
|
||||
@@ -42,7 +45,7 @@ describe('req.is()', function(){
|
||||
it('should match', function(){
|
||||
req('application/json')
|
||||
.is('application/json')
|
||||
.should.be.true;
|
||||
.should.equal('application/json');
|
||||
|
||||
req('image/jpeg')
|
||||
.is('application/json')
|
||||
@@ -54,7 +57,7 @@ describe('req.is()', function(){
|
||||
it('should match', function(){
|
||||
req('application/json')
|
||||
.is('*/json')
|
||||
.should.be.true;
|
||||
.should.equal('application/json');
|
||||
|
||||
req('image/jpeg')
|
||||
.is('*/json')
|
||||
@@ -65,7 +68,7 @@ describe('req.is()', function(){
|
||||
it('should match', function(){
|
||||
req('text/html; charset=utf-8')
|
||||
.is('*/html')
|
||||
.should.be.true;
|
||||
.should.equal('text/html');
|
||||
|
||||
req('text/plain; charset=utf-8')
|
||||
.is('*/html')
|
||||
@@ -78,7 +81,7 @@ describe('req.is()', function(){
|
||||
it('should match', function(){
|
||||
req('image/png')
|
||||
.is('image/*')
|
||||
.should.be.true;
|
||||
.should.equal('image/png');
|
||||
|
||||
req('text/html')
|
||||
.is('image/*')
|
||||
@@ -89,7 +92,7 @@ describe('req.is()', function(){
|
||||
it('should match', function(){
|
||||
req('text/html; charset=utf-8')
|
||||
.is('text/*')
|
||||
.should.be.true;
|
||||
.should.equal('text/html');
|
||||
|
||||
req('something/html; charset=utf-8')
|
||||
.is('text/*')
|
||||
|
||||
+3
-2
@@ -1,6 +1,7 @@
|
||||
|
||||
var express = require('../')
|
||||
, request = require('./support/http');
|
||||
, request = require('./support/http')
|
||||
, bodyParser = require('body-parser')
|
||||
|
||||
describe('req', function(){
|
||||
describe('.param(name, default)', function(){
|
||||
@@ -33,7 +34,7 @@ describe('req', function(){
|
||||
it('should check req.body', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(express.bodyParser());
|
||||
app.use(bodyParser());
|
||||
|
||||
app.use(function(req, res){
|
||||
res.end(req.param('name'));
|
||||
|
||||
@@ -8,13 +8,11 @@ describe('req', function(){
|
||||
var app = express();
|
||||
|
||||
app.get('/user/:id/:op?', function(req, res, next){
|
||||
req.route.method.should.equal('get');
|
||||
req.route.path.should.equal('/user/:id/:op?');
|
||||
next();
|
||||
});
|
||||
|
||||
app.get('/user/:id/edit', function(req, res){
|
||||
req.route.method.should.equal('get');
|
||||
req.route.path.should.equal('/user/:id/edit');
|
||||
res.end();
|
||||
});
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
|
||||
var express = require('../')
|
||||
, request = require('./support/http');
|
||||
, request = require('./support/http')
|
||||
, cookieParser = require('cookie-parser')
|
||||
|
||||
describe('req', function(){
|
||||
describe('.signedCookies', function(){
|
||||
it('should return a signed JSON cookie', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(express.cookieParser('secret'));
|
||||
app.use(cookieParser('secret'));
|
||||
|
||||
app.use(function(req, res){
|
||||
if ('/set' == req.path) {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
|
||||
var express = require('../')
|
||||
, request = require('./support/http')
|
||||
, utils = require('connect').utils
|
||||
, cookie = require('cookie');
|
||||
, mixin = require('utils-merge')
|
||||
, cookie = require('cookie')
|
||||
, cookieParser = require('cookie-parser')
|
||||
|
||||
describe('res', function(){
|
||||
describe('.cookie(name, object)', function(){
|
||||
@@ -46,13 +47,14 @@ describe('res', function(){
|
||||
app.use(function(req, res){
|
||||
res.cookie('name', 'tobi');
|
||||
res.cookie('age', 1);
|
||||
res.cookie('gender', '?');
|
||||
res.end();
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(function(err, res){
|
||||
var val = ['name=tobi; Path=/', 'age=1; Path=/'];
|
||||
var val = ['name=tobi; Path=/', 'age=1; Path=/', 'gender=%3F; Path=/'];
|
||||
res.headers['set-cookie'].should.eql(val);
|
||||
done();
|
||||
})
|
||||
@@ -114,7 +116,7 @@ describe('res', function(){
|
||||
var app = express();
|
||||
|
||||
var options = { maxAge: 1000 };
|
||||
var optionsCopy = utils.merge({}, options);
|
||||
var optionsCopy = mixin({}, options);
|
||||
|
||||
app.use(function(req, res){
|
||||
res.cookie('name', 'tobi', options)
|
||||
@@ -134,7 +136,7 @@ describe('res', function(){
|
||||
it('should generate a signed JSON cookie', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(express.cookieParser('foo bar baz'));
|
||||
app.use(cookieParser('foo bar baz'));
|
||||
|
||||
app.use(function(req, res){
|
||||
res.cookie('user', { name: 'tobi' }, { signed: true }).end();
|
||||
@@ -155,7 +157,7 @@ describe('res', function(){
|
||||
it('should set a signed cookie', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(express.cookieParser('foo bar baz'));
|
||||
app.use(cookieParser('foo bar baz'));
|
||||
|
||||
app.use(function(req, res){
|
||||
res.cookie('name', 'tobi', { signed: true }).end();
|
||||
|
||||
+3
-10
@@ -52,7 +52,7 @@ describe('res', function(){
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
describe('when given an object', function(){
|
||||
it('should respond with json', function(done){
|
||||
var app = express();
|
||||
@@ -95,14 +95,7 @@ describe('res', function(){
|
||||
})
|
||||
|
||||
describe('"json spaces" setting', function(){
|
||||
it('should default to 2 in development', function(){
|
||||
process.env.NODE_ENV = 'development';
|
||||
var app = express();
|
||||
app.get('json spaces').should.equal(2);
|
||||
process.env.NODE_ENV = 'test';
|
||||
})
|
||||
|
||||
it('should be undefined otherwise', function(){
|
||||
it('should be undefined by default', function(){
|
||||
var app = express();
|
||||
assert(undefined === app.get('json spaces'));
|
||||
})
|
||||
@@ -125,7 +118,7 @@ describe('res', function(){
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
describe('.json(status, object)', function(){
|
||||
it('should respond with json and set the .statusCode', function(done){
|
||||
var app = express();
|
||||
|
||||
+1
-8
@@ -181,14 +181,7 @@ describe('res', function(){
|
||||
})
|
||||
|
||||
describe('"json spaces" setting', function(){
|
||||
it('should default to 2 in development', function(){
|
||||
process.env.NODE_ENV = 'development';
|
||||
var app = express();
|
||||
app.get('json spaces').should.equal(2);
|
||||
process.env.NODE_ENV = 'test';
|
||||
})
|
||||
|
||||
it('should be undefined otherwise', function(){
|
||||
it('should be undefined by default', function(){
|
||||
var app = express();
|
||||
assert(undefined === app.get('json spaces'));
|
||||
})
|
||||
|
||||
@@ -3,15 +3,12 @@ var express = require('../')
|
||||
, request = require('./support/http');
|
||||
|
||||
describe('res', function(){
|
||||
describe('.locals(obj)', function(){
|
||||
it('should merge locals', function(done){
|
||||
describe('.locals', function(){
|
||||
it('should be empty by default', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
Object.keys(res.locals).should.eql([]);
|
||||
res.locals({ user: 'tobi', age: 1 });
|
||||
res.locals.user.should.equal('tobi');
|
||||
res.locals.age.should.equal(1);
|
||||
res.end();
|
||||
});
|
||||
|
||||
|
||||
@@ -18,171 +18,5 @@ describe('res', function(){
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
describe('with leading //', function(){
|
||||
it('should pass through scheme-relative urls', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.location('//cuteoverload.com').end();
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('location', '//cuteoverload.com');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('with leading /', function(){
|
||||
it('should construct scheme-relative urls', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.location('/login').end();
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('location', '/login');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('with leading ./', function(){
|
||||
it('should construct path-relative urls', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.location('./edit').end();
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/post/1')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('location', '/post/1/edit');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('with leading ../', function(){
|
||||
it('should construct path-relative urls', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.location('../new').end();
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/post/1')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('location', '/post/new');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('with leading ./ and containing ..', function(){
|
||||
it('should construct path-relative urls', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.location('./skip/../../new').end();
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/post/1')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('location', '/post/new');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('without leading /', function(){
|
||||
it('should construct mount-point relative urls', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.location('login').end();
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('location', '/login');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('when mounted', function(){
|
||||
describe('deeply', function(){
|
||||
it('should respect the mount-point', function(done){
|
||||
var app = express()
|
||||
, blog = express()
|
||||
, admin = express();
|
||||
|
||||
admin.use(function(req, res){
|
||||
res.location('login').end();
|
||||
});
|
||||
|
||||
app.use('/blog', blog);
|
||||
blog.use('/admin', admin);
|
||||
|
||||
request(app)
|
||||
.get('/blog/admin')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('location', '/blog/admin/login');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('omitting leading /', function(){
|
||||
it('should respect the mount-point', function(done){
|
||||
var app = express()
|
||||
, admin = express();
|
||||
|
||||
admin.use(function(req, res){
|
||||
res.location('admin/login').end();
|
||||
});
|
||||
|
||||
app.use('/blog', admin);
|
||||
|
||||
request(app)
|
||||
.get('/blog')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('location', '/blog/admin/login');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('providing leading /', function(){
|
||||
it('should ignore mount-point', function(done){
|
||||
var app = express()
|
||||
, admin = express();
|
||||
|
||||
admin.use(function(req, res){
|
||||
res.location('/admin/login').end();
|
||||
});
|
||||
|
||||
app.use('/blog', admin);
|
||||
|
||||
request(app)
|
||||
.get('/blog')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('location', '/admin/login');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
+1
-73
@@ -105,7 +105,7 @@ describe('res', function(){
|
||||
.set('Host', 'http://example.com')
|
||||
.set('Accept', 'text/html')
|
||||
.end(function(err, res){
|
||||
res.text.should.equal('<p>Moved Temporarily. Redirecting to <a href="/<lame>">/<lame></a></p>');
|
||||
res.text.should.equal('<p>Moved Temporarily. Redirecting to <a href="<lame>"><lame></a></p>');
|
||||
done();
|
||||
})
|
||||
})
|
||||
@@ -169,76 +169,4 @@ describe('res', function(){
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('responses redirected to relative paths', function(){
|
||||
function create(depth, parent) {
|
||||
var app = express();
|
||||
|
||||
if (parent) {
|
||||
parent.use('/depth' + depth, app);
|
||||
}
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.redirect('./index');
|
||||
});
|
||||
|
||||
app.get('/index', function(req, res){
|
||||
res.json({ depth: depth, content: 'index' });
|
||||
});
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
var root = create(0);
|
||||
var depth1 = create(1, root);
|
||||
var depth2 = create(2, depth1);
|
||||
var depth3 = create(3, depth2);
|
||||
|
||||
root.use('/depth2', depth2);
|
||||
root.use('/depth3', depth3);
|
||||
|
||||
it('should not contain redundant leading slashes in the location header', function(done){
|
||||
request(root)
|
||||
.get('/')
|
||||
.end(function(err, res){
|
||||
res.headers.location.search(/^\/{2}/).should.equal(-1);
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('should preserve context when redirecting nested applications at any depth', function(done){
|
||||
request(root)
|
||||
.get('/depth1')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('location', '/depth1/index');
|
||||
|
||||
request(root)
|
||||
.get('/depth1/depth2')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('location', '/depth1/depth2/index');
|
||||
|
||||
request(root)
|
||||
.get('/depth1/depth2/depth3')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('location', '/depth1/depth2/depth3/index');
|
||||
done();
|
||||
})
|
||||
})
|
||||
});
|
||||
})
|
||||
|
||||
it('should redirect correctly for nested applications that have been remounted', function(done){
|
||||
request(root)
|
||||
.get('/depth2')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('location', '/depth2/index');
|
||||
request(root)
|
||||
.get('/depth3')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('location', '/depth3/index');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -47,6 +47,21 @@ describe('res', function(){
|
||||
.get('/')
|
||||
.expect('<p>tobi</p>', done);
|
||||
})
|
||||
|
||||
it('should expose app.locals with `name` property', function(done){
|
||||
var app = express();
|
||||
|
||||
app.set('views', __dirname + '/fixtures');
|
||||
app.locals.name = 'tobi';
|
||||
|
||||
app.use(function(req, res){
|
||||
res.render('name.jade');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('<p>tobi</p>', done);
|
||||
})
|
||||
|
||||
it('should support index.<engine>', function(done){
|
||||
var app = express();
|
||||
|
||||
+5
-1
@@ -14,6 +14,7 @@ describe('res', function(){
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Content-Length', '0')
|
||||
.expect('', done);
|
||||
})
|
||||
})
|
||||
@@ -28,7 +29,10 @@ describe('res', function(){
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('', done);
|
||||
.expect('', function(req, res){
|
||||
res.header.should.not.have.property('content-length');
|
||||
done();
|
||||
});
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ describe('res', function(){
|
||||
app.use(function(req, res){
|
||||
res.sendfile('test/fixtures/nope.html', function(err){
|
||||
++calls;
|
||||
assert(!res.headerSent);
|
||||
assert(!res.headersSent);
|
||||
res.send(err.message);
|
||||
});
|
||||
});
|
||||
@@ -77,7 +77,7 @@ describe('res', function(){
|
||||
|
||||
app.use(function(req, res){
|
||||
res.sendfile('test/fixtures/foo/../user.html', function(err){
|
||||
assert(!res.headerSent);
|
||||
assert(!res.headersSent);
|
||||
++calls;
|
||||
res.send(err.message);
|
||||
});
|
||||
@@ -95,7 +95,7 @@ describe('res', function(){
|
||||
|
||||
app.use(function(req, res){
|
||||
res.sendfile('test/fixtures/user.html', function(err){
|
||||
assert(!res.headerSent);
|
||||
assert(!res.headersSent);
|
||||
req.socket.listeners('error').should.have.length(1); // node's original handler
|
||||
done();
|
||||
});
|
||||
|
||||
-178
@@ -41,181 +41,3 @@ describe('utils.flatten(arr)', function(){
|
||||
.should.eql(['one', 'two', 'three', 'four', 'five']);
|
||||
})
|
||||
})
|
||||
|
||||
describe('utils.escape(html)', function(){
|
||||
it('should escape html entities', function(){
|
||||
utils.escape('<script>foo & "bar"')
|
||||
.should.equal('<script>foo & "bar"')
|
||||
})
|
||||
})
|
||||
|
||||
describe('utils.parseParams(str)', function(){
|
||||
it('should default quality to 1', function(){
|
||||
utils.parseParams('text/html')
|
||||
.should.eql([{ value: 'text/html', quality: 1, params: {}, originalIndex: 0 }]);
|
||||
})
|
||||
|
||||
it('should parse qvalues', function(){
|
||||
utils.parseParams('text/html; q=0.5')
|
||||
.should.eql([{ value: 'text/html', quality: 0.5, params: {}, originalIndex: 0 }]);
|
||||
|
||||
utils.parseParams('text/html; q=.2')
|
||||
.should.eql([{ value: 'text/html', quality: 0.2, params: {}, originalIndex: 0 }]);
|
||||
})
|
||||
|
||||
it('should parse accept parameters', function(){
|
||||
utils.parseParams('application/json; ver=2.0')
|
||||
.should.eql([{ value: 'application/json', quality: 1, params: {ver: "2.0"}, originalIndex: 0 }]);
|
||||
|
||||
utils.parseParams('text/html; q=0.5; level=2')
|
||||
.should.eql([{ value: 'text/html', quality: 0.5, params: {level: "2"}, originalIndex: 0 }]);
|
||||
utils.parseParams('text/html;q=.2;ver=beta')
|
||||
.should.eql([{ value: 'text/html', quality: 0.2, params: {ver: "beta"}, originalIndex: 0 }]);
|
||||
})
|
||||
|
||||
it('should work with messed up whitespace', function(){
|
||||
utils.parseParams('text/html ; q = .2')
|
||||
.should.eql([{ value: 'text/html', quality: 0.2, params: {}, originalIndex: 0 }]);
|
||||
})
|
||||
|
||||
it('should work with multiples', function(){
|
||||
var str = 'da, en;q=.5, en-gb;q=.8';
|
||||
var arr = utils.parseParams(str);
|
||||
arr[0].value.should.equal('da');
|
||||
arr[1].value.should.equal('en-gb');
|
||||
arr[2].value.should.equal('en');
|
||||
})
|
||||
|
||||
it('should work with long lists', function(){
|
||||
var str = 'en, nl, fr, de, ja, it, es, pt, pt-PT, da, fi, nb, sv, ko, zh-Hans, zh-Hant, ru, pl';
|
||||
var arr = utils.parseParams(str).map(function(o){ return o.value });
|
||||
arr.should.eql(str.split(', '));
|
||||
})
|
||||
|
||||
it('should sort by quality', function(){
|
||||
var str = 'text/plain;q=.2, application/json, text/html;q=0.5';
|
||||
var arr = utils.parseParams(str);
|
||||
arr[0].value.should.equal('application/json');
|
||||
arr[1].value.should.equal('text/html');
|
||||
arr[2].value.should.equal('text/plain');
|
||||
})
|
||||
|
||||
it('should exclude those with a quality of 0', function(){
|
||||
var str = 'text/plain;q=.2, application/json, text/html;q=0';
|
||||
var arr = utils.parseParams(str);
|
||||
arr.should.have.length(2);
|
||||
})
|
||||
})
|
||||
|
||||
describe('utils.parseAccept(str)', function(){
|
||||
it('should provide .type', function(){
|
||||
var arr = utils.parseAccept('text/html');
|
||||
arr[0].type.should.equal('text');
|
||||
})
|
||||
|
||||
it('should provide .subtype', function(){
|
||||
var arr = utils.parseAccept('text/html');
|
||||
arr[0].subtype.should.equal('html');
|
||||
})
|
||||
})
|
||||
|
||||
describe('utils.accepts(type, str)', function(){
|
||||
describe('when a string is not given', function(){
|
||||
it('should return the value', function(){
|
||||
utils.accepts('text/html')
|
||||
.should.equal('text/html');
|
||||
})
|
||||
})
|
||||
|
||||
describe('when a string is empty', function(){
|
||||
it('should return the value', function(){
|
||||
utils.accepts('text/html', '')
|
||||
.should.equal('text/html');
|
||||
})
|
||||
})
|
||||
|
||||
describe('when */* is given', function(){
|
||||
it('should return the value', function(){
|
||||
utils.accepts('text/html', 'text/plain, */*')
|
||||
.should.equal('text/html');
|
||||
})
|
||||
})
|
||||
|
||||
describe('when an array is given', function(){
|
||||
it('should return the best match', function(){
|
||||
utils.accepts(['html', 'json'], 'text/plain, application/json')
|
||||
.should.equal('json');
|
||||
|
||||
utils.accepts(['html', 'application/json'], 'text/plain, application/json')
|
||||
.should.equal('application/json');
|
||||
|
||||
utils.accepts(['text/html', 'application/json'], 'application/json;q=.5, text/html')
|
||||
.should.equal('text/html');
|
||||
})
|
||||
})
|
||||
|
||||
describe('when a comma-delimited list is give', function(){
|
||||
it('should behave like an array', function(){
|
||||
utils.accepts('html, json', 'text/plain, application/json')
|
||||
.should.equal('json');
|
||||
|
||||
utils.accepts('html, application/json', 'text/plain, application/json')
|
||||
.should.equal('application/json');
|
||||
|
||||
utils.accepts('text/html, application/json', 'application/json;q=.5, text/html')
|
||||
.should.equal('text/html');
|
||||
})
|
||||
})
|
||||
|
||||
describe('when accepting type/subtype', function(){
|
||||
it('should return the value when present', function(){
|
||||
utils.accepts('text/html', 'text/plain, text/html')
|
||||
.should.equal('text/html');
|
||||
})
|
||||
|
||||
it('should return undefined otherwise', function(){
|
||||
assert(null == utils.accepts('text/html', 'text/plain, application/json'));
|
||||
})
|
||||
})
|
||||
|
||||
describe('when accepting */subtype', function(){
|
||||
it('should return the value when present', function(){
|
||||
utils.accepts('text/html', 'text/*')
|
||||
.should.equal('text/html');
|
||||
})
|
||||
|
||||
it('should return undefined otherwise', function(){
|
||||
assert(null == utils.accepts('text/html', 'image/*'));
|
||||
})
|
||||
})
|
||||
|
||||
describe('when accepting type/*', function(){
|
||||
it('should return the value when present', function(){
|
||||
utils.accepts('text/html', '*/html')
|
||||
.should.equal('text/html');
|
||||
})
|
||||
|
||||
it('should return undefined otherwise', function(){
|
||||
assert(null == utils.accepts('text/html', '*/json'));
|
||||
})
|
||||
})
|
||||
|
||||
describe('when an extension is given', function(){
|
||||
it('should return the value when present', function(){
|
||||
utils.accepts('html', 'text/html, application/json')
|
||||
.should.equal('html');
|
||||
})
|
||||
|
||||
it('should return undefined otherwise', function(){
|
||||
assert(null == utils.accepts('html', 'text/plain, application/json'));
|
||||
})
|
||||
|
||||
it('should support *', function(){
|
||||
utils.accepts('html', 'text/*')
|
||||
.should.equal('html');
|
||||
|
||||
utils.accepts('html', '*/html')
|
||||
.should.equal('html');
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário