mirror of
https://github.com/expressjs/express.git
synced 2026-02-27 11:09:29 +00:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c72abc5293 | ||
|
|
93189ad0b6 | ||
|
|
c0aab36187 | ||
|
|
5ae994ee8f | ||
|
|
60d16eab77 | ||
|
|
fc60dfc1a6 | ||
|
|
45d149c146 | ||
|
|
4dfc1a69c3 | ||
|
|
0ae18bca60 | ||
|
|
2aaf0defe7 | ||
|
|
73ea5cd7ee | ||
|
|
e7f2d229ec | ||
|
|
87bc265817 | ||
|
|
796aaff295 | ||
|
|
8f87c50320 | ||
|
|
ee4471b345 | ||
|
|
6815feb8cf | ||
|
|
dbbe7be891 | ||
|
|
09c9452e5c | ||
|
|
b0e669ba00 | ||
|
|
f46ae9f3b2 | ||
|
|
9f2b344be8 | ||
|
|
6b47271679 | ||
|
|
6f7075be74 | ||
|
|
4b9cc3d698 |
23
History.md
23
History.md
@@ -1,4 +1,27 @@
|
||||
|
||||
2.4.3 / 2011-07-14
|
||||
==================
|
||||
|
||||
* Added docs for `status` option special-case. Closes #739
|
||||
* Fixed `options.filename`, exposing the view path to template engines
|
||||
|
||||
2.4.2. / 2011-07-06
|
||||
==================
|
||||
|
||||
* Revert "removed jsonp stripping" for XSS
|
||||
|
||||
2.4.1 / 2011-07-06
|
||||
==================
|
||||
|
||||
* Added `res.json()` JSONP support. Closes #737
|
||||
* Added _extending-templates_ example. Closes #730
|
||||
* Added "strict routing" setting for trailing slashes
|
||||
* Added support for multiple envs in `app.configure()` calls. Closes #735
|
||||
* Changed: `res.send()` using `res.json()`
|
||||
* Changed: when cookie `path === null` don't default it
|
||||
* Changed; default cookie path to "home" setting. Closes #731
|
||||
* Removed _pids/logs_ creation from express(1)
|
||||
|
||||
2.4.0 / 2011-06-28
|
||||
==================
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ var fs = require('fs')
|
||||
* Framework version.
|
||||
*/
|
||||
|
||||
var version = '2.4.0';
|
||||
var version = '2.4.3';
|
||||
|
||||
/**
|
||||
* Add session support.
|
||||
@@ -260,8 +260,6 @@ while (args.length) {
|
||||
|
||||
function createApplicationAt(path) {
|
||||
mkdir(path, function(){
|
||||
mkdir(path + '/pids');
|
||||
mkdir(path + '/logs');
|
||||
mkdir(path + '/public/javascripts');
|
||||
mkdir(path + '/public/images');
|
||||
mkdir(path + '/public/stylesheets', function(){
|
||||
|
||||
@@ -180,6 +180,8 @@
|
||||
</a>
|
||||
<div id="wrapper">
|
||||
<div id="container"><ul id="toc">
|
||||
|
||||
</ul><ul id="toc">
|
||||
<li><a href="#installation">Installation</a></li>
|
||||
<li><a href="#creating-a server">Creating A Server</a></li>
|
||||
<li><a href="#creating-an https server">Creating An HTTPS Server</a></li>
|
||||
|
||||
@@ -71,6 +71,12 @@ otherwise the first call to _app.get()_, _app.post()_, etc will mount the routes
|
||||
app.use(express.errorHandler());
|
||||
});
|
||||
|
||||
For similar environments you may also pass several env strings:
|
||||
|
||||
app.configure('stage', 'prod', function(){
|
||||
// config
|
||||
});
|
||||
|
||||
For internal and arbitrary settings Express provides the _set(key[, val])_, _enable(key)_, _disable(key)_ methods:
|
||||
|
||||
app.configure(function(){
|
||||
@@ -104,6 +110,8 @@ Express supports the following settings out of the box:
|
||||
* _view options_ An object specifying global view options
|
||||
* _view cache_ Enable view caching (enabled in production)
|
||||
* _case sensitive routes_ Enable case-sensitive routing
|
||||
* _strict routing_ When enabled trailing slashes are no longer ignored
|
||||
* _jsonp callback_ Enable _res.send()_ / _res.json()_ transparent jsonp support
|
||||
|
||||
### Routing
|
||||
|
||||
@@ -943,7 +951,8 @@ the "home" setting and defaults to "/".
|
||||
|
||||
### res.cookie(name, val[, options])
|
||||
|
||||
Sets the given cookie _name_ to _val_, with options _httpOnly_, _secure_, _expires_ etc.
|
||||
Sets the given cookie _name_ to _val_, with options _httpOnly_, _secure_, _expires_ etc. The _path_ option defaults to the app's "home" setting, which
|
||||
is typically "/".
|
||||
|
||||
// "Remember me" for 15 minutes
|
||||
res.cookie('rememberme', 'yes', { expires: new Date(Date.now() + 900000), httpOnly: true });
|
||||
@@ -962,7 +971,8 @@ To parse incoming _Cookie_ headers, use the _cookieParser_ middleware, which pro
|
||||
|
||||
### res.clearCookie(name[, options])
|
||||
|
||||
Clear cookie _name_ by setting "expires" far in the past.
|
||||
Clear cookie _name_ by setting "expires" far in the past. Much like
|
||||
_res.cookie()_ the _path_ option also defaults to the "home" setting.
|
||||
|
||||
res.clearCookie('rememberme');
|
||||
|
||||
@@ -977,6 +987,15 @@ The _options_ passed are the local variables as well, for example if we want to
|
||||
var user = { name: 'tj' };
|
||||
res.render('index', { layout: false, user: user });
|
||||
|
||||
This _options_ object is also considered an "options" object. For example
|
||||
when you pass the _status_ local, it's not only available to the view, it
|
||||
sets the response status to this number. This is also useful if a template
|
||||
engine accepts specific options, such as _debug_, or _compress_. Below
|
||||
is an example of how one might render an error page, passing the _status_ for
|
||||
display, as well as it setting _res.statusCode_.
|
||||
|
||||
res.render('error', { status: 500, message: 'Internal Server Error' });
|
||||
|
||||
### res.partial(view[, options])
|
||||
|
||||
Render _view_ partial with the given _options_. This method is always available
|
||||
@@ -1218,7 +1237,6 @@ as well as the _name()_ function exposed.
|
||||
Express also provides a few locals by default:
|
||||
|
||||
- `settings` the app's settings object
|
||||
- `filename` the view's filename
|
||||
- `layout(path)` specify the layout from within a view
|
||||
|
||||
This method is aliased as _app.locals()_.
|
||||
|
||||
@@ -9,13 +9,15 @@ require.paths.unshift(__dirname + '/../../support');
|
||||
var express = require('../../lib/express');
|
||||
|
||||
var app = express.createServer();
|
||||
app.set('views', __dirname + '/views');
|
||||
app.set('view engine', 'jade');
|
||||
|
||||
// Serve default connect favicon
|
||||
app.use(express.favicon());
|
||||
|
||||
// Logger is placed below favicon, so favicon.ico
|
||||
// requests will not be logged
|
||||
app.use(express.logger({ format: '":method :url" :status' }));
|
||||
app.use(express.logger('":method :url" :status'));
|
||||
|
||||
// "app.router" positions our routes
|
||||
// specifically above the middleware
|
||||
@@ -23,59 +25,38 @@ app.use(express.logger({ format: '":method :url" :status' }));
|
||||
|
||||
app.use(app.router);
|
||||
|
||||
// When no more middleware require execution, aka
|
||||
// our router is finished and did not respond, we
|
||||
// can assume that it is "not found". Instead of
|
||||
// letting Connect deal with this, we define our
|
||||
// custom middleware here to simply pass a NotFound
|
||||
// exception
|
||||
// Since this is the last non-error-handling
|
||||
// middleware use()d, we assume 404, as nothing else
|
||||
// responded.
|
||||
|
||||
app.use(function(req, res, next){
|
||||
next(new NotFound(req.url));
|
||||
// the status option, or res.statusCode = 404
|
||||
// are equivalent, however with the option we
|
||||
// get the "status" local available as well
|
||||
res.render('404', { status: 404, url: req.url });
|
||||
});
|
||||
|
||||
app.set('views', __dirname + '/views');
|
||||
// error-handling middleware, take the same form
|
||||
// as regular middleware, however they require an
|
||||
// arity of 4, aka the signature (err, req, res, next).
|
||||
// when connect has an error, it will invoke ONLY error-handling
|
||||
// middleware.
|
||||
|
||||
// Provide our app with the notion of NotFound exceptions
|
||||
// If we were to next() here any remaining non-error-handling
|
||||
// middleware would then be executed, or if we next(err) to
|
||||
// continue passing the error, only error-handling middleware
|
||||
// would remain being executed, however here
|
||||
// we simply respond with an error page.
|
||||
|
||||
function NotFound(path){
|
||||
this.name = 'NotFound';
|
||||
if (path) {
|
||||
Error.call(this, 'Cannot find ' + path);
|
||||
this.path = path;
|
||||
} else {
|
||||
Error.call(this, 'Not Found');
|
||||
}
|
||||
Error.captureStackTrace(this, arguments.callee);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inherit from `Error.prototype`.
|
||||
*/
|
||||
|
||||
NotFound.prototype.__proto__ = Error.prototype;
|
||||
|
||||
// We can call app.error() several times as shown below.
|
||||
// Here we check for an instanceof NotFound and show the
|
||||
// 404 page, or we pass on to the next error handler.
|
||||
|
||||
// These handlers could potentially be defined within
|
||||
// configure() blocks to provide introspection when
|
||||
// in the development environment.
|
||||
|
||||
app.error(function(err, req, res, next){
|
||||
if (err instanceof NotFound) {
|
||||
res.render('404.jade', { status: 404, error: err });
|
||||
} else {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
|
||||
// Here we assume all errors as 500 for the simplicity of
|
||||
// this demo, however you can choose whatever you like
|
||||
|
||||
app.error(function(err, req, res){
|
||||
res.render('500.jade', { status: 500, error: err });
|
||||
app.use(function(err, req, res, next){
|
||||
// we may use properties of the error object
|
||||
// here and next(err) appropriately, or if
|
||||
// we possibly recovered from the error, simply next().
|
||||
res.render('500', {
|
||||
status: err.status || 500
|
||||
, error: err
|
||||
});
|
||||
});
|
||||
|
||||
// Routes
|
||||
@@ -84,8 +65,14 @@ app.get('/', function(req, res){
|
||||
res.render('index.jade');
|
||||
});
|
||||
|
||||
app.get('/404', function(req, res){
|
||||
throw new NotFound(req.url);
|
||||
app.get('/404', function(req, res, next){
|
||||
next();
|
||||
});
|
||||
|
||||
app.get('/403', function(req, res, next){
|
||||
var err = new Error('not allowed!');
|
||||
err.status = 403;
|
||||
next(err);
|
||||
});
|
||||
|
||||
app.get('/500', function(req, res, next){
|
||||
|
||||
@@ -1,4 +1 @@
|
||||
- if (error.path)
|
||||
h2 Cannot find #{error.path}
|
||||
- else
|
||||
h2 Page Not Found
|
||||
h2 Cannot find #{url}
|
||||
@@ -5,4 +5,7 @@ ul
|
||||
a(href="/500") 500
|
||||
li
|
||||
| visit
|
||||
a(href="/404") 404
|
||||
a(href="/404") 404
|
||||
li
|
||||
| visit
|
||||
a(href='/403') 403
|
||||
66
examples/extending-templates/app.js
Normal file
66
examples/extending-templates/app.js
Normal file
@@ -0,0 +1,66 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express');
|
||||
|
||||
var app = express.createServer();
|
||||
|
||||
// Register ejs as .html
|
||||
|
||||
app.register('.html', require('ejs'));
|
||||
|
||||
// Optional since express defaults to CWD/views
|
||||
|
||||
app.set('views', __dirname + '/views');
|
||||
app.set('view engine', 'html');
|
||||
|
||||
// Dummy users
|
||||
var users = [
|
||||
{ name: 'tj', email: 'tj@sencha.com' }
|
||||
, { name: 'ciaran', email: 'ciaranj@gmail.com' }
|
||||
, { name: 'aaron', email: 'aaron.heckmann+github@gmail.com' }
|
||||
];
|
||||
|
||||
// dynamic helpers are simply functions that are invoked
|
||||
// per request (once), passed both the request and response
|
||||
// objects. These can be used for request-specific
|
||||
// details within a view, such telling the layout which
|
||||
// scripts to include.
|
||||
app.dynamicHelpers({
|
||||
// by simply returning an object here
|
||||
// we can set it's properties such as "page.title"
|
||||
// within a view, and it remains specific to that request,
|
||||
// so it would be valid to do:
|
||||
// page.title = user.name + "'s account"
|
||||
page: function() {
|
||||
return {};
|
||||
},
|
||||
|
||||
// the scripts array here is assigned once,
|
||||
// so by returning a closure, we can use script(path)
|
||||
// in a template, instead of something like
|
||||
// scripts.push(path).
|
||||
script: function(req){
|
||||
req._scripts = [];
|
||||
return function(path){
|
||||
req._scripts.push(path);
|
||||
}
|
||||
},
|
||||
|
||||
// to expose our scripts array for iteration within
|
||||
// our views (typically the layout), we simply return it
|
||||
// here, and since composite types are mutable, it will
|
||||
// contain all of the paths pushed with the helper above.
|
||||
scripts: function(req){
|
||||
return req._scripts;
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.render('users', { users: users });
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express app started on port 3000');
|
||||
11
examples/extending-templates/views/layout.html
Normal file
11
examples/extending-templates/views/layout.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<html>
|
||||
<head>
|
||||
<title><%- page.title %></title>
|
||||
<% for (var i in scripts) { %>
|
||||
<script src="<%= scripts[i] %>"></script>
|
||||
<% } %>
|
||||
</head>
|
||||
<body>
|
||||
<%- body %>
|
||||
</body>
|
||||
</html>
|
||||
8
examples/extending-templates/views/users/index.html
Normal file
8
examples/extending-templates/views/users/index.html
Normal file
@@ -0,0 +1,8 @@
|
||||
<% page.title = 'Users' %>
|
||||
<% script('/javascripts/jquery.js') %>
|
||||
<% script('/javascripts/users.js') %>
|
||||
|
||||
<h1>Users</h1>
|
||||
<ul id="users">
|
||||
<%- partial('user', users) %>
|
||||
</ul>
|
||||
1
examples/extending-templates/views/users/user.html
Normal file
1
examples/extending-templates/views/users/user.html
Normal file
@@ -0,0 +1 @@
|
||||
<li><%= user.name %> <<%= user.email %>></li>
|
||||
@@ -5,21 +5,26 @@
|
||||
|
||||
var express = require('../../lib/express');
|
||||
|
||||
// $ npm install connect-redis
|
||||
var RedisStore = require('connect-redis');
|
||||
// pass the express to the connect redis module
|
||||
// allowing it to inherit from express.session.Store
|
||||
var RedisStore = require('connect-redis')(express);
|
||||
|
||||
var app = express.createServer(
|
||||
express.logger(),
|
||||
var app = express.createServer();
|
||||
|
||||
// Required by session() middleware
|
||||
express.cookieParser(),
|
||||
app.use(express.favicon());
|
||||
|
||||
// Populates:
|
||||
// - req.session
|
||||
// - req.sessionStore
|
||||
// - req.sessionID (or req.session.id)
|
||||
express.session({ secret: 'keyboard cat', store: new RedisStore })
|
||||
);
|
||||
// request logging
|
||||
app.use(express.logger());
|
||||
|
||||
// required to parse the session cookie
|
||||
app.use(express.cookieParser());
|
||||
|
||||
// Populates:
|
||||
// - req.session
|
||||
// - req.sessionStore
|
||||
// - req.sessionID (or req.session.id)
|
||||
|
||||
app.use(express.session({ secret: 'keyboard cat', store: new RedisStore }));
|
||||
|
||||
app.get('/', function(req, res){
|
||||
var body = '';
|
||||
|
||||
@@ -28,7 +28,7 @@ var exports = module.exports = connect.middleware;
|
||||
* Framework version.
|
||||
*/
|
||||
|
||||
exports.version = '2.4.0';
|
||||
exports.version = '2.4.3';
|
||||
|
||||
/**
|
||||
* Shortcut for `new Server(...)`.
|
||||
|
||||
28
lib/http.js
28
lib/http.js
@@ -471,17 +471,37 @@ app.redirect = function(key, url){
|
||||
};
|
||||
|
||||
/**
|
||||
* Configure callback for the given `env`.
|
||||
* 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.
|
||||
*
|
||||
* @param {String} env
|
||||
* 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
|
||||
* });
|
||||
*
|
||||
* @param {String} env...
|
||||
* @param {Function} fn
|
||||
* @return {Server} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.configure = function(env, fn){
|
||||
if ('function' == typeof env) fn = env, env = 'all';
|
||||
if ('all' == env || env == this.settings.env) fn.call(this);
|
||||
var envs = 'all'
|
||||
, args = toArray(arguments);
|
||||
fn = args.pop();
|
||||
if (args.length) envs = args;
|
||||
if ('all' == envs || ~envs.indexOf(this.settings.env)) fn.call(this);
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
@@ -75,16 +75,7 @@ res.send = function(body, headers, status){
|
||||
this.contentType('.bin');
|
||||
}
|
||||
} else {
|
||||
if (!this.header('Content-Type')) {
|
||||
this.charset = this.charset || 'utf-8';
|
||||
this.contentType('.json');
|
||||
}
|
||||
body = JSON.stringify(body);
|
||||
if (this.req.query.callback && this.app.set('jsonp callback')) {
|
||||
this.charset = this.charset || 'utf-8';
|
||||
this.header('Content-Type', 'text/javascript');
|
||||
body = this.req.query.callback.replace(/[^\w$.]/g, '') + '(' + body + ');';
|
||||
}
|
||||
return this.json(body, headers, status);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -135,9 +126,19 @@ res.send = function(body, headers, status){
|
||||
*/
|
||||
|
||||
res.json = function(obj, headers, status){
|
||||
var body = JSON.stringify(obj)
|
||||
, callback = this.req.query.callback
|
||||
, jsonp = this.app.enabled('jsonp callback');
|
||||
|
||||
this.charset = this.charset || 'utf-8';
|
||||
this.header('Content-Type', 'application/json');
|
||||
return this.send(JSON.stringify(obj), headers, status);
|
||||
|
||||
if (callback && jsonp) {
|
||||
this.header('Content-Type', 'text/javascript');
|
||||
body = callback.replace(/[^\w$.]/g, '') + '(' + body + ');';
|
||||
}
|
||||
|
||||
return this.send(body, headers, status);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -303,6 +304,7 @@ res.clearCookie = function(name, options){
|
||||
* Options:
|
||||
*
|
||||
* - `maxAge` max-age in milliseconds, converted to `expires`
|
||||
* - `path` defaults to the "home" setting which is typically "/"
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
@@ -321,6 +323,7 @@ res.clearCookie = function(name, options){
|
||||
res.cookie = function(name, val, options){
|
||||
options = options || {};
|
||||
if ('maxAge' in options) options.expires = new Date(Date.now() + options.maxAge);
|
||||
if (undefined === options.path) options.path = this.app.set('home');
|
||||
var cookie = utils.serializeCookie(name, val, options);
|
||||
this.header('Set-Cookie', cookie);
|
||||
};
|
||||
|
||||
@@ -373,6 +373,7 @@ Router.prototype._route = function(method, path, fn){
|
||||
// create the route
|
||||
var route = new Route(method, path, fn, {
|
||||
sensitive: app.enabled('case sensitive routes')
|
||||
, strict: app.enabled('strict routing')
|
||||
, middleware: middleware
|
||||
});
|
||||
|
||||
|
||||
@@ -17,7 +17,8 @@ module.exports = Route;
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - `sensitive` enable case-sensitive routes
|
||||
* - `sensitive` enable case-sensitive routes
|
||||
* - `strict` enable strict matching for trailing slashes
|
||||
* - `middleware` array of middleware
|
||||
*
|
||||
* @param {String} method
|
||||
@@ -32,8 +33,11 @@ function Route(method, path, fn, options) {
|
||||
this.callback = fn;
|
||||
this.path = path;
|
||||
this.method = method;
|
||||
this.regexp = normalize(path, this.keys = [], options.sensitive);
|
||||
this.middleware = options.middleware;
|
||||
this.regexp = normalize(path
|
||||
, this.keys = []
|
||||
, options.sensitive
|
||||
, options.strict);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -60,14 +64,15 @@ Route.prototype.match = function(path){
|
||||
* @param {String|RegExp} path
|
||||
* @param {Array} keys
|
||||
* @param {Boolean} sensitive
|
||||
* @param {Boolean} strict
|
||||
* @return {RegExp}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function normalize(path, keys, sensitive) {
|
||||
if (path instanceof RegExp) return path;
|
||||
function normalize(path, keys, sensitive, strict) {
|
||||
if (path instanceof RegExp) return path;
|
||||
path = path
|
||||
.concat('/?')
|
||||
.concat(strict ? '' : '/?')
|
||||
.replace(/\/\(/g, '(?:/')
|
||||
.replace(/(\/)?(\.)?:(\w+)(?:(\(.*?\)))?(\?)?/g, function(_, slash, format, key, capture, optional){
|
||||
keys.push({ name: key, optional: !! optional });
|
||||
|
||||
@@ -61,6 +61,7 @@ exports.compile = function(view, cache, cid, options){
|
||||
}
|
||||
|
||||
// compile
|
||||
options.filename = view.path;
|
||||
view.fn = view.templateEngine.compile(view.contents, options);
|
||||
cache[cid] = view;
|
||||
|
||||
@@ -318,8 +319,7 @@ res.render = function(view, opts, fn, parent, sub){
|
||||
// callback given
|
||||
if (fn) {
|
||||
fn(err);
|
||||
// unwind to root call to prevent
|
||||
// several next(err) calls
|
||||
// unwind to root call to prevent multiple callbacks
|
||||
} else if (sub) {
|
||||
throw err;
|
||||
// root template, next(err)
|
||||
@@ -414,7 +414,6 @@ res._render = function(view, opts, fn, parent, sub){
|
||||
// View lookup
|
||||
options.hint = app.enabled('hints');
|
||||
view = exports.compile(view, app.cache, cid, options);
|
||||
options.filename = view.path;
|
||||
|
||||
// layout helper
|
||||
options.layout = function(path){
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "express",
|
||||
"description": "Sinatra inspired web development framework",
|
||||
"version": "2.4.0",
|
||||
"version": "2.4.3",
|
||||
"author": "TJ Holowaychuk <tj@vision-media.ca>",
|
||||
"contributors": [
|
||||
{ "name": "TJ Holowaychuk", "email": "tj@vision-media.ca" },
|
||||
@@ -10,7 +10,7 @@
|
||||
{ "name": "Guillermo Rauch", "email": "rauchg@gmail.com" }
|
||||
],
|
||||
"dependencies": {
|
||||
"connect": ">= 1.5.1 < 2.0.0",
|
||||
"connect": ">= 1.5.2 < 2.0.0",
|
||||
"mime": ">= 0.0.1",
|
||||
"qs": ">= 0.0.6"
|
||||
},
|
||||
|
||||
@@ -236,7 +236,6 @@ module.exports = {
|
||||
var server = express.createServer();
|
||||
server.set('env', 'development');
|
||||
|
||||
// Config blocks
|
||||
var ret = server.configure(function(){
|
||||
assert.equal(this, server, 'Test context of configure() is the server');
|
||||
calls.push('any');
|
||||
@@ -297,7 +296,23 @@ module.exports = {
|
||||
{ url: '/' },
|
||||
{ body: 'first route last' });
|
||||
},
|
||||
|
||||
|
||||
'test #configure() multiple envs': function(){
|
||||
var app = express.createServer();
|
||||
app.set('env', 'prod');
|
||||
var calls = [];
|
||||
|
||||
app.configure('stage', 'prod', function(){
|
||||
calls.push('stage/prod');
|
||||
});
|
||||
|
||||
app.configure('prod', function(){
|
||||
calls.push('prod');
|
||||
});
|
||||
|
||||
calls.should.eql(['stage/prod', 'prod']);
|
||||
},
|
||||
|
||||
'test #set()': function(){
|
||||
var app = express.createServer();
|
||||
var ret = app.set('title', 'My App').set('something', 'else');
|
||||
|
||||
@@ -72,13 +72,6 @@ module.exports = {
|
||||
res.send({ foo: 'bar' }, { 'X-Foo': 'baz' }, 201);
|
||||
});
|
||||
|
||||
app.get('/jsonp', function(req, res){
|
||||
app.enable('jsonp callback');
|
||||
res.header('X-Foo', 'bar');
|
||||
res.send({ foo: 'bar' }, { 'X-Foo': 'baz' }, 201);
|
||||
app.disable('jsonp callback');
|
||||
});
|
||||
|
||||
app.get('/text', function(req, res){
|
||||
res.header('X-Foo', 'bar');
|
||||
res.contentType('txt');
|
||||
@@ -135,41 +128,6 @@ module.exports = {
|
||||
, 'X-Foo': 'baz'
|
||||
}});
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/jsonp?callback=test' },
|
||||
{ body: 'test({"foo":"bar"});'
|
||||
, status: 201
|
||||
, headers: {
|
||||
'Content-Type': 'text/javascript; charset=utf-8'
|
||||
, 'X-Foo': 'baz'
|
||||
}});
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/jsonp?callback=baz' },
|
||||
{ body: 'baz({"foo":"bar"});'
|
||||
, status: 201, headers: {
|
||||
'Content-Type': 'text/javascript; charset=utf-8'
|
||||
, 'X-Foo': 'baz'
|
||||
}});
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/jsonp?callback=invalid()[]' },
|
||||
{ body: 'invalid({"foo":"bar"});'
|
||||
, status: 201
|
||||
, headers: {
|
||||
'Content-Type': 'text/javascript; charset=utf-8'
|
||||
, 'X-Foo': 'baz'
|
||||
}});
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/json?callback=test' },
|
||||
{ body: '{"foo":"bar"}'
|
||||
, status: 201
|
||||
, headers: {
|
||||
'Content-Type': 'application/json; charset=utf-8'
|
||||
, 'X-Foo': 'baz'
|
||||
}});
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/text' },
|
||||
{ body: 'wahoo'
|
||||
@@ -218,8 +176,91 @@ module.exports = {
|
||||
assert.equal(undefined, res.headers['content-type']);
|
||||
assert.equal(undefined, res.headers['content-length']);
|
||||
});
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/json?callback=test' },
|
||||
{ body: '{"foo":"bar"}'
|
||||
, status: 201
|
||||
, headers: {
|
||||
'Content-Type': 'application/json; charset=utf-8'
|
||||
, 'X-Foo': 'baz'
|
||||
}});
|
||||
},
|
||||
|
||||
'test #send() JSONP': function(){
|
||||
var app = express.createServer();
|
||||
|
||||
app.enable('jsonp callback');
|
||||
|
||||
app.get('/jsonp', function(req, res){
|
||||
res.header('X-Foo', 'bar');
|
||||
res.send({ foo: 'bar' }, { 'X-Foo': 'baz' }, 201);
|
||||
});
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/jsonp?callback=test' },
|
||||
{ body: 'test({"foo":"bar"});'
|
||||
, status: 201
|
||||
, headers: {
|
||||
'Content-Type': 'text/javascript; charset=utf-8'
|
||||
, 'X-Foo': 'baz'
|
||||
}});
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/jsonp?callback=baz' },
|
||||
{ body: 'baz({"foo":"bar"});'
|
||||
, status: 201, headers: {
|
||||
'Content-Type': 'text/javascript; charset=utf-8'
|
||||
, 'X-Foo': 'baz'
|
||||
}});
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/jsonp?callback=invalid()[]' },
|
||||
{ body: 'invalid({"foo":"bar"});'
|
||||
, status: 201
|
||||
, headers: {
|
||||
'Content-Type': 'text/javascript; charset=utf-8'
|
||||
, 'X-Foo': 'baz'
|
||||
}});
|
||||
},
|
||||
|
||||
'test #json() JSONP': function(){
|
||||
var app = express.createServer();
|
||||
|
||||
app.enable('jsonp callback');
|
||||
|
||||
app.get('/jsonp', function(req, res){
|
||||
res.header('X-Foo', 'bar');
|
||||
res.json({ foo: 'bar' }, { 'X-Foo': 'baz' }, 201);
|
||||
});
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/jsonp?callback=test' },
|
||||
{ body: 'test({"foo":"bar"});'
|
||||
, status: 201
|
||||
, headers: {
|
||||
'Content-Type': 'text/javascript; charset=utf-8'
|
||||
, 'X-Foo': 'baz'
|
||||
}});
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/jsonp?callback=baz' },
|
||||
{ body: 'baz({"foo":"bar"});'
|
||||
, status: 201, headers: {
|
||||
'Content-Type': 'text/javascript; charset=utf-8'
|
||||
, 'X-Foo': 'baz'
|
||||
}});
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/jsonp?callback=invalid()[]' },
|
||||
{ body: 'invalid({"foo":"bar"});'
|
||||
, status: 201
|
||||
, headers: {
|
||||
'Content-Type': 'text/javascript; charset=utf-8'
|
||||
, 'X-Foo': 'baz'
|
||||
}});
|
||||
},
|
||||
|
||||
'test #contentType()': function(){
|
||||
var app = express.createServer();
|
||||
|
||||
@@ -612,15 +653,55 @@ module.exports = {
|
||||
});
|
||||
},
|
||||
|
||||
'test #cookie()': function(){
|
||||
'test #cookie() path default': function(){
|
||||
var app = express.createServer();
|
||||
|
||||
|
||||
app.set('home', '/foo');
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.cookie('rememberme', 'yes', { expires: new Date(1), httpOnly: true });
|
||||
res.cookie('something', 'else');
|
||||
res.redirect('/');
|
||||
});
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/', headers: { Host: 'foo.com' }},
|
||||
function(res){
|
||||
res.headers['set-cookie']
|
||||
.should.eql(['rememberme=yes; path=/foo; expires=Thu, 01 Jan 1970 00:00:00 GMT; httpOnly', 'something=else; path=/foo']);
|
||||
});
|
||||
},
|
||||
|
||||
'test #cookie() explicit path': function(){
|
||||
var app = express.createServer();
|
||||
|
||||
app.set('/home', '/foo');
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.cookie('rememberme', 'yes', { path: '/', expires: new Date(1), httpOnly: true });
|
||||
res.cookie('something', 'else');
|
||||
res.redirect('/');
|
||||
});
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/', headers: { Host: 'foo.com' }},
|
||||
function(res){
|
||||
res.headers['set-cookie']
|
||||
.should.eql(['rememberme=yes; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT; httpOnly', 'something=else; path=/']);
|
||||
});
|
||||
},
|
||||
|
||||
'test #cookie() null path': function(){
|
||||
var app = express.createServer();
|
||||
|
||||
app.set('/home', '/foo');
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.cookie('rememberme', 'yes', { path: null, expires: new Date(1), httpOnly: true });
|
||||
res.cookie('something', 'else', { path: null });
|
||||
res.redirect('/');
|
||||
});
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/', headers: { Host: 'foo.com' }},
|
||||
function(res){
|
||||
@@ -628,10 +709,30 @@ module.exports = {
|
||||
.should.eql(['rememberme=yes; expires=Thu, 01 Jan 1970 00:00:00 GMT; httpOnly', 'something=else']);
|
||||
});
|
||||
},
|
||||
|
||||
'test #clearCookie()': function(){
|
||||
|
||||
'test #clearCookie() default path': function(){
|
||||
var app = express.createServer();
|
||||
|
||||
app.set('home', '/foo');
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.clearCookie('rememberme');
|
||||
res.redirect('/');
|
||||
});
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/' },
|
||||
function(res){
|
||||
res.headers['set-cookie']
|
||||
.should.eql(['rememberme=; path=/foo; expires=Thu, 01 Jan 1970 00:00:00 GMT']);
|
||||
});
|
||||
},
|
||||
|
||||
'test #clearCookie() explicit path': function(){
|
||||
var app = express.createServer();
|
||||
|
||||
app.set('home', '/bar');
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.clearCookie('rememberme', { path: '/foo' });
|
||||
res.redirect('/');
|
||||
@@ -644,7 +745,7 @@ module.exports = {
|
||||
.should.eql(['rememberme=; path=/foo; expires=Thu, 01 Jan 1970 00:00:00 GMT']);
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
'test HEAD': function(){
|
||||
var app = express.createServer();
|
||||
|
||||
|
||||
@@ -317,7 +317,29 @@ module.exports = {
|
||||
app.match.all('/user/12').should.have.length(0);
|
||||
app.get('/user/:id').should.have.length(0);
|
||||
},
|
||||
|
||||
|
||||
'test "strict routing" setting': function(){
|
||||
var app = express.createServer();
|
||||
|
||||
app.enable('strict routing');
|
||||
|
||||
app.get('/:path', function(req, res, next){
|
||||
res.send({ type: 'directory' });
|
||||
});
|
||||
|
||||
app.get('/:path/', function(req, res, next){
|
||||
res.send(['.', '..', 'foo.js', 'bar.js']);
|
||||
});
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/lib' },
|
||||
{ body: '{"type":"directory"}' });
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/lib/' },
|
||||
{ body: '[".","..","foo.js","bar.js"]' });
|
||||
},
|
||||
|
||||
'test "case sensitive routes" setting': function(){
|
||||
var app = express.createServer();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user