Compare commits

...

90 Commits

Author SHA1 Message Date
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
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
61 changed files with 1133 additions and 593 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

@@ -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,216 @@
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
===================
* 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
===================

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

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

@@ -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')
@@ -11,9 +20,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.
@@ -21,6 +30,13 @@ var deprecate = require('depd')('express');
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;
}
@@ -484,13 +520,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

@@ -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,15 +1,24 @@
/**
* Module dependencies.
/*!
* 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');
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
@@ -85,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;
@@ -152,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);
}
}
@@ -172,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;
};
@@ -413,15 +426,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 +559,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 +625,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 +653,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 +755,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

@@ -1,13 +1,19 @@
/*!
* express
* Copyright(c) 2009-2013 TJ Holowaychuk
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
/**
* Module dependencies.
* @api private
*/
var crc = require('crc').crc32;
var mime = require('connect').mime
, proxyaddr = require('proxy-addr')
, crypto = require('crypto');
var typer = require('media-typer');
var contentType = require('content-type');
var etag = require('etag');
var mime = require('connect').mime;
var proxyaddr = require('proxy-addr');
/**
* toString ref.
@@ -24,17 +30,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 +48,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});
};
/**
@@ -404,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.17.7",
"version": "3.20.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,37 @@
"app",
"api"
],
"repository": "strongloop/express",
"license": "MIT",
"homepage": "http://expressjs.com/",
"dependencies": {
"basic-auth": "1.0.0",
"connect": "2.26.5",
"commander": "1.3.2",
"cookie-signature": "1.0.5",
"crc": "3.0.0",
"debug": "~2.0.0",
"depd": "0.4.5",
"connect": "2.29.1",
"content-disposition": "0.5.0",
"content-type": "~1.0.1",
"commander": "2.6.0",
"cookie": "0.1.2",
"cookie-signature": "1.0.6",
"debug": "~2.1.3",
"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",
"merge-descriptors": "1.0.0",
"methods": "~1.1.1",
"mkdirp": "0.5.0",
"parseurl": "~1.3.0",
"proxy-addr": "~1.0.3",
"proxy-addr": "~1.0.7",
"range-parser": "~1.0.2",
"send": "0.9.3",
"vary": "~1.0.0",
"cookie": "0.1.2",
"merge-descriptors": "0.0.2"
"send": "0.12.2",
"utils-merge": "1.0.0",
"vary": "~1.0.0"
},
"devDependencies": {
"connect-redis": "~1.5.0",
"istanbul": "0.3.2",
"mocha": "~1.21.4",
"should": "~4.0.0",
"supertest": "~0.14.0",
"ejs": "~1.0.0",
"jade": "~1.6.0",
"hjs": "~0.0.6",
"marked": "0.3.2"
"ejs": "2.3.1",
"istanbul": "0.3.8",
"marked": "0.3.3",
"mocha": "~2.2.1",
"should": "~5.2.0",
"supertest": "~0.15.0"
},
"engines": {
"node": ">= 0.8.0"
@@ -63,8 +63,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

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

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

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

@@ -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/"7ff-2796319984"')
.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/"fz/jGo0ONwzb+aKy/rWipg=="')
.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/"7ff-2796319984"')
.end(done);
.expect('ETag', 'W/"fz/jGo0ONwzb+aKy/rWipg=="')
.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/"7ff-2796319984"')
.set('If-None-Match', 'W/"fz/jGo0ONwzb+aKy/rWipg=="')
.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-1525560792"', 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/"7ff-2796319984"', done)
.expect('ETag', 'W/"c-5aee35d8"')
.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-5aee35d8"')
.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-0"')
.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/"fz/jGo0ONwzb+aKy/rWipg=="')
.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', '"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-1486392595"', done)
.expect('ETag', 'W/"d-58988d13"')
.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

@@ -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(){