Compare commits

...

93 Commits

Author SHA1 Message Date
Douglas Christopher Wilson
cb59086305 3.21.2 2015-07-31 16:15:06 -04:00
Douglas Christopher Wilson
ce087e559e build: marked@0.3.5 2015-07-31 16:13:41 -04:00
Douglas Christopher Wilson
93dd15cd61 deps: connect@2.30.2 2015-07-31 16:13:09 -04:00
Douglas Christopher Wilson
b53feaa1d8 deps: vary@~1.0.1 2015-07-27 22:12:39 -04:00
Douglas Christopher Wilson
d51d1ea57a build: ejs@2.3.3 2015-07-27 22:11:54 -04:00
Douglas Christopher Wilson
fc95112145 build: should@7.0.2 2015-07-27 22:09:34 -04:00
Douglas Christopher Wilson
3c0ff8133b 3.21.1 2015-07-06 00:53:25 -04:00
Douglas Christopher Wilson
f247a4182f deps: basic-auth@~1.0.3 2015-07-06 00:39:42 -04:00
Douglas Christopher Wilson
71d56db947 build: ejs@2.3.2 2015-07-06 00:39:06 -04:00
Douglas Christopher Wilson
3ec7cca550 deps: connect@2.30.1 2015-07-06 00:38:10 -04:00
Douglas Christopher Wilson
115dbe1a4d 3.21.0 2015-06-18 21:14:56 -04:00
Douglas Christopher Wilson
4729685912 deps: fresh@0.3.0 2015-06-18 20:56:48 -04:00
Douglas Christopher Wilson
14b849246e deps: send@0.13.0 2015-06-18 20:56:03 -04:00
Douglas Christopher Wilson
c8d61b6269 deps: etag@~1.7.0
fixes #2667
2015-06-18 20:54:26 -04:00
Douglas Christopher Wilson
0fbf2078e1 deps: escape-html@1.0.2 2015-06-18 20:36:48 -04:00
Douglas Christopher Wilson
77402110b9 deps: cookie@0.1.3 2015-06-18 20:35:56 -04:00
Douglas Christopher Wilson
5207b99e08 deps: basic-auth@1.0.2 2015-06-18 20:34:04 -04:00
Douglas Christopher Wilson
92b5fa8c53 build: should@7.0.1 2015-06-18 20:10:16 -04:00
Douglas Christopher Wilson
62dfa792b2 deps: connect@2.30.0 2015-06-18 20:08:32 -04:00
Douglas Christopher Wilson
29f51c67a6 docs: fix typos in history
closes #2676
closes #2677
closes #2678
2015-06-17 01:24:21 -04:00
Douglas Christopher Wilson
a20a9a1a2e deps: mkdirp@0.5.1 2015-06-17 01:21:20 -04:00
Douglas Christopher Wilson
9ae08f932e build: should@6.0.3 2015-06-17 01:17:42 -04:00
Douglas Christopher Wilson
b149430114 3.20.3 2015-05-18 00:04:41 -04:00
Douglas Christopher Wilson
057898bbe8 docs: update badges 2015-05-18 00:03:54 -04:00
Douglas Christopher Wilson
630c650c3e deps: debug@~2.2.0 2015-05-17 23:54:59 -04:00
Douglas Christopher Wilson
ee2e4f17bb deps: should@6.0.1 2015-05-17 23:53:35 -04:00
Douglas Christopher Wilson
7df8fa3be5 deps: supertest@1.0.1 2015-05-17 23:44:09 -04:00
Douglas Christopher Wilson
96b4a76382 deps: depd@~1.0.1 2015-05-17 23:38:35 -04:00
Douglas Christopher Wilson
519f655f17 deps: send@0.12.3 2015-05-17 21:07:06 -04:00
Douglas Christopher Wilson
f7455227e0 deps: proxy-addr@~1.0.8 2015-05-17 21:04:02 -04:00
Douglas Christopher Wilson
c90de122c8 deps: mocha@2.2.5 2015-05-17 20:59:02 -04:00
Douglas Christopher Wilson
cac867da84 deps: istanbul@0.3.9 2015-05-17 20:58:21 -04:00
Douglas Christopher Wilson
d0e8ac795d deps: connect@2.29.2 2015-05-17 20:56:52 -04:00
Douglas Christopher Wilson
011e5dc241 3.20.2 2015-03-17 01:03:53 -04:00
Douglas Christopher Wilson
389ab1b19f tests: add test for cookie-sessions example 2015-03-17 01:02:08 -04:00
Douglas Christopher Wilson
279c8bbec3 deps: proxy-addr@~1.0.7 2015-03-17 00:47:15 -04:00
Douglas Christopher Wilson
6744f811b4 deps: debug@~2.1.3 2015-03-17 00:25:00 -04:00
Douglas Christopher Wilson
d7a6d709af deps: merge-descriptors@1.0.0 2015-03-17 00:23:23 -04:00
Douglas Christopher Wilson
ff44e0f9ae deps: send@0.12.2 2015-03-17 00:21:58 -04:00
Douglas Christopher Wilson
100e50f23d deps: connect@2.29.1 2015-03-17 00:17:34 -04:00
Douglas Christopher Wilson
20c040db22 deps: istanbul@0.3.8 2015-03-17 00:15:07 -04:00
Douglas Christopher Wilson
5d8a7a610f deps: should@~5.2.0 2015-03-17 00:14:09 -04:00
Douglas Christopher Wilson
d34d60ce92 deps: mocha@~2.2.1 2015-03-17 00:13:14 -04:00
Douglas Christopher Wilson
b2311c7402 3.20.1 2015-02-28 23:16:27 -05:00
Douglas Christopher Wilson
9ca0c66e23 build: skip unnecessary dependency in Travis CI 2015-02-28 22:41:01 -05:00
Douglas Christopher Wilson
ef71373fa3 deps: istanbul@0.3.6 2015-02-28 22:39:55 -05:00
Douglas Christopher Wilson
5873d335bd deps: ejs@2.3.1 2015-02-28 22:39:06 -05:00
Douglas Christopher Wilson
2e0f5e7817 Fix req.host when using "trust proxy" hops count 2015-02-28 21:32:51 -05:00
Paul Serby
20aa12616a Fix req.protocol/req.secure when using "trust proxy" hops count
fixes #2569
closes #2570
2015-02-28 21:29:43 -05:00
Douglas Christopher Wilson
bb4703e199 deps: remove un-used devDependency 2015-02-28 21:06:03 -05:00
Douglas Christopher Wilson
85755e32d9 3.20.0 2015-02-18 21:25:55 -05:00
Douglas Christopher Wilson
b40e74d6b6 Fix "trust proxy" setting to inherit when app is mounted
fixes #2550
fixes #2551
2015-02-18 00:59:56 -05:00
Douglas Christopher Wilson
eaf3318dd3 Generate ETags for all request responses
closes #2546
2015-02-18 00:12:28 -05:00
Douglas Christopher Wilson
e1057bd7fd build: support Node.js 0.12
closes #2538
2015-02-17 22:52:23 -05:00
Douglas Christopher Wilson
f22937f3d1 Use content-type to parse Content-Type headers 2015-02-17 22:49:24 -05:00
Douglas Christopher Wilson
69a4869db0 deps: should@~5.0.0 2015-02-17 22:43:38 -05:00
Douglas Christopher Wilson
c2a6c8d338 deps: send@0.12.1 2015-02-17 22:42:02 -05:00
Douglas Christopher Wilson
2ce05047f8 deps: cookie-signature@1.0.6 2015-02-17 22:40:51 -05:00
Douglas Christopher Wilson
829fa34581 build: use Travis CI container infrastructure 2015-02-17 22:37:28 -05:00
Douglas Christopher Wilson
3610fdce36 deps: connect@2.29.0 2015-02-17 22:32:18 -05:00
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
60 changed files with 1114 additions and 540 deletions

View File

@@ -2,10 +2,8 @@ language: node_js
node_js:
- "0.8"
- "0.10"
- "0.11"
matrix:
allow_failures:
- node_js: "0.11"
fast_finish: true
- "0.12"
sudo: false
before_install: "npm rm --save-dev connect-redis"
script: "npm run-script test-travis"
after_script: "npm install coveralls@2.10.0 && cat ./coverage/lcov.info | coveralls"

View File

@@ -1,3 +1,247 @@
3.21.2 / 2015-07-31
===================
* deps: connect@2.30.2
- deps: body-parser@~1.13.3
- deps: compression@~1.5.2
- deps: errorhandler@~1.4.2
- deps: method-override@~2.3.5
- deps: serve-index@~1.7.2
- deps: type-is@~1.6.6
- deps: vhost@~3.0.1
* deps: vary@~1.0.1
- Fix setting empty header from empty `field`
- perf: enable strict mode
- perf: remove argument reassignments
3.21.1 / 2015-07-05
===================
* deps: basic-auth@~1.0.3
* deps: connect@2.30.1
- deps: body-parser@~1.13.2
- deps: compression@~1.5.1
- deps: errorhandler@~1.4.1
- deps: morgan@~1.6.1
- deps: pause@0.1.0
- deps: qs@4.0.0
- deps: serve-index@~1.7.1
- deps: type-is@~1.6.4
3.21.0 / 2015-06-18
===================
* deps: basic-auth@1.0.2
- perf: enable strict mode
- perf: hoist regular expression
- perf: parse with regular expressions
- perf: remove argument reassignment
* deps: connect@2.30.0
- deps: body-parser@~1.13.1
- deps: bytes@2.1.0
- deps: compression@~1.5.0
- deps: cookie@0.1.3
- deps: cookie-parser@~1.3.5
- deps: csurf@~1.8.3
- deps: errorhandler@~1.4.0
- deps: express-session@~1.11.3
- deps: finalhandler@0.4.0
- deps: fresh@0.3.0
- deps: morgan@~1.6.0
- deps: serve-favicon@~2.3.0
- deps: serve-index@~1.7.0
- deps: serve-static@~1.10.0
- deps: type-is@~1.6.3
* deps: cookie@0.1.3
- perf: deduce the scope of try-catch deopt
- perf: remove argument reassignments
* deps: escape-html@1.0.2
* deps: etag@~1.7.0
- Always include entity length in ETags for hash length extensions
- Generate non-Stats ETags using MD5 only (no longer CRC32)
- Improve stat performance by removing hashing
- Improve support for JXcore
- Remove base64 padding in ETags to shorten
- Support "fake" stats objects in environments without fs
- Use MD5 instead of MD4 in weak ETags over 1KB
* deps: fresh@0.3.0
- Add weak `ETag` matching support
* deps: mkdirp@0.5.1
- Work in global strict mode
* deps: send@0.13.0
- Allow Node.js HTTP server to set `Date` response header
- Fix incorrectly removing `Content-Location` on 304 response
- Improve the default redirect response headers
- Send appropriate headers on default error response
- Use `http-errors` for standard emitted errors
- Use `statuses` instead of `http` module for status messages
- deps: escape-html@1.0.2
- deps: etag@~1.7.0
- deps: fresh@0.3.0
- deps: on-finished@~2.3.0
- perf: enable strict mode
- perf: remove unnecessary array allocations
3.20.3 / 2015-05-17
===================
* deps: connect@2.29.2
- deps: body-parser@~1.12.4
- deps: compression@~1.4.4
- deps: connect-timeout@~1.6.2
- deps: debug@~2.2.0
- deps: depd@~1.0.1
- deps: errorhandler@~1.3.6
- deps: finalhandler@0.3.6
- deps: method-override@~2.3.3
- deps: morgan@~1.5.3
- deps: qs@2.4.2
- deps: response-time@~2.3.1
- deps: serve-favicon@~2.2.1
- deps: serve-index@~1.6.4
- deps: serve-static@~1.9.3
- deps: type-is@~1.6.2
* deps: debug@~2.2.0
- deps: ms@0.7.1
* deps: depd@~1.0.1
* deps: proxy-addr@~1.0.8
- deps: ipaddr.js@1.0.1
* deps: send@0.12.3
- deps: debug@~2.2.0
- deps: depd@~1.0.1
- deps: etag@~1.6.0
- deps: ms@0.7.1
- deps: on-finished@~2.2.1
3.20.2 / 2015-03-16
===================
* deps: connect@2.29.1
- deps: body-parser@~1.12.2
- deps: compression@~1.4.3
- deps: connect-timeout@~1.6.1
- deps: debug@~2.1.3
- deps: errorhandler@~1.3.5
- deps: express-session@~1.10.4
- deps: finalhandler@0.3.4
- deps: method-override@~2.3.2
- deps: morgan@~1.5.2
- deps: qs@2.4.1
- deps: serve-index@~1.6.3
- deps: serve-static@~1.9.2
- deps: type-is@~1.6.1
* deps: debug@~2.1.3
- Fix high intensity foreground color for bold
- deps: ms@0.7.0
* deps: merge-descriptors@1.0.0
* deps: proxy-addr@~1.0.7
- deps: ipaddr.js@0.1.9
* deps: send@0.12.2
- Throw errors early for invalid `extensions` or `index` options
- deps: debug@~2.1.3
3.20.1 / 2015-02-28
===================
* Fix `req.host` when using "trust proxy" hops count
* Fix `req.protocol`/`req.secure` when using "trust proxy" hops count
3.20.0 / 2015-02-18
===================
* Fix `"trust proxy"` setting to inherit when app is mounted
* Generate `ETag`s for all request responses
- No longer restricted to only responses for `GET` and `HEAD` requests
* Use `content-type` to parse `Content-Type` headers
* deps: connect@2.29.0
- Use `content-type` to parse `Content-Type` headers
- deps: body-parser@~1.12.0
- deps: compression@~1.4.1
- deps: connect-timeout@~1.6.0
- deps: cookie-parser@~1.3.4
- deps: cookie-signature@1.0.6
- deps: csurf@~1.7.0
- deps: errorhandler@~1.3.4
- deps: express-session@~1.10.3
- deps: http-errors@~1.3.1
- deps: response-time@~2.3.0
- deps: serve-index@~1.6.2
- deps: serve-static@~1.9.1
- deps: type-is@~1.6.0
* deps: cookie-signature@1.0.6
* deps: send@0.12.1
- Always read the stat size from the file
- Fix mutating passed-in `options`
- deps: mime@1.3.4
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
===================
@@ -686,7 +930,7 @@
* update commander
* jsonp: check if callback is a function
* router: wrap encodeURIComponent in a try/catch #1735 (@lxe)
* res.format: now includes chraset @1747 (@sorribas)
* res.format: now includes charset @1747 (@sorribas)
* res.links: allow multiple calls @1746 (@sorribas)
3.4.0 / 2013-09-07
@@ -965,7 +1209,7 @@
* Added another example to content-negotiation
* Added `fresh` dep
* Changed: `res.send()` always checks freshness
* Fixed: expose connects mime module. Cloases #1165
* Fixed: expose connects mime module. Closes #1165
3.0.0beta2 / 2012-06-06
==================
@@ -1047,7 +1291,7 @@
* Added `req.ips`
* Added `req.fresh`
* Added `req.stale`
* Added comma-delmited / array support for `req.accepts()`
* Added comma-delimited / array support for `req.accepts()`
* Added debug instrumentation
* Added `res.set(obj)`
* Added `res.set(field, value)`

View File

@@ -1,6 +1,8 @@
(The MIT License)
Copyright (c) 2009-2013 TJ Holowaychuk <tj@vision-media.ca>
Copyright (c) 2013 Roman Shtylman <shtylman+expressjs@gmail.com>
Copyright (c) 2014-2015 Douglas Christopher Wilson <doug@somethingdoug.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

View File

@@ -2,10 +2,10 @@
Fast, unopinionated, minimalist web framework for [node](http://nodejs.org).
[![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/)
[![NPM version](https://img.shields.io/npm/v/express.svg)](https://www.npmjs.org/package/express)
[![Build Status](https://img.shields.io/travis/strongloop/express/3.x.svg)](https://travis-ci.org/strongloop/express)
[![Coverage Status](https://img.shields.io/coveralls/strongloop/express/3.x.svg)](https://coveralls.io/r/strongloop/express)
[![Gratipay](https://img.shields.io/gratipay/dougwilson.svg)](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

@@ -16,12 +16,20 @@ var users = [
, { name: 'bandit' }
];
// Create HTTP error
function createError(status, message) {
var err = new Error(message);
err.status = status;
return err;
}
// Convert :to and :from to integers
app.param(['to', 'from'], function(req, res, next, num, name){
req.params[name] = parseInt(num, 10);
if( isNaN(req.params[name]) ){
next(new Error('failed to parseInt '+num));
next(createError(400, 'failed to parseInt '+num));
} else {
next();
}
@@ -33,7 +41,7 @@ app.param('user', function(req, res, next, id){
if (req.user = users[id]) {
next();
} else {
next(new Error('failed to find user'));
next(createError(404, 'failed to find user'));
}
});

View File

@@ -1,5 +1,14 @@
/*!
* express
* Copyright(c) 2009-2013 TJ Holowaychuk
* Copyright(c) 2013 Roman Shtylman
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
/**
* Module dependencies.
* @api private
*/
var connect = require('connect')
@@ -21,6 +30,13 @@ var merge = require('utils-merge');
var app = exports = module.exports = {};
/**
* Variable for trust proxy inheritance back-compat
* @api private
*/
var trustProxyDefaultSymbol = '@@symbol:trust_proxy_default';
/**
* Initialize the server.
*
@@ -53,14 +69,27 @@ app.defaultConfiguration = function(){
this.set('subdomain offset', 2);
this.set('trust proxy', false);
// trust proxy inherit back-compat
Object.defineProperty(this.settings, trustProxyDefaultSymbol, {
configurable: true,
value: true
});
debug('booting in %s mode', env);
// implicit middleware
this.use(connect.query());
this.use(middleware.init(this));
// inherit protos
this.on('mount', function(parent){
this.on('mount', function onmount(parent) {
// inherit trust proxy
if (this.settings[trustProxyDefaultSymbol] === true
&& typeof parent.settings['trust proxy fn'] === 'function') {
delete this.settings['trust proxy'];
delete this.settings['trust proxy fn'];
}
// inherit protos
this.request.__proto__ = parent.request;
this.response.__proto__ = parent.response;
this.engines.__proto__ = parent.engines;
@@ -271,6 +300,13 @@ app.set = function(setting, val){
case 'trust proxy':
debug('compile trust proxy %s', val);
this.set('trust proxy fn', compileTrust(val));
// trust proxy inherit back-compat
Object.defineProperty(this.settings, trustProxyDefaultSymbol, {
configurable: true,
value: false
});
break;
}

View File

@@ -358,7 +358,7 @@ req.__defineGetter__('protocol', function(){
: 'http';
var trust = this.app.get('trust proxy fn');
if (!trust(this.connection.remoteAddress)) {
if (!trust(this.connection.remoteAddress, 0)) {
return proto;
}
@@ -491,7 +491,7 @@ req.__defineGetter__('host', function(){
var trust = this.app.get('trust proxy fn');
var host = this.get('X-Forwarded-Host');
if (!host || !trust(this.connection.remoteAddress)) {
if (!host || !trust(this.connection.remoteAddress, 0)) {
host = this.get('Host');
}
@@ -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

@@ -1,5 +1,13 @@
/*!
* express
* Copyright(c) 2009-2013 TJ Holowaychuk
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
/**
* Module dependencies.
* @api private
*/
var contentDisposition = require('content-disposition');
@@ -86,7 +94,6 @@ res.links = function(links){
res.send = function(body){
var req = this.req;
var head = 'HEAD' == req.method;
var type;
var encoding;
var len;
@@ -153,12 +160,12 @@ res.send = function(body){
this.set('Content-Length', len);
}
// ETag support
var etag = len !== undefined && app.get('etag fn');
if (etag && ('GET' === req.method || 'HEAD' === req.method)) {
if (!this.get('ETag')) {
etag = etag(body, encoding);
etag && this.set('ETag', etag);
// populate ETag
var etag;
var generateETag = len !== undefined && app.get('etag fn');
if (typeof generateETag === 'function' && !this.get('ETag')) {
if ((etag = generateETag(body, encoding))) {
this.set('ETag', etag);
}
}
@@ -173,8 +180,13 @@ res.send = function(body){
body = '';
}
// respond
this.end((head ? null : body), encoding);
if (req.method === 'HEAD') {
// skip body for HEAD
this.end();
} else {
// respond
this.end(body, encoding);
}
return this;
};

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

@@ -1,12 +1,19 @@
/*!
* express
* Copyright(c) 2009-2013 TJ Holowaychuk
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
/**
* Module dependencies.
* @api private
*/
var contentType = require('content-type');
var etag = require('etag');
var mime = require('connect').mime;
var proxyaddr = require('proxy-addr');
var typer = require('media-typer');
/**
* toString ref.
@@ -393,15 +400,17 @@ exports.compileTrust = function(val) {
* @api private
*/
exports.setCharset = function(type, charset){
if (!type || !charset) return type;
exports.setCharset = function setCharset(type, charset) {
if (!type || !charset) {
return type;
}
// parse type
var parsed = typer.parse(type);
var parsed = contentType.parse(type);
// set charset
parsed.parameters.charset = charset;
// format type
return typer.format(parsed);
return contentType.format(parsed);
};

View File

@@ -1,7 +1,7 @@
{
"name": "express",
"description": "Sinatra inspired web development framework",
"version": "3.18.4",
"version": "3.21.2",
"author": "TJ Holowaychuk <tj@vision-media.ca>",
"contributors": [
"Aaron Heckmann <aaron.heckmann+github@gmail.com>",
@@ -26,38 +26,36 @@
"api"
],
"dependencies": {
"basic-auth": "1.0.0",
"connect": "2.27.4",
"basic-auth": "~1.0.3",
"connect": "2.30.2",
"content-disposition": "0.5.0",
"commander": "1.3.2",
"cookie-signature": "1.0.5",
"debug": "~2.1.0",
"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",
"mkdirp": "0.5.0",
"content-type": "~1.0.1",
"commander": "2.6.0",
"cookie": "0.1.3",
"cookie-signature": "1.0.6",
"debug": "~2.2.0",
"depd": "~1.0.1",
"escape-html": "1.0.2",
"etag": "~1.7.0",
"fresh": "0.3.0",
"merge-descriptors": "1.0.0",
"methods": "~1.1.1",
"mkdirp": "0.5.1",
"parseurl": "~1.3.0",
"proxy-addr": "~1.0.4",
"proxy-addr": "~1.0.8",
"range-parser": "~1.0.2",
"send": "0.10.1",
"send": "0.13.0",
"utils-merge": "1.0.0",
"vary": "~1.0.0",
"cookie": "0.1.2",
"merge-descriptors": "0.0.2"
"vary": "~1.0.1"
},
"devDependencies": {
"connect-redis": "~1.5.0",
"istanbul": "0.3.2",
"mocha": "~2.0.0",
"should": "~4.3.0",
"supertest": "~0.15.0",
"ejs": "~1.0.0",
"jade": "~1.7.0",
"hjs": "~0.0.6",
"marked": "0.3.2"
"ejs": "2.3.3",
"istanbul": "0.3.9",
"marked": "0.3.5",
"mocha": "2.2.5",
"should": "7.0.2",
"supertest": "1.0.1"
},
"engines": {
"node": ">= 0.8.0"

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

@@ -0,0 +1,36 @@
var app = require('../../examples/cookie-sessions')
var request = require('supertest')
function getCookie(res) {
return res.headers['set-cookie'][0].split(';')[0]
}
describe('cookie-sessions', function () {
describe('GET /', function () {
it('should display no views', function (done) {
request(app)
.get('/')
.expect(200, 'viewed 0 times\n', done)
})
it('should set a session cookie', function (done) {
request(app)
.get('/')
.expect('Set-Cookie', /connect\.sess=/)
.expect(200, done)
})
it('should display 1 view on revisit', function (done) {
request(app)
.get('/')
.expect(200, 'viewed 0 times\n', function (err, res) {
if (err) return done(err)
request(app)
.get('/')
.set('Cookie', getCookie(res))
.expect(200, 'viewed 1 times\n', done)
})
})
})
})

View File

@@ -35,7 +35,7 @@ describe('mvc', function(){
.put('/pet/3')
.set('Content-Type', 'application/x-www-form-urlencoded')
.send({ pet: { name: 'Boots' } })
.end(function(err, res){
.expect(302, function (err, res) {
if (err) return done(err);
request(app)
.get('/pet/3/edit')
@@ -98,7 +98,7 @@ describe('mvc', function(){
.put('/user/1')
.set('Content-Type', 'application/x-www-form-urlencoded')
.send({ user: { name: 'Tobo' }})
.end(function(err, res){
.expect(302, function (err, res) {
if (err) return done(err);
request(app)
.get('/user/1/edit')

View File

@@ -21,8 +21,8 @@ describe('params', function(){
describe('GET /user/9', function(){
it('should fail to find user', function(done){
request(app)
.get('/user/9')
.expect(/failed to find user/,done)
.get('/user/9')
.expect(404, /failed to find user/, done)
})
})
@@ -37,8 +37,8 @@ describe('params', function(){
describe('GET /users/foo-bar', function(){
it('should fail integer parsing', function(done){
request(app)
.get('/users/foo-bar')
.expect(/failed to parseInt foo/,done)
.get('/users/foo-bar')
.expect(400, /failed to parseInt foo/, done)
})
})
})

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,6 +1,7 @@
var express = require('../')
, request = require('supertest');
var assert = require('assert');
var express = require('..');
var request = require('supertest');
describe('app', function(){
it('should emit "mount" when mounted', function(done){

View File

@@ -1,30 +1,36 @@
var express = require('../')
, assert = require('assert');
var assert = require('assert');
var express = require('..');
describe('config', function(){
describe('.set()', function(){
it('should set a value', function(){
describe('config', function () {
describe('.set()', function () {
it('should set a value', function () {
var app = express();
app.set('foo', 'bar').should.equal(app);
app.set('foo', 'bar');
assert.equal(app.get('foo'), 'bar');
})
it('should return the app when undefined', function(){
it('should return the app', function () {
var app = express();
app.set('foo', undefined).should.equal(app);
assert.equal(app.set('foo', 'bar'), app);
})
it('should return the app when undefined', function () {
var app = express();
assert.equal(app.set('foo', undefined), app);
})
describe('"etag"', function(){
it('should throw on bad value', function(){
var app = express()
app.set.bind(app, 'etag', 42).should.throw(/unknown value/)
var app = express();
assert.throws(app.set.bind(app, 'etag', 42), /unknown value/);
})
it('should set "etag fn"', function(){
var app = express()
var fn = function(){}
app.set('etag', fn)
app.get('etag fn').should.equal(fn)
assert.equal(app.get('etag fn'), fn)
})
})
@@ -33,7 +39,7 @@ describe('config', function(){
var app = express()
var fn = function(){}
app.set('trust proxy', fn)
app.get('trust proxy fn').should.equal(fn)
assert.equal(app.get('trust proxy fn'), fn)
})
})
})
@@ -41,34 +47,73 @@ describe('config', function(){
describe('.get()', function(){
it('should return undefined when unset', function(){
var app = express();
assert(undefined === app.get('foo'));
assert.strictEqual(app.get('foo'), undefined);
})
it('should otherwise return the value', function(){
var app = express();
app.set('foo', 'bar');
app.get('foo').should.equal('bar');
assert.equal(app.get('foo'), 'bar');
})
describe('when mounted', function(){
it('should default to the parent app', function(){
var app = express()
, blog = express();
var app = express();
var blog = express();
app.set('title', 'Express');
app.use(blog);
blog.get('title').should.equal('Express');
assert.equal(blog.get('title'), 'Express');
})
it('should given precedence to the child', function(){
var app = express()
, blog = express();
var app = express();
var blog = express();
app.use(blog);
app.set('title', 'Express');
blog.set('title', 'Some Blog');
blog.get('title').should.equal('Some Blog');
assert.equal(blog.get('title'), 'Some Blog');
})
it('should inherit "trust proxy" setting', function () {
var app = express();
var blog = express();
function fn() { return false }
app.set('trust proxy', fn);
assert.equal(app.get('trust proxy'), fn);
assert.equal(app.get('trust proxy fn'), fn);
app.use(blog);
assert.equal(blog.get('trust proxy'), fn);
assert.equal(blog.get('trust proxy fn'), fn);
})
it('should prefer child "trust proxy" setting', function () {
var app = express();
var blog = express();
function fn1() { return false }
function fn2() { return true }
app.set('trust proxy', fn1);
assert.equal(app.get('trust proxy'), fn1);
assert.equal(app.get('trust proxy fn'), fn1);
blog.set('trust proxy', fn2);
assert.equal(blog.get('trust proxy'), fn2);
assert.equal(blog.get('trust proxy fn'), fn2);
app.use(blog);
assert.equal(app.get('trust proxy'), fn1);
assert.equal(app.get('trust proxy fn'), fn1);
assert.equal(blog.get('trust proxy'), fn2);
assert.equal(blog.get('trust proxy fn'), fn2);
})
})
})
@@ -76,42 +121,42 @@ describe('config', function(){
describe('.enable()', function(){
it('should set the value to true', function(){
var app = express();
app.enable('tobi').should.equal(app);
app.get('tobi').should.be.true;
assert.equal(app.enable('tobi'), app);
assert.strictEqual(app.get('tobi'), true);
})
})
describe('.disable()', function(){
it('should set the value to false', function(){
var app = express();
app.disable('tobi').should.equal(app);
app.get('tobi').should.be.false;
assert.equal(app.disable('tobi'), app);
assert.strictEqual(app.get('tobi'), false);
})
})
describe('.enabled()', function(){
it('should default to false', function(){
var app = express();
app.enabled('foo').should.be.false;
assert.strictEqual(app.enabled('foo'), false);
})
it('should return true when set', function(){
var app = express();
app.set('foo', 'bar');
app.enabled('foo').should.be.true;
assert.strictEqual(app.enabled('foo'), true);
})
})
describe('.disabled()', function(){
it('should default to true', function(){
var app = express();
app.disabled('foo').should.be.true;
assert.strictEqual(app.disabled('foo'), true);
})
it('should return false when set', function(){
var app = express();
app.set('foo', 'bar');
app.disabled('foo').should.be.false;
assert.strictEqual(app.disabled('foo'), false);
})
})
})

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

@@ -117,6 +117,24 @@ describe('req', function(){
.set('Host', 'example.com')
.expect('example.com', done);
})
describe('when trusting hop count', function () {
it('should respect X-Forwarded-Host', function (done) {
var app = express();
app.set('trust proxy', 1);
app.use(function (req, res) {
res.end(req.host);
});
request(app)
.get('/')
.set('Host', 'localhost')
.set('X-Forwarded-Host', 'example.com')
.expect('example.com', done);
})
})
})
describe('when "trust proxy" is disabled', function(){

View File

@@ -35,6 +35,23 @@ describe('req', function(){
.set('X-Forwarded-For', 'client, p1, p2')
.expect('p1', done);
})
it('should return the addr after trusted proxy, from sub app', function (done) {
var app = express();
var sub = express();
app.set('trust proxy', 2);
app.use(sub);
sub.use(function (req, res, next) {
res.send(req.ip);
});
request(app)
.get('/')
.set('X-Forwarded-For', 'client, p1, p2')
.expect(200, 'p1', done);
})
})
describe('when "trust proxy" is disabled', function(){

View File

@@ -75,6 +75,23 @@ describe('req', function(){
.get('/')
.expect('http', done);
})
describe('when trusting hop count', function () {
it('should respect X-Forwarded-Proto', function (done) {
var app = express();
app.set('trust proxy', 1);
app.use(function (req, res) {
res.end(req.protocol);
});
request(app)
.get('/')
.set('X-Forwarded-Proto', 'https')
.expect('https', done);
})
})
})
describe('when "trust proxy" is disabled', function(){

View File

@@ -78,6 +78,23 @@ describe('req', function(){
.set('X-Forwarded-Proto', 'https, http')
.expect('yes', done)
})
describe('when "trust proxy" trusting hop count', function () {
it('should respect X-Forwarded-Proto', function (done) {
var app = express();
app.set('trust proxy', 1);
app.get('/', function (req, res) {
res.send(req.secure ? 'yes' : 'no');
});
request(app)
.get('/')
.set('X-Forwarded-Proto', 'https')
.expect('yes', 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

@@ -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

@@ -1,7 +1,8 @@
var express = require('../')
, request = require('supertest')
, assert = require('assert');
var assert = require('assert');
var express = require('..');
var methods = require('methods');
var request = require('supertest');
describe('res', function(){
describe('.send(null)', function(){
@@ -110,35 +111,18 @@ describe('res', function(){
})
})
it('should set ETag', function(done){
it('should set ETag', function (done) {
var app = express();
app.use(function(req, res){
app.use(function (req, res) {
var str = Array(1024 * 2).join('-');
res.send(str);
});
request(app)
.get('/')
.expect('ETag', 'W/"fz/jGo0ONwzb+aKy/rWipg=="')
.end(done);
})
it('should not set ETag for non-GET/HEAD', function(done){
var app = express();
app.use(function(req, res){
var str = Array(1024 * 2).join('-');
res.send(str);
});
request(app)
.post('/')
.end(function(err, res){
if (err) return done(err);
assert(!res.header.etag, 'has an ETag');
done();
});
.expect('ETag', 'W/"7ff-fFD7Se+Vsq6deAl063thow"')
.expect(200, done);
})
it('should not override Content-Type', function(done){
@@ -199,18 +183,18 @@ describe('res', function(){
})
})
it('should set ETag', function(done){
it('should set ETag', function (done) {
var app = express();
app.use(function(req, res){
app.use(function (req, res) {
var str = Array(1024 * 2).join('-');
res.send(new Buffer(str));
});
request(app)
.get('/')
.expect('ETag', 'W/"fz/jGo0ONwzb+aKy/rWipg=="')
.end(done);
.expect('ETag', 'W/"7ff-fFD7Se+Vsq6deAl063thow"')
.expect(200, done);
})
it('should not override Content-Type', function(done){
@@ -325,7 +309,7 @@ describe('res', function(){
request(app)
.get('/')
.set('If-None-Match', 'W/"fz/jGo0ONwzb+aKy/rWipg=="')
.set('If-None-Match', 'W/"7ff-fFD7Se+Vsq6deAl063thow"')
.expect(304, done);
})
@@ -358,12 +342,12 @@ describe('res', function(){
.expect('{"foo":"bar"}', done);
})
describe('"etag" setting', function(){
describe('when enabled', function(){
it('should send ETag', function(done){
describe('"etag" setting', function () {
describe('when enabled', function () {
it('should send ETag', function (done) {
var app = express();
app.use(function(req, res){
app.use(function (req, res) {
res.send('kajdslfkasdf');
});
@@ -371,76 +355,95 @@ describe('res', function(){
request(app)
.get('/')
.expect('etag', 'W/"c-5aee35d8"', done)
})
it('should send ETag for empty string response', function(done){
var app = express()
app.use(function(req, res){
res.send('')
});
app.enable('etag')
request(app)
.get('/')
.expect('etag', 'W/"0-0"', done)
})
it('should send ETag for long response', function(done){
var app = express();
app.use(function(req, res){
var str = Array(1024 * 2).join('-');
res.send(str);
});
app.enable('etag');
request(app)
.get('/')
.expect('etag', 'W/"fz/jGo0ONwzb+aKy/rWipg=="', done)
.expect('ETag', 'W/"c-ZUfd0NJ26qwjlKF4r8qb2g"')
.expect(200, done);
});
it('should not override ETag when manually set', function(done){
var app = express();
methods.forEach(function (method) {
if (method === 'connect') return;
app.use(function(req, res){
res.set('etag', '"asdf"');
res.send(200);
});
it('should send ETag in response to ' + method.toUpperCase() + ' request', function (done) {
var app = express();
app.enable('etag');
app[method]('/', function (req, res) {
res.send('kajdslfkasdf');
});
request(app)
.get('/')
.expect('etag', '"asdf"', done)
});
it('should not send ETag for res.send()', function(done){
var app = express()
app.use(function(req, res){
res.send()
});
app.enable('etag')
request(app)
.get('/')
.end(function(err, res){
res.headers.should.not.have.property('etag');
done();
request(app)
[method]('/')
.expect('ETag', 'W/"c-ZUfd0NJ26qwjlKF4r8qb2g"')
.expect(200, done);
})
});
it('should send ETag for empty string response', function (done) {
var app = express();
app.use(function (req, res) {
res.send('');
});
app.enable('etag');
request(app)
.get('/')
.expect('ETag', 'W/"0-1B2M2Y8AsgTpgAmY7PhCfg"')
.expect(200, done);
})
it('should send ETag for long response', function (done) {
var app = express();
app.use(function (req, res) {
var str = Array(1024 * 2).join('-');
res.send(str);
});
app.enable('etag');
request(app)
.get('/')
.expect('ETag', 'W/"7ff-fFD7Se+Vsq6deAl063thow"')
.expect(200, done);
});
it('should not override ETag when manually set', function (done) {
var app = express();
app.use(function (req, res) {
res.set('etag', '"asdf"');
res.send(200);
});
app.enable('etag');
request(app)
.get('/')
.expect('ETag', '"asdf"')
.expect(200, done);
});
it('should not send ETag for res.send()', function (done) {
var app = express();
app.use(function (req, res) {
res.send();
});
app.enable('etag');
request(app)
.get('/')
.expect(shouldNotHaveHeader('ETag'))
.expect(200, done);
})
});
describe('when disabled', function(){
it('should send no ETag', function(done){
describe('when disabled', function () {
it('should send no ETag', function (done) {
var app = express();
app.use(function(req, res){
app.use(function (req, res) {
var str = Array(1024 * 2).join('-');
res.send(str);
});
@@ -449,97 +452,103 @@ describe('res', function(){
request(app)
.get('/')
.end(function(err, res){
res.headers.should.not.have.property('etag');
done();
});
.expect(shouldNotHaveHeader('ETag'))
.expect(200, done);
});
it('should send ETag when manually set', function(done){
it('should send ETag when manually set', function (done) {
var app = express();
app.disable('etag');
app.use(function(req, res){
app.use(function (req, res) {
res.set('etag', '"asdf"');
res.send(200);
});
request(app)
.get('/')
.expect('etag', '"asdf"', done)
.expect('ETag', '"asdf"')
.expect(200, done);
});
});
describe('when "strong"', function(){
it('should send strong ETag', function(done){
var app = express()
describe('when "strong"', function () {
it('should send strong ETag', function (done) {
var app = express();
app.set('etag', 'strong');
app.use(function(req, res){
app.use(function (req, res) {
res.send('hello, world!');
});
request(app)
.get('/')
.expect('etag', '"Otu60XkfuuPskIiUxJY4cA=="', done)
.expect('ETag', '"d-Otu60XkfuuPskIiUxJY4cA"')
.expect(200, done);
})
})
describe('when "weak"', function(){
it('should send weak ETag', function(done){
var app = express()
describe('when "weak"', function () {
it('should send weak ETag', function (done) {
var app = express();
app.set('etag', 'weak');
app.use(function(req, res){
app.use(function (req, res) {
res.send('hello, world!');
});
request(app)
.get('/')
.expect('etag', 'W/"d-58988d13"', done)
.expect('ETag', 'W/"d-Otu60XkfuuPskIiUxJY4cA"')
.expect(200, done)
})
})
describe('when a function', function(){
it('should send custom ETag', function(done){
var app = express()
describe('when a function', function () {
it('should send custom ETag', function (done) {
var app = express();
app.set('etag', function(body, encoding){
body.should.equal('hello, world!')
encoding.should.equal('utf8')
return '"custom"'
app.set('etag', function (body, encoding) {
body.should.equal('hello, world!');
encoding.should.equal('utf8');
return '"custom"';
});
app.use(function(req, res){
app.use(function (req, res) {
res.send('hello, world!');
});
request(app)
.get('/')
.expect('etag', '"custom"', done)
.expect('ETag', '"custom"')
.expect(200, done);
})
it('should not send falsy ETag', function(done){
var app = express()
it('should not send falsy ETag', function (done) {
var app = express();
app.set('etag', function(body, encoding){
return undefined
app.set('etag', function (body, encoding) {
return undefined;
});
app.use(function(req, res){
app.use(function (req, res) {
res.send('hello, world!');
});
request(app)
.get('/')
.end(function(err, res){
res.headers.should.not.have.property('etag')
done();
})
.expect(shouldNotHaveHeader('ETag'))
.expect(200, done);
})
})
})
})
function shouldNotHaveHeader(header) {
return function (res) {
assert.ok(!(header.toLowerCase() in res.headers), 'should not have header ' + header)
}
}

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

@@ -5,46 +5,46 @@ var utils = require('../lib/utils')
describe('utils.etag(body, encoding)', function(){
it('should support strings', function(){
utils.etag('express!')
.should.eql('"zZdv4imtWD49AHEviejT6A=="')
.should.eql('"8-zZdv4imtWD49AHEviejT6A"')
})
it('should support utf8 strings', function(){
utils.etag('express❤', 'utf8')
.should.eql('"fsFba4IxwQS6h6Umb+FNxw=="')
.should.eql('"a-fsFba4IxwQS6h6Umb+FNxw"')
})
it('should support buffer', function(){
var buf = new Buffer('express!')
utils.etag(buf)
.should.eql('"zZdv4imtWD49AHEviejT6A=="');
.should.eql('"8-zZdv4imtWD49AHEviejT6A"');
})
it('should support empty string', function(){
utils.etag('')
.should.eql('"1B2M2Y8AsgTpgAmY7PhCfg=="');
.should.eql('"0-1B2M2Y8AsgTpgAmY7PhCfg"');
})
})
describe('utils.wetag(body, encoding)', function(){
it('should support strings', function(){
utils.wetag('express!')
.should.eql('W/"8-b8aabac7"')
.should.eql('W/"8-zZdv4imtWD49AHEviejT6A"')
})
it('should support utf8 strings', function(){
utils.wetag('express❤', 'utf8')
.should.eql('W/"a-686b0af1"')
.should.eql('W/"a-fsFba4IxwQS6h6Umb+FNxw"')
})
it('should support buffer', function(){
var buf = new Buffer('express!')
utils.wetag(buf)
.should.eql('W/"8-b8aabac7"');
.should.eql('W/"8-zZdv4imtWD49AHEviejT6A"');
})
it('should support empty string', function(){
utils.wetag('')
.should.eql('W/"0-0"');
.should.eql('W/"0-1B2M2Y8AsgTpgAmY7PhCfg"');
})
})