Compare commits

...

76 Commits

Author SHA1 Message Date
Douglas Christopher Wilson
86328767fe 3.19.2 2015-02-01 15:15:53 -05:00
Douglas Christopher Wilson
e497d068a1 deps: marked@0.3.3 2015-02-01 14:58:19 -05:00
Douglas Christopher Wilson
926a71f5ac deps: should@~4.6.2 2015-02-01 14:56:18 -05:00
Douglas Christopher Wilson
55f5a2dc8d deps: proxy-addr@~1.0.6 2015-02-01 14:55:42 -05:00
Douglas Christopher Wilson
fe435e497e deps: connect@2.28.3 2015-02-01 14:54:46 -05:00
Douglas Christopher Wilson
0c567b3282 3.19.1 2015-01-21 03:18:16 -05:00
Douglas Christopher Wilson
855176b633 tests: remove more mocking uses 2015-01-21 03:17:30 -05:00
Douglas Christopher Wilson
b95f2ee820 deps: should@~4.6.1 2015-01-21 02:14:27 -05:00
Douglas Christopher Wilson
ae92db98f3 deps: ejs@2.1.4 2015-01-21 02:13:17 -05:00
Douglas Christopher Wilson
0b25547ca0 deps: send@0.11.1 2015-01-21 02:05:03 -05:00
Douglas Christopher Wilson
548f2865e2 deps: connect@2.28.2 2015-01-21 02:03:28 -05:00
Douglas Christopher Wilson
ee3f2b073c 3.19.0 2015-01-09 01:07:12 -05:00
Douglas Christopher Wilson
34b6385dc3 deps: debug@~2.1.1 2015-01-09 01:05:41 -05:00
Douglas Christopher Wilson
11529a2ea0 Fix OPTIONS responses to include the HEAD method property
fixes #2459
2015-01-08 23:30:42 -05:00
Douglas Christopher Wilson
b0f8809e3d deps: commander@2.6.0 2015-01-08 22:23:04 -05:00
Douglas Christopher Wilson
ec1175daa3 Use readline for prompt in express(1) 2015-01-08 22:21:50 -05:00
Douglas Christopher Wilson
3a1d9b8289 deps: ejs@2.0.8 2015-01-08 22:17:19 -05:00
Douglas Christopher Wilson
192be8fea3 deps: send@0.11.0 2015-01-08 22:15:53 -05:00
Douglas Christopher Wilson
1afcff955b deps: proxy-addr@~1.0.5 2015-01-08 22:14:46 -05:00
Douglas Christopher Wilson
224fe05697 deps: methods@~1.1.1 2015-01-08 21:31:32 -05:00
Douglas Christopher Wilson
2dd332b491 deps: mocha@~2.1.0 2015-01-08 21:25:17 -05:00
Douglas Christopher Wilson
33e4193f45 deps: should@~4.4.4 2015-01-08 21:24:28 -05:00
Douglas Christopher Wilson
c163d2f33d deps: connect@2.28.1 2015-01-08 21:18:56 -05:00
Douglas Christopher Wilson
a715ba6be4 docs: Gittip is now Gratipay 2015-01-08 17:06:08 -05:00
Douglas Christopher Wilson
4405b849a9 3.18.6 2014-12-12 21:39:47 -05:00
Troy Goode
5d74a553d6 Fix exception in req.fresh/req.stale without response headers
fixes #2468
2014-12-12 21:17:23 -05:00
Douglas Christopher Wilson
262b60537f 3.18.5 2014-12-11 23:10:34 -05:00
Douglas Christopher Wilson
e77e644224 deps: should@~4.3.1 2014-12-11 23:03:01 -05:00
Douglas Christopher Wilson
ce89c00cd9 deps: istanbul@0.3.5 2014-12-11 23:01:12 -05:00
Douglas Christopher Wilson
d5ad34b0e9 deps: connect@2.27.6 2014-12-10 22:55:36 -05:00
Douglas Christopher Wilson
ebfa00a9c0 build: remove support folder 2014-11-29 12:10:30 -05:00
Douglas Christopher Wilson
d23417e6e8 examples: switch examples used in tests to ejs engine 2014-11-29 12:09:00 -05:00
Douglas Christopher Wilson
91824514ce tests: run render tests with internal template engine 2014-11-28 09:10:44 -05:00
Douglas Christopher Wilson
6c8bcd5c4e 3.18.4 2014-11-23 15:42:03 -05:00
Douglas Christopher Wilson
95e63ec287 deps: should@~4.3.0 2014-11-23 15:36:59 -05:00
Douglas Christopher Wilson
ebca5887cc deps: proxy-addr@~1.0.4 2014-11-23 15:34:57 -05:00
Douglas Christopher Wilson
8535d3a990 deps: supertest@~0.15.0 2014-11-23 14:58:56 -05:00
Douglas Christopher Wilson
13184c4379 deps: etag@~1.5.1 2014-11-23 14:58:22 -05:00
Douglas Christopher Wilson
eaba4eeb70 deps: connect@2.27.4 2014-11-23 14:53:23 -05:00
Douglas Christopher Wilson
28c6952d1c 3.18.3 2014-11-09 18:35:34 -05:00
Douglas Christopher Wilson
01e3530a31 deps: should@~4.2.1 2014-11-09 18:33:17 -05:00
Douglas Christopher Wilson
77c83d0c57 deps: connect@2.27.3 2014-11-09 18:32:43 -05:00
Douglas Christopher Wilson
a12ae729bd 3.18.2 2014-10-29 01:10:45 -04:00
Douglas Christopher Wilson
d53a0cd91e deps: connect@2.27.2 2014-10-29 01:08:36 -04:00
Douglas Christopher Wilson
88dfd36eaa 3.18.1 2014-10-23 01:26:21 -04:00
Douglas Christopher Wilson
5759b3e9f5 deps: send@0.10.1 2014-10-23 01:25:07 -04:00
Douglas Christopher Wilson
c939a771c0 deps: connect@2.27.1 2014-10-23 01:23:54 -04:00
Douglas Christopher Wilson
af1043844f Fix internal utils.merge deprecation warnings 2014-10-22 15:18:10 -04:00
Douglas Christopher Wilson
dd763ec5b8 deps: should@~4.1.0 2014-10-22 15:10:22 -04:00
Douglas Christopher Wilson
9c2c21aaaf deps: mocha@~2.0.0 2014-10-22 15:08:49 -04:00
Douglas Christopher Wilson
366000184f 3.18.0 2014-10-18 00:57:48 -04:00
Douglas Christopher Wilson
4d1ee23f84 Use etag module to generate ETag headers 2014-10-18 00:53:17 -04:00
Douglas Christopher Wilson
0e5613363f Use content-disposition module 2014-10-17 21:08:05 -04:00
Fishrock123
7a7f18c20b build: misc. updates to packaging
closes #2398
2014-10-17 20:49:56 -04:00
Douglas Christopher Wilson
b766aad112 deps: jade@~1.7.0 2014-10-17 20:45:57 -04:00
Douglas Christopher Wilson
7488e27609 deps: send@0.10.0 2014-10-17 20:45:09 -04:00
Douglas Christopher Wilson
bc9d854763 deps: depd@~1.0.0 2014-10-17 20:44:07 -04:00
Douglas Christopher Wilson
2e20a85810 deps: debug@~2.1.0 2014-10-17 20:43:23 -04:00
Douglas Christopher Wilson
a706408208 deps: connect@2.27.0 2014-10-17 20:42:12 -04:00
Douglas Christopher Wilson
6d39d0f8a8 3.17.8 2014-10-16 00:29:56 -04:00
Douglas Christopher Wilson
159ea67713 deps: connect@2.26.6 2014-10-16 00:24:28 -04:00
Douglas Christopher Wilson
33959ed350 deps: mocha@~1.21.5 2014-10-16 00:19:47 -04:00
Bessie Chan
be478d348c Fix typo in res.redirect deprecation
closes #2395
2014-10-11 18:11:22 -04:00
Douglas Christopher Wilson
9f292d873e 3.17.7 2014-10-08 17:00:45 -04:00
Douglas Christopher Wilson
ef3e95ca73 deps: supertest@~0.14.0 2014-10-08 16:44:29 -04:00
Douglas Christopher Wilson
f45bd632df deps: connect@2.26.5 2014-10-08 16:43:02 -04:00
Douglas Christopher Wilson
cc18da5cdf 3.17.6 2014-10-02 23:29:40 -04:00
Douglas Christopher Wilson
5603f86edd deps: connect@2.26.4 2014-10-02 23:27:41 -04:00
Douglas Christopher Wilson
43e2cd79cb 3.17.5 2014-09-24 19:38:35 -04:00
Douglas Christopher Wilson
653270bb43 deps: send@0.9.3 2014-09-24 19:15:46 -04:00
Douglas Christopher Wilson
734bdf5ca1 deps: proxy-addr@~1.0.3 2014-09-24 19:14:33 -04:00
Douglas Christopher Wilson
341c1919d9 deps: connect@2.26.3 2014-09-24 19:12:43 -04:00
Douglas Christopher Wilson
b09afad7b1 3.17.4 2014-09-19 22:57:07 -07:00
Douglas Christopher Wilson
0e0b259556 deps: connect@2.26.2 2014-09-19 22:54:39 -07:00
Douglas Christopher Wilson
63286e1192 3.17.3 2014-09-18 10:38:31 -07:00
Douglas Christopher Wilson
c00f2f8596 deps: proxy-addr@~1.0.2 2014-09-18 10:36:21 -07:00
52 changed files with 714 additions and 411 deletions

38
.gitignore vendored
View File

@@ -1,16 +1,26 @@
coverage/
.DS_Store
*.seed
# OS X
.DS_Store*
Icon?
._*
# Windows
Thumbs.db
ehthumbs.db
Desktop.ini
# Linux
.directory
*~
# npm
node_modules
*.log
*.csv
*.dat
*.out
*.pid
*.swp
*.swo
*.gz
# Coveralls
coverage
# Benchmarking
benchmarks/graphs
testing
node_modules/
testing
test.js
.idea

View File

@@ -1,10 +0,0 @@
.git*
benchmarks/
coverage/
docs/
examples/
support/
test/
testing.js
.DS_Store
.travis.yml

View File

@@ -1,3 +1,195 @@
3.19.2 / 2015-02-01
===================
* deps: connect@2.28.3
- deps: compression@~1.3.1
- deps: csurf@~1.6.6
- deps: errorhandler@~1.3.3
- deps: express-session@~1.10.2
- deps: serve-index@~1.6.1
- deps: type-is@~1.5.6
* deps: proxy-addr@~1.0.6
- deps: ipaddr.js@0.1.8
3.19.1 / 2015-01-20
===================
* deps: connect@2.28.2
- deps: body-parser@~1.10.2
- deps: serve-static@~1.8.1
* deps: send@0.11.1
- Fix root path disclosure
3.19.0 / 2015-01-09
===================
* Fix `OPTIONS` responses to include the `HEAD` method property
* Use `readline` for prompt in `express(1)`
* deps: commander@2.6.0
* deps: connect@2.28.1
- deps: body-parser@~1.10.1
- deps: compression@~1.3.0
- deps: connect-timeout@~1.5.0
- deps: csurf@~1.6.4
- deps: debug@~2.1.1
- deps: errorhandler@~1.3.2
- deps: express-session@~1.10.1
- deps: finalhandler@0.3.3
- deps: method-override@~2.3.1
- deps: morgan@~1.5.1
- deps: serve-favicon@~2.2.0
- deps: serve-index@~1.6.0
- deps: serve-static@~1.8.0
- deps: type-is@~1.5.5
* deps: debug@~2.1.1
* deps: methods@~1.1.1
* deps: proxy-addr@~1.0.5
- deps: ipaddr.js@0.1.6
* deps: send@0.11.0
- deps: debug@~2.1.1
- deps: etag@~1.5.1
- deps: ms@0.7.0
- deps: on-finished@~2.2.0
3.18.6 / 2014-12-12
===================
* Fix exception in `req.fresh`/`req.stale` without response headers
3.18.5 / 2014-12-11
===================
* deps: connect@2.27.6
- deps: compression@~1.2.2
- deps: express-session@~1.9.3
- deps: http-errors@~1.2.8
- deps: serve-index@~1.5.3
- deps: type-is@~1.5.4
3.18.4 / 2014-11-23
===================
* deps: connect@2.27.4
- deps: body-parser@~1.9.3
- deps: compression@~1.2.1
- deps: errorhandler@~1.2.3
- deps: express-session@~1.9.2
- deps: qs@2.3.3
- deps: serve-favicon@~2.1.7
- deps: serve-static@~1.5.1
- deps: type-is@~1.5.3
* deps: etag@~1.5.1
* deps: proxy-addr@~1.0.4
- deps: ipaddr.js@0.1.5
3.18.3 / 2014-11-09
===================
* deps: connect@2.27.3
- Correctly invoke async callback asynchronously
- deps: csurf@~1.6.3
3.18.2 / 2014-10-28
===================
* deps: connect@2.27.2
- Fix handling of URLs containing `://` in the path
- deps: body-parser@~1.9.2
- deps: qs@2.3.2
3.18.1 / 2014-10-22
===================
* Fix internal `utils.merge` deprecation warnings
* deps: connect@2.27.1
- deps: body-parser@~1.9.1
- deps: express-session@~1.9.1
- deps: finalhandler@0.3.2
- deps: morgan@~1.4.1
- deps: qs@2.3.0
- deps: serve-static@~1.7.1
* deps: send@0.10.1
- deps: on-finished@~2.1.1
3.18.0 / 2014-10-17
===================
* Use `content-disposition` module for `res.attachment`/`res.download`
- Sends standards-compliant `Content-Disposition` header
- Full Unicode support
* Use `etag` module to generate `ETag` headers
* deps: connect@2.27.0
- Use `http-errors` module for creating errors
- Use `utils-merge` module for merging objects
- deps: body-parser@~1.9.0
- deps: compression@~1.2.0
- deps: connect-timeout@~1.4.0
- deps: debug@~2.1.0
- deps: depd@~1.0.0
- deps: express-session@~1.9.0
- deps: finalhandler@0.3.1
- deps: method-override@~2.3.0
- deps: morgan@~1.4.0
- deps: response-time@~2.2.0
- deps: serve-favicon@~2.1.6
- deps: serve-index@~1.5.0
- deps: serve-static@~1.7.0
* deps: debug@~2.1.0
- Implement `DEBUG_FD` env variable support
* deps: depd@~1.0.0
* deps: send@0.10.0
- deps: debug@~2.1.0
- deps: depd@~1.0.0
- deps: etag@~1.5.0
3.17.8 / 2014-10-15
===================
* deps: connect@2.26.6
- deps: compression@~1.1.2
- deps: csurf@~1.6.2
- deps: errorhandler@~1.2.2
3.17.7 / 2014-10-08
===================
* deps: connect@2.26.5
- Fix accepting non-object arguments to `logger`
- deps: serve-static@~1.6.4
3.17.6 / 2014-10-02
===================
* deps: connect@2.26.4
- deps: morgan@~1.3.2
- deps: type-is@~1.5.2
3.17.5 / 2014-09-24
===================
* deps: connect@2.26.3
- deps: body-parser@~1.8.4
- deps: serve-favicon@~2.1.5
- deps: serve-static@~1.6.3
* deps: proxy-addr@~1.0.3
- Use `forwarded` npm module
* deps: send@0.9.3
- deps: etag@~1.4.0
3.17.4 / 2014-09-19
===================
* deps: connect@2.26.2
- deps: body-parser@~1.8.3
- deps: qs@2.2.4
3.17.3 / 2014-09-18
===================
* deps: proxy-addr@~1.0.2
- Fix a global leak when multiple subnets are trusted
- deps: ipaddr.js@0.1.3
3.17.2 / 2014-09-15
===================

View File

@@ -5,7 +5,7 @@
[![NPM version](https://img.shields.io/npm/v/express.svg?style=flat)](https://www.npmjs.org/package/express)
[![Build Status](https://img.shields.io/travis/strongloop/express.svg?style=flat)](https://travis-ci.org/strongloop/express)
[![Coverage Status](https://img.shields.io/coveralls/strongloop/express.svg?style=flat)](https://coveralls.io/r/strongloop/express)
[![Gittip](https://img.shields.io/gittip/dougwilson.svg?style=flat)](https://www.gittip.com/dougwilson/)
[![Gratipay](https://img.shields.io/gratipay/dougwilson.svg?style=flat)](https://gratipay.com/dougwilson/)
```js
var express = require('express');

View File

@@ -7,6 +7,7 @@
var program = require('commander')
, mkdirp = require('mkdirp')
, pkg = require('../package.json')
, readline = require('readline')
, version = pkg.version
, os = require('os')
, fs = require('fs');
@@ -249,7 +250,7 @@ var app = [
if (empty || program.force) {
createApplicationAt(path);
} else {
program.confirm('destination is not empty, continue? ', function(ok){
confirm('destination is not empty, continue? [y/N] ', function (ok) {
if (ok) {
process.stdin.destroy();
createApplicationAt(path);
@@ -261,6 +262,22 @@ var app = [
});
})(path);
/**
* Prompt for confirmation on STDOUT/STDIN
*/
function confirm(msg, callback) {
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question(msg, function (input) {
rl.close();
callback(/^y|yes|ok|true$/i.test(input));
});
}
/**
* Create application at the given directory `path`.
*

View File

@@ -8,7 +8,7 @@ var express = require('../../')
// general config
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.set('view engine', 'ejs');
// our custom "verbose errors" setting
// which we can use in the templates
@@ -82,7 +82,7 @@ app.use(function(err, req, res, next){
// Routes
app.get('/', function(req, res){
res.render('index.jade');
res.render('index.ejs');
});
app.get('/404', function(req, res, next){

View File

@@ -0,0 +1,3 @@
<% include error_header %>
<h2>Cannot find <%= url %></h2>
<% include footer %>

View File

@@ -1,5 +0,0 @@
extends error
block content
h2 Cannot find #{url}

View File

@@ -0,0 +1,8 @@
<% include error_header %>
<h2>Error: <%= error.message %></h2>
<% if (settings['verbose errors']) { %>
<pre><%= error.stack %></pre>
<% } else { %>
<p>An error occurred!</p>
<% } %>
<% include footer %>

View File

@@ -1,13 +0,0 @@
// note that we extend a different
// layout with jade for 4xx & 5xx
// responses
extends error
block content
h1 Error: #{error.message}
if settings['verbose errors']
pre= error.stack
else
p An error ocurred!

View File

@@ -1,6 +0,0 @@
html
head
title Error
body
h1 An error occurred!
block content

View File

@@ -0,0 +1,8 @@
<!DOCTYPE html>
<html>
<head>
<title>Error</title>
</head>
<body>
<h1>An error occurred!</h1>

View File

@@ -0,0 +1,2 @@
</body>
</html>

View File

@@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<head>
<title>Custom Pages Example</title>
</head>
<body>
<h1>My Site</h1>
<h2>Pages Example</h2>
<ul>
<li>visit <a href="/500">500</a></li>
<li>visit <a href="/404">404</a></li>
<li>visit <a href="/403">403</a></li>
</ul>
</body>
</html>

View File

@@ -1,15 +0,0 @@
extends layout
block content
h2 Pages Example
ul
li
| visit
a(href="/500") 500
li
| visit
a(href="/404") 404
li
| visit
a(href='/403') 403

View File

@@ -1,6 +0,0 @@
html
head
title Custom Pages Example
body
h1 My Site
block content

View File

@@ -1,7 +1,7 @@
var db = require('../../db');
exports.engine = 'jade';
exports.engine = 'ejs';
exports.before = function(req, res, next){
var pet = db.pets[req.params.pet_id];

View File

@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Edit <%= pet.name %></title>
</head>
<body>
<h1><%= pet.name %></h1>
<form action="/pet/<%= pet.id %>" method="post">
<input type="hidden" name="_method" value="put">
<label>Name: <input type="text" name="user[name]" value="<%= pet.name %>"></label>
<input type="submit" value="Update">
</form>
</body>
</html>

View File

@@ -1,7 +0,0 @@
link(rel='stylesheet', href='/style.css')
h1= pet.name
form(action='/pet/#{pet.id}', method='post')
input(type='hidden', name='_method', value='put')
label Name:
input(type='text', name='user[name]', value=pet.name)
input(type='submit', value='Update')

View File

@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title><%= pet.name %></title>
</head>
<body>
<h1><%= pet.name %> <a href="/pet/<%= pet.id %>/edit">edit</a></h1>
<p>You are viewing <%= pet.name %></p>
</body>
</html>

View File

@@ -1,6 +0,0 @@
link(rel='stylesheet', href='/style.css')
h1= pet.name
a(href='/pet/#{pet.id}/edit') edit
p You are viewing #{pet.name}

View File

@@ -11,9 +11,9 @@ var connect = require('connect')
, compileETag = require('./utils').compileETag
, compileTrust = require('./utils').compileTrust
, View = require('./view')
, utils = connect.utils
, http = require('http');
var deprecate = require('depd')('express');
var merge = require('utils-merge');
/**
* Application prototype.
@@ -484,13 +484,15 @@ app.render = function(name, options, fn){
}
// merge app.locals
utils.merge(opts, this.locals);
merge(opts, this.locals);
// merge options._locals
if (options._locals) utils.merge(opts, options._locals);
if (options._locals) {
merge(opts, options._locals);
}
// merge options
utils.merge(opts, options);
merge(opts, options);
// set .cache unless explicitly provided
opts.cache = null == opts.cache

View File

@@ -3,14 +3,14 @@
*/
var deprecate = require('depd')('express');
var merge = require('merge-descriptors');
var mixin = require('merge-descriptors');
var merge = require('utils-merge');
var connect = require('connect')
, proto = require('./application')
, Route = require('./router/route')
, Router = require('./router')
, req = require('./request')
, res = require('./response')
, utils = connect.utils;
, res = require('./response');
/**
* Expose `createApplication()`.
@@ -33,7 +33,7 @@ exports.mime = connect.mime;
function createApplication() {
var app = connect();
utils.merge(app, proto);
merge(app, proto);
app.request = { __proto__: req, app: app };
app.response = { __proto__: res, app: app };
app.init();
@@ -45,7 +45,7 @@ function createApplication() {
* for example `express.logger` etc.
*/
merge(exports, connect.middleware);
mixin(exports, connect.middleware);
/**
* Deprecated createServer().

View File

@@ -526,7 +526,7 @@ req.__defineGetter__('fresh', function(){
// 2xx or 304 as per rfc2616 14.26
if ((s >= 200 && s < 300) || 304 == s) {
return fresh(this.headers, this.res._headers);
return fresh(this.headers, (this.res._headers || {}));
}
return false;

View File

@@ -2,14 +2,15 @@
* Module dependencies.
*/
var contentDisposition = require('content-disposition');
var deprecate = require('depd')('express');
var escapeHtml = require('escape-html');
var merge = require('utils-merge');
var parseUrl = require('parseurl');
var vary = require('vary');
var http = require('http')
, path = require('path')
, connect = require('connect')
, utils = connect.utils
, sign = require('cookie-signature').sign
, normalizeType = require('./utils').normalizeType
, normalizeTypes = require('./utils').normalizeTypes
@@ -413,15 +414,17 @@ res.sendfile = function(path, options, fn){
* @api public
*/
res.download = function(path, filename, fn){
res.download = function download(path, filename, fn) {
// support function as second arg
if ('function' == typeof filename) {
if (typeof filename === 'function') {
fn = filename;
filename = null;
}
filename = filename || path;
this.set('Content-Disposition', 'attachment; filename="' + basename(filename) + '"');
this.set('Content-Disposition', contentDisposition(filename));
return this.sendfile(path, fn);
};
@@ -544,11 +547,13 @@ res.format = function(obj){
* @api public
*/
res.attachment = function(filename){
if (filename) this.type(extname(filename));
this.set('Content-Disposition', filename
? 'attachment; filename="' + basename(filename) + '"'
: 'attachment');
res.attachment = function attachment(filename) {
if (filename) {
this.type(extname(filename));
}
this.set('Content-Disposition', contentDisposition(filename));
return this;
};
@@ -608,7 +613,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)
? merge(opts, options)
: opts);
};
@@ -636,7 +641,7 @@ res.clearCookie = function(name, options){
*/
res.cookie = function(name, val, options){
options = utils.merge({}, options);
options = merge({}, options);
var secret = this.req.secret;
var signed = options.signed;
if (signed && !secret) throw new Error('connect.cookieParser("secret") required for signed cookies');
@@ -738,7 +743,7 @@ res.redirect = function(url){
status = url;
url = arguments[1];
} else {
deprecate('res.redirect(ur, status): Use res.redirect(status, url) instead');
deprecate('res.redirect(url, status): Use res.redirect(status, url) instead');
status = arguments[1];
}
}

View File

@@ -196,17 +196,32 @@ Router.prototype._options = function(req, res, next){
* @api private
*/
Router.prototype._optionsFor = function(path){
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;
Router.prototype._optionsFor = function _optionsFor(path) {
var options = [];
for (var i = 0; i < methods.length; i++) {
var method = methods[i];
if (method === 'options') continue;
var routes = this.map[method];
// HEAD methods include GET routes
if (!routes && method === 'head') {
routes = this.map.get;
}
}).map(function(method){
return method.toUpperCase();
});
if (!routes) continue;
for (var j = 0; j < routes.length; j++) {
if (routes[j].match(path)) {
options.push(method.toUpperCase());
break;
}
}
}
return options.sort();
};
/**

View File

@@ -3,10 +3,9 @@
* Module dependencies.
*/
var crc = require('crc').crc32;
var mime = require('connect').mime
, proxyaddr = require('proxy-addr')
, crypto = require('crypto');
var etag = require('etag');
var mime = require('connect').mime;
var proxyaddr = require('proxy-addr');
var typer = require('media-typer');
/**
@@ -24,17 +23,12 @@ var toString = {}.toString;
* @api private
*/
exports.etag = function etag(body, encoding){
if (body.length === 0) {
// fast-path empty body
return '"1B2M2Y8AsgTpgAmY7PhCfg=="'
}
exports.etag = function (body, encoding) {
var buf = !Buffer.isBuffer(body)
? new Buffer(body, encoding)
: body;
var hash = crypto
.createHash('md5')
.update(body, encoding)
.digest('base64')
return '"' + hash + '"'
return etag(buf, {weak: false});
};
/**
@@ -47,16 +41,11 @@ exports.etag = function etag(body, encoding){
*/
exports.wetag = function wetag(body, encoding){
if (body.length === 0) {
// fast-path empty body
return 'W/"0-0"'
}
var buf = !Buffer.isBuffer(body)
? new Buffer(body, encoding)
: body;
var buf = Buffer.isBuffer(body)
? body
: new Buffer(body, encoding)
var len = buf.length
return 'W/"' + len.toString(16) + '-' + crc(buf) + '"'
return etag(buf, {weak: true});
};
/**

View File

@@ -1,7 +1,7 @@
{
"name": "express",
"description": "Sinatra inspired web development framework",
"version": "3.17.2",
"version": "3.19.2",
"author": "TJ Holowaychuk <tj@vision-media.ca>",
"contributors": [
"Aaron Heckmann <aaron.heckmann+github@gmail.com>",
@@ -11,6 +11,9 @@
"Jonathan Ong <me@jongleberry.com>",
"Roman Shtylman <shtylman+expressjs@gmail.com"
],
"license": "MIT",
"repository": "strongloop/express",
"homepage": "http://expressjs.com/",
"keywords": [
"express",
"framework",
@@ -22,40 +25,38 @@
"app",
"api"
],
"repository": "strongloop/express",
"license": "MIT",
"homepage": "http://expressjs.com/",
"dependencies": {
"basic-auth": "1.0.0",
"connect": "2.26.1",
"commander": "1.3.2",
"connect": "2.28.3",
"content-disposition": "0.5.0",
"commander": "2.6.0",
"cookie-signature": "1.0.5",
"crc": "3.0.0",
"debug": "~2.0.0",
"depd": "0.4.5",
"debug": "~2.1.1",
"depd": "~1.0.0",
"escape-html": "1.0.1",
"etag": "~1.5.1",
"fresh": "0.2.4",
"media-typer": "0.3.0",
"methods": "1.1.0",
"methods": "~1.1.1",
"mkdirp": "0.5.0",
"parseurl": "~1.3.0",
"proxy-addr": "1.0.1",
"proxy-addr": "~1.0.6",
"range-parser": "~1.0.2",
"send": "0.9.2",
"send": "0.11.1",
"utils-merge": "1.0.0",
"vary": "~1.0.0",
"cookie": "0.1.2",
"merge-descriptors": "0.0.2"
},
"devDependencies": {
"connect-redis": "~1.5.0",
"istanbul": "0.3.2",
"mocha": "~1.21.4",
"should": "~4.0.0",
"ejs": "~1.0.0",
"jade": "~1.6.0",
"hjs": "~0.0.6",
"marked": "0.3.2",
"supertest": "~0.13.0"
"ejs": "2.1.4",
"istanbul": "0.3.5",
"marked": "0.3.3",
"mocha": "~2.1.0",
"should": "~4.6.2",
"supertest": "~0.15.0",
"hjs": "~0.0.6"
},
"engines": {
"node": ">= 0.8.0"
@@ -63,8 +64,15 @@
"bin": {
"express": "./bin/express"
},
"files": [
"LICENSE",
"History.md",
"Readme.md",
"index.js",
"bin/",
"lib/"
],
"scripts": {
"prepublish": "npm prune",
"test": "mocha --require test/support/env --reporter dot --check-leaks test/ test/acceptance/",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --require test/support/env --reporter dot --check-leaks test/ test/acceptance/",
"test-tap": "mocha --require test/support/env --reporter tap --check-leaks test/ test/acceptance/",

View File

@@ -1,66 +0,0 @@
/**
* Module dependencies.
*/
var express = require('../');
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');
app.set('view engine', 'jade');
app.locals.self = true;
app.get('/render', function(req, res){
res.render('hello');
});
admin.get('/', function(req, res){
res.send('Hello World\n');
});
blog.get('/', function(req, res){
res.send('Hello World\n');
});
app.get('/', function(req, res){
res.send('Hello World\n');
});
app.get('/json', function(req, res){
res.send({ name: 'Tobi', role: 'admin' });
});
app.get('/json/:n', function(req, res){
var n = ~~req.params.n;
var arr = [];
var obj = { name: 'Tobi', role: 'admin' };
while (n--) arr.push(obj);
res.send(arr);
});
function foo(req, res, next) {
next();
}
app.get('/middleware', foo, foo, foo, foo, function(req, res){
res.send('Hello World\n');
});
var n = 100;
while (n--) {
app.get('/foo', foo, foo, function(req, res){
});
}
app.get('/match', function(req, res){
res.send('Hello World\n');
});
app.listen(8000);

View File

@@ -1,21 +0,0 @@
#!/usr/bin/env node
var buf = '';
process.stdin.setEncoding('utf8');
process.stdin.on('data', function(chunk){
buf += chunk;
}).on('end', function(){
var comments = JSON.parse(buf);
comments.forEach(function(comment){
if (comment.ignore) return;
if (comment.isPrivate) return;
if (!comment.ctx) return;
if (!comment.description.full.indexOf('Module dep')) return;
var ctx = comment.ctx;
console.log();
console.log('# %s', ctx.string);
console.log();
console.log(comment.description.full.trim().replace(/^/gm, ' '));
});
console.log();
}).resume();

View File

@@ -1 +0,0 @@
p Hello

View File

@@ -12,8 +12,8 @@ describe('OPTIONS', function(){
request(app)
.options('/users')
.expect('GET,PUT')
.expect('Allow', 'GET,PUT', done);
.expect('GET,HEAD,PUT')
.expect('Allow', 'GET,HEAD,PUT', done);
})
it('should not respond if the path is not defined', function(done){
@@ -36,8 +36,8 @@ describe('OPTIONS', function(){
request(app)
.options('/other')
.expect('GET')
.expect('Allow', 'GET', done);
.expect('GET,HEAD')
.expect('Allow', 'GET,HEAD', done);
})
})

View File

@@ -1,14 +1,15 @@
var express = require('../');
var express = require('..');
var tmpl = require('./support/tmpl');
describe('app', function(){
describe('.render(name, fn)', function(){
it('should support absolute paths', function(done){
var app = express();
var app = createApp();
app.locals.user = { name: 'tobi' };
app.render(__dirname + '/fixtures/user.jade', function(err, str){
app.render(__dirname + '/fixtures/user.tmpl', function (err, str) {
if (err) return done(err);
str.should.equal('<p>tobi</p>');
done();
@@ -16,9 +17,9 @@ describe('app', function(){
})
it('should support absolute paths with "view engine"', function(done){
var app = express();
var app = createApp();
app.set('view engine', 'jade');
app.set('view engine', 'tmpl');
app.locals.user = { name: 'tobi' };
app.render(__dirname + '/fixtures/user', function(err, str){
@@ -29,12 +30,12 @@ describe('app', function(){
})
it('should expose app.locals', function(done){
var app = express();
var app = createApp();
app.set('views', __dirname + '/fixtures');
app.locals.user = { name: 'tobi' };
app.render('user.jade', function(err, str){
app.render('user.tmpl', function (err, str) {
if (err) return done(err);
str.should.equal('<p>tobi</p>');
done();
@@ -42,12 +43,12 @@ describe('app', function(){
})
it('should support index.<engine>', function(done){
var app = express();
var app = createApp();
app.set('views', __dirname + '/fixtures');
app.set('view engine', 'jade');
app.set('view engine', 'tmpl');
app.render('blog/post', function(err, str){
app.render('blog/post', function (err, str) {
if (err) return done(err);
str.should.equal('<h1>blog post</h1>');
done();
@@ -77,10 +78,11 @@ describe('app', function(){
describe('when the file does not exist', function(){
it('should provide a helpful error', function(done){
var app = express();
var app = createApp();
app.set('views', __dirname + '/fixtures');
app.render('rawr.jade', function(err){
err.message.should.equal('Failed to lookup view "rawr.jade" in views directory "' + __dirname + '/fixtures"');
app.render('rawr.tmpl', function (err) {
err.message.should.equal('Failed to lookup view "rawr.tmpl" in views directory "' + __dirname + '/fixtures"');
done();
});
})
@@ -88,11 +90,11 @@ describe('app', function(){
describe('when an error occurs', function(){
it('should invoke the callback', function(done){
var app = express();
var app = createApp();
app.set('views', __dirname + '/fixtures');
app.render('user.jade', function(err, str){
app.render('user.tmpl', function (err, str) {
// nextTick to prevent cyclic
process.nextTick(function(){
err.message.should.match(/Cannot read property 'name' of undefined/);
@@ -104,11 +106,11 @@ describe('app', function(){
describe('when an extension is given', function(){
it('should render the template', function(done){
var app = express();
var app = createApp();
app.set('views', __dirname + '/fixtures');
app.render('email.jade', function(err, str){
app.render('email.tmpl', function (err, str) {
if (err) return done(err);
str.should.equal('<p>This is an email</p>');
done();
@@ -118,9 +120,9 @@ describe('app', function(){
describe('when "view engine" is given', function(){
it('should render the template', function(done){
var app = express();
var app = createApp();
app.set('view engine', 'jade');
app.set('view engine', 'tmpl');
app.set('views', __dirname + '/fixtures');
app.render('email', function(err, str){
@@ -219,13 +221,13 @@ describe('app', function(){
describe('.render(name, options, fn)', function(){
it('should render the template', function(done){
var app = express();
var app = createApp();
app.set('views', __dirname + '/fixtures');
var user = { name: 'tobi' };
app.render('user.jade', { user: user }, function(err, str){
app.render('user.tmpl', { user: user }, function (err, str) {
if (err) return done(err);
str.should.equal('<p>tobi</p>');
done();
@@ -233,12 +235,12 @@ describe('app', function(){
})
it('should expose app.locals', function(done){
var app = express();
var app = createApp();
app.set('views', __dirname + '/fixtures');
app.locals.user = { name: 'tobi' };
app.render('user.jade', {}, function(err, str){
app.render('user.tmpl', {}, function (err, str) {
if (err) return done(err);
str.should.equal('<p>tobi</p>');
done();
@@ -246,13 +248,13 @@ describe('app', function(){
})
it('should give precedence to app.render() locals', function(done){
var app = express();
var app = createApp();
app.set('views', __dirname + '/fixtures');
app.locals.user = { name: 'tobi' };
var jane = { name: 'jane' };
app.render('user.jade', { user: jane }, function(err, str){
app.render('user.tmpl', { user: jane }, function (err, str) {
if (err) return done(err);
str.should.equal('<p>jane</p>');
done();
@@ -292,3 +294,11 @@ describe('app', function(){
})
})
})
function createApp() {
var app = express();
app.engine('.tmpl', tmpl);
return app;
}

View File

@@ -1 +0,0 @@
h1 blog post

1
test/fixtures/blog/post/index.tmpl vendored Normal file
View File

@@ -0,0 +1 @@
<h1>blog post</h1>

View File

@@ -1 +0,0 @@
p This is an email

1
test/fixtures/email.tmpl vendored Normal file
View File

@@ -0,0 +1 @@
<p>This is an email</p>

View File

@@ -1 +0,0 @@
p #{first} #{last} is a #{species}

View File

@@ -1 +0,0 @@
p= user.name

1
test/fixtures/user.tmpl vendored Normal file
View File

@@ -0,0 +1 @@
<p>$user.name</p>

View File

@@ -32,5 +32,18 @@ describe('req', function(){
.set('If-None-Match', '"12345"')
.expect(200, 'false', done);
})
it('should return false without response headers', function(done){
var app = express();
app.use(function(req, res){
res._headers = null;
res.send(req.fresh);
});
request(app)
.get('/')
.expect(200, 'false', done);
})
})
})

View File

@@ -32,5 +32,18 @@ describe('req', function(){
.set('If-None-Match', '"12345"')
.expect(200, 'true', done);
})
it('should return true without response headers', function(done){
var app = express();
app.use(function(req, res){
res._headers = null;
res.send(req.stale);
});
request(app)
.get('/')
.expect(200, 'true', done);
})
})
})

View File

@@ -1,8 +1,8 @@
var express = require('../')
, request = require('supertest')
, utils = require('connect').utils
, cookie = require('cookie');
var merge = require('utils-merge');
describe('res', function(){
describe('.cookie(name, object)', function(){
@@ -111,7 +111,7 @@ describe('res', function(){
var app = express();
var options = { maxAge: 1000 };
var optionsCopy = utils.merge({}, options);
var optionsCopy = merge({}, options);
app.use(function(req, res){
res.cookie('name', 'tobi', options)

View File

@@ -81,7 +81,7 @@ describe('res', function(){
it('should be invoked instead of auto-responding', function(done){
request(app3)
.get('/')
.set('Accept: text/html')
.set('Accept', 'text/html')
.expect('default', done);
})
})

View File

@@ -1,14 +1,20 @@
var express = require('../')
, res = express.response;
var express = require('..');
var request = require('supertest');
describe('res', function(){
describe('.get(field)', function(){
it('should get the response header field', function(){
res.setHeader('Content-Type', 'text/x-foo');
res.get('Content-Type').should.equal('text/x-foo');
res.get('Content-type').should.equal('text/x-foo');
res.get('content-type').should.equal('text/x-foo');
it('should get the response header field', function (done) {
var app = express();
app.use(function (req, res) {
res.setHeader('Content-Type', 'text/x-foo');
res.send(res.get('Content-Type'));
});
request(app)
.get('/')
.expect(200, 'text/x-foo', done);
})
})
})

View File

@@ -1,41 +1,46 @@
var express = require('../')
, res = express.response;
var express = require('..');
var request = require('supertest');
describe('res', function(){
beforeEach(function() {
res.removeHeader('link');
});
describe('.links(obj)', function(){
it('should set Link header field', function(){
res.links({
next: 'http://api.example.com/users?page=2',
last: 'http://api.example.com/users?page=5'
it('should set Link header field', function (done) {
var app = express();
app.use(function (req, res) {
res.links({
next: 'http://api.example.com/users?page=2',
last: 'http://api.example.com/users?page=5'
});
res.end();
});
res.get('link')
.should.equal(
'<http://api.example.com/users?page=2>; rel="next", '
+ '<http://api.example.com/users?page=5>; rel="last"');
request(app)
.get('/')
.expect('Link', '<http://api.example.com/users?page=2>; rel="next", <http://api.example.com/users?page=5>; rel="last"')
.expect(200, done);
})
it('should set Link header field for multiple calls', function() {
res.links({
next: 'http://api.example.com/users?page=2',
last: 'http://api.example.com/users?page=5'
it('should set Link header field for multiple calls', function (done) {
var app = express();
app.use(function (req, res) {
res.links({
next: 'http://api.example.com/users?page=2',
last: 'http://api.example.com/users?page=5'
});
res.links({
prev: 'http://api.example.com/users?page=1'
});
res.end();
});
res.links({
prev: 'http://api.example.com/users?page=1',
});
res.get('link')
.should.equal(
'<http://api.example.com/users?page=2>; rel="next", '
+ '<http://api.example.com/users?page=5>; rel="last", '
+ '<http://api.example.com/users?page=1>; rel="prev"');
request(app)
.get('/')
.expect('Link', '<http://api.example.com/users?page=2>; rel="next", <http://api.example.com/users?page=5>; rel="last", <http://api.example.com/users?page=1>; rel="prev"')
.expect(200, done);
})
})
})

View File

@@ -1,16 +1,17 @@
var express = require('../')
, request = require('supertest');
var express = require('..');
var request = require('supertest');
var tmpl = require('./support/tmpl');
describe('res', function(){
describe('.render(name)', function(){
it('should support absolute paths', function(done){
var app = express();
var app = createApp();
app.locals.user = { name: 'tobi' };
app.use(function(req, res){
res.render(__dirname + '/fixtures/user.jade');
res.render(__dirname + '/fixtures/user.tmpl');
});
request(app)
@@ -19,10 +20,10 @@ describe('res', function(){
})
it('should support absolute paths with "view engine"', function(done){
var app = express();
var app = createApp();
app.locals.user = { name: 'tobi' };
app.set('view engine', 'jade');
app.set('view engine', 'tmpl');
app.use(function(req, res){
res.render(__dirname + '/fixtures/user');
@@ -34,13 +35,13 @@ describe('res', function(){
})
it('should expose app.locals', function(done){
var app = express();
var app = createApp();
app.set('views', __dirname + '/fixtures');
app.locals.user = { name: 'tobi' };
app.use(function(req, res){
res.render('user.jade');
res.render('user.tmpl');
});
request(app)
@@ -49,10 +50,10 @@ describe('res', function(){
})
it('should support index.<engine>', function(done){
var app = express();
var app = createApp();
app.set('views', __dirname + '/fixtures');
app.set('view engine', 'jade');
app.set('view engine', 'tmpl');
app.use(function(req, res){
res.render('blog/post');
@@ -65,12 +66,12 @@ describe('res', function(){
describe('when an error occurs', function(){
it('should next(err)', function(done){
var app = express();
var app = createApp();
app.set('views', __dirname + '/fixtures');
app.use(function(req, res){
res.render('user.jade');
res.render('user.tmpl');
});
app.use(function(err, req, res, next){
@@ -85,9 +86,9 @@ describe('res', function(){
describe('when "view engine" is given', function(){
it('should render the template', function(done){
var app = express();
var app = createApp();
app.set('view engine', 'jade');
app.set('view engine', 'tmpl');
app.set('views', __dirname + '/fixtures');
app.use(function(req, res){
@@ -103,14 +104,14 @@ describe('res', function(){
describe('.render(name, option)', function(){
it('should render the template', function(done){
var app = express();
var app = createApp();
app.set('views', __dirname + '/fixtures');
var user = { name: 'tobi' };
app.use(function(req, res){
res.render('user.jade', { user: user });
res.render('user.tmpl', { user: user });
});
request(app)
@@ -119,13 +120,13 @@ describe('res', function(){
})
it('should expose app.locals', function(done){
var app = express();
var app = createApp();
app.set('views', __dirname + '/fixtures');
app.locals.user = { name: 'tobi' };
app.use(function(req, res){
res.render('user.jade');
res.render('user.tmpl');
});
request(app)
@@ -134,13 +135,13 @@ describe('res', function(){
})
it('should expose res.locals', function(done){
var app = express();
var app = createApp();
app.set('views', __dirname + '/fixtures');
app.use(function(req, res){
res.locals.user = { name: 'tobi' };
res.render('user.jade');
res.render('user.tmpl');
});
request(app)
@@ -149,14 +150,14 @@ describe('res', function(){
})
it('should give precedence to res.locals over app.locals', function(done){
var app = express();
var app = createApp();
app.set('views', __dirname + '/fixtures');
app.locals.user = { name: 'tobi' };
app.use(function(req, res){
res.locals.user = { name: 'jane' };
res.render('user.jade', {});
res.render('user.tmpl', {});
});
request(app)
@@ -165,14 +166,14 @@ describe('res', function(){
})
it('should give precedence to res.render() locals over res.locals', function(done){
var app = express();
var app = createApp();
app.set('views', __dirname + '/fixtures');
var jane = { name: 'jane' };
app.use(function(req, res){
res.locals.user = { name: 'tobi' };
res.render('user.jade', { user: jane });
res.render('user.tmpl', { user: jane });
});
request(app)
@@ -181,14 +182,14 @@ describe('res', function(){
})
it('should give precedence to res.render() locals over app.locals', function(done){
var app = express();
var app = createApp();
app.set('views', __dirname + '/fixtures');
app.locals.user = { name: 'tobi' };
var jane = { name: 'jane' };
app.use(function(req, res){
res.render('user.jade', { user: jane });
res.render('user.tmpl', { user: jane });
});
request(app)
@@ -199,13 +200,13 @@ describe('res', function(){
describe('.render(name, options, fn)', function(){
it('should pass the resulting string', function(done){
var app = express();
var app = createApp();
app.set('views', __dirname + '/fixtures');
app.use(function(req, res){
var tobi = { name: 'tobi' };
res.render('user.jade', { user: tobi }, function(err, html){
res.render('user.tmpl', { user: tobi }, function (err, html) {
html = html.replace('tobi', 'loki');
res.end(html);
});
@@ -219,13 +220,13 @@ describe('res', function(){
describe('.render(name, fn)', function(){
it('should pass the resulting string', function(done){
var app = express();
var app = createApp();
app.set('views', __dirname + '/fixtures');
app.use(function(req, res){
res.locals.user = { name: 'tobi' };
res.render('user.jade', function(err, html){
res.render('user.tmpl', function (err, html) {
html = html.replace('tobi', 'loki');
res.end(html);
});
@@ -238,12 +239,12 @@ describe('res', function(){
describe('when an error occurs', function(){
it('should pass it to the callback', function(done){
var app = express();
var app = createApp();
app.set('views', __dirname + '/fixtures');
app.use(function(req, res){
res.render('user.jade', function(err){
res.render('user.tmpl', function (err) {
res.end(err.message);
});
});
@@ -255,3 +256,11 @@ describe('res', function(){
})
})
})
function createApp() {
var app = express();
app.engine('.tmpl', tmpl);
return app;
}

View File

@@ -120,7 +120,7 @@ describe('res', function(){
request(app)
.get('/')
.expect('ETag', 'W/"7ff-2796319984"')
.expect('ETag', 'W/"fz/jGo0ONwzb+aKy/rWipg=="')
.end(done);
})
@@ -209,7 +209,7 @@ describe('res', function(){
request(app)
.get('/')
.expect('ETag', 'W/"7ff-2796319984"')
.expect('ETag', 'W/"fz/jGo0ONwzb+aKy/rWipg=="')
.end(done);
})
@@ -325,7 +325,7 @@ describe('res', function(){
request(app)
.get('/')
.set('If-None-Match', 'W/"7ff-2796319984"')
.set('If-None-Match', 'W/"fz/jGo0ONwzb+aKy/rWipg=="')
.expect(304, done);
})
@@ -371,7 +371,7 @@ describe('res', function(){
request(app)
.get('/')
.expect('etag', 'W/"c-1525560792"', done)
.expect('etag', 'W/"c-5aee35d8"', done)
})
it('should send ETag for empty string response', function(done){
@@ -400,7 +400,7 @@ describe('res', function(){
request(app)
.get('/')
.expect('etag', 'W/"7ff-2796319984"', done)
.expect('etag', 'W/"fz/jGo0ONwzb+aKy/rWipg=="', done)
});
it('should not override ETag when manually set', function(done){
@@ -499,7 +499,7 @@ describe('res', function(){
request(app)
.get('/')
.expect('etag', 'W/"d-1486392595"', done)
.expect('etag', 'W/"d-58988d13"', done)
})
})

View File

@@ -1,7 +1,6 @@
var express = require('../')
, request = require('supertest')
, res = express.response;
var express = require('..');
var request = require('supertest');
describe('res', function(){
describe('.set(field, value)', function(){
@@ -18,10 +17,18 @@ describe('res', function(){
.end(done);
})
it('should coerce to a string', function(){
res.headers = {};
res.set('X-Number', 123);
res.get('X-Number').should.equal('123');
it('should coerce to a string', function (done) {
var app = express();
app.use(function (req, res) {
res.set('X-Number', 123);
res.end(typeof res.get('X-Number'));
});
request(app)
.get('/')
.expect('X-Number', '123')
.expect(200, 'string', done);
})
})
@@ -39,11 +46,18 @@ describe('res', function(){
.expect('["type=ninja","language=javascript"]', done);
})
it('should coerce to an array of strings', function(){
res.headers = {};
res.set('X-Numbers', [123, 456]);
JSON.stringify(res.get('X-Numbers'))
.should.equal('["123","456"]');
it('should coerce to an array of strings', function (done) {
var app = express();
app.use(function (req, res) {
res.set('X-Numbers', [123, 456]);
res.end(JSON.stringify(res.get('X-Numbers')));
});
request(app)
.get('/')
.expect('X-Numbers', '123, 456')
.expect(200, '["123","456"]', done);
})
})
@@ -65,10 +79,18 @@ describe('res', function(){
.end(done);
})
it('should coerce to a string', function(){
res.headers = {};
res.set({ 'X-Number': 123 });
res.get('X-Number').should.equal('123');
it('should coerce to a string', function (done) {
var app = express();
app.use(function (req, res) {
res.set({ 'X-Number': 123 });
res.end(typeof res.get('X-Number'));
});
request(app)
.get('/')
.expect('X-Number', '123')
.expect(200, 'string', done);
})
})
})

View File

@@ -1,55 +1,96 @@
var express = require('../')
, should = require('should');
function response() {
var res = Object.create(express.response);
res._headers = {};
return res;
}
var assert = require('assert');
var express = require('..');
var request = require('supertest');
describe('res.vary()', function(){
describe('with no arguments', function(){
it('should not set Vary', function(){
var res = response();
res.vary();
should.not.exist(res.get('Vary'));
it('should not set Vary', function (done) {
var app = express();
app.use(function (req, res) {
res.vary();
res.end();
});
request(app)
.get('/')
.expect(shouldNotHaveHeader('Vary'))
.expect(200, done);
})
})
describe('with an empty array', function(){
it('should not set Vary', function(){
var res = response();
res.vary([]);
should.not.exist(res.get('Vary'));
it('should not set Vary', function (done) {
var app = express();
app.use(function (req, res) {
res.vary([]);
res.end();
});
request(app)
.get('/')
.expect(shouldNotHaveHeader('Vary'))
.expect(200, done);
})
})
describe('with an array', function(){
it('should set the values', function(){
var res = response();
res.vary(['Accept', 'Accept-Language', 'Accept-Encoding']);
res.get('Vary').should.equal('Accept, Accept-Language, Accept-Encoding');
it('should set the values', function (done) {
var app = express();
app.use(function (req, res) {
res.vary(['Accept', 'Accept-Language', 'Accept-Encoding']);
res.end();
});
request(app)
.get('/')
.expect('Vary', 'Accept, Accept-Language, Accept-Encoding')
.expect(200, done);
})
})
describe('with a string', function(){
it('should set the value', function(){
var res = response();
res.vary('Accept');
res.get('Vary').should.equal('Accept');
it('should set the value', function (done) {
var app = express();
app.use(function (req, res) {
res.vary('Accept');
res.end();
});
request(app)
.get('/')
.expect('Vary', 'Accept')
.expect(200, done);
})
})
describe('when the value is present', function(){
it('should not add it again', function(){
var res = response();
res.vary('Accept');
res.vary('Accept-Encoding');
res.vary('Accept-Encoding');
res.vary('Accept-Encoding');
res.vary('Accept');
res.get('Vary').should.equal('Accept, Accept-Encoding');
it('should not add it again', function (done) {
var app = express();
app.use(function (req, res) {
res.vary('Accept');
res.vary('Accept-Encoding');
res.vary('Accept-Encoding');
res.vary('Accept-Encoding');
res.vary('Accept');
res.end();
});
request(app)
.get('/')
.expect('Vary', 'Accept, Accept-Encoding')
.expect(200, done);
})
})
})
function shouldNotHaveHeader(header) {
return function (res) {
assert.ok(!(header.toLowerCase() in res.headers), 'should not have header ' + header);
};
}

35
test/support/tmpl.js Normal file
View File

@@ -0,0 +1,35 @@
var fs = require('fs');
var variableRegExp = /\$([0-9a-zA-Z\.]+)/g;
module.exports = function renderFile(fileName, options, callback) {
function onReadFile(err, str) {
if (err) {
callback(err);
return;
}
try {
str = str.replace(variableRegExp, generateVariableLookup(options));
} catch (e) {
err = e;
}
callback(err, str);
}
fs.readFile(fileName, 'utf8', onReadFile);
};
function generateVariableLookup(data) {
return function variableLookup(str, path) {
var parts = path.split('.');
var value = data;
for (var i = 0; i < parts.length; i++) {
value = value[parts[i]];
}
return value;
};
}

View File

@@ -28,18 +28,18 @@ describe('utils.etag(body, encoding)', function(){
describe('utils.wetag(body, encoding)', function(){
it('should support strings', function(){
utils.wetag('express!')
.should.eql('W/"8-3098196679"')
.should.eql('W/"8-b8aabac7"')
})
it('should support utf8 strings', function(){
utils.wetag('express❤', 'utf8')
.should.eql('W/"a-1751845617"')
.should.eql('W/"a-686b0af1"')
})
it('should support buffer', function(){
var buf = new Buffer('express!')
utils.wetag(buf)
.should.eql('W/"8-3098196679"');
.should.eql('W/"8-b8aabac7"');
})
it('should support empty string', function(){