Comparar commits

...

95 Commits

Autor SHA1 Mensagem Data
Roman Shtylman b0da4b1a94 streaming view rendering
Allows for a view engine to return a stream upon being asked to render a
path. This allows for the engine to simply stream out data as it is
loaded from disk (or other IO location) without having to collect it all
first and then send it.

Fallback mode for all existing engines that call `fn` upon completion
takes over if no stream is returned. This works for both app.render and
res.render
2013-11-09 21:27:01 -05:00
Jonathan Ong 2bc703cfc2 Merge pull request #1802 from kapouer/patch-1
Remove leading ./ when using res.location('./relative')
2013-11-02 15:09:30 -07:00
Jérémy Lal c9865b821d Test location with leading ./ and containing .. 2013-11-02 02:28:54 +01:00
Jérémy Lal 9c0de23645 Update tests expectancy of location headers 2013-11-02 02:28:49 +01:00
Jérémy Lal b7a38af41d Use url.resolve to compute location header of relative paths 2013-11-02 02:28:29 +01:00
Jérémy Lal 661914781e semicolons 2013-11-02 00:39:32 +01:00
Jonathan Ong 6e3f3887e9 pin deps using semver1
somebody is going to complain that they can't install stuff because
they haven't upgraded npm
2013-10-30 20:55:11 -07:00
Jonathan Ong a66d6bb034 pin dev deps to semver compatible versions 2013-10-30 20:51:10 -07:00
Jonathan Ong 2e197e2b98 be less picky with ENOENT errors in tests
closes #1580
2013-10-30 20:37:01 -07:00
Jonathan Ong 55d1a4f964 always send ETag when content-length > 0
closes #1780
2013-10-30 20:34:16 -07:00
Jonathan Ong 82a7d7a977 no semver2 so travis stops crying 2013-10-29 22:44:01 -07:00
Jonathan Ong dae54b456f 3.4.4 2013-10-29 10:33:32 -07:00
Jonathan Ong 1b7a044f33 bump connect 2013-10-29 10:30:26 -07:00
Jonathan Ong 18264403b1 bump supertest to 0.8.1 2013-10-28 15:24:48 -07:00
Jonathan Ong 04d43b7039 remove .gitmodules
it's empty
2013-10-28 14:38:46 -07:00
TJ Holowaychuk 2dfecfb661 update methods for SEARCH 2013-10-28 12:02:24 -07:00
Jonathan Ong 250f1f5f6e Merge pull request #1796 from malixsys/patch-1
2013-100-23 -> 2013-10-23
2013-10-25 10:59:48 -07:00
M Alix 3ac718763f 2013-100-23 -> 2013-10-23 2013-10-25 14:28:24 +02:00
Jonathan Ong 05e1555c0d Merge pull request #1795 from chirag04/master
replace bodyparser with json and urlencoded
2013-10-25 03:31:24 -07:00
chirag04 855d1e2bf5 replace bodyparser with json and urlencoded 2013-10-25 15:45:25 +05:30
Jonathan Ong f0bfb3b2b2 3.4.3 2013-10-23 11:19:48 -07:00
Jonathan Ong 4b4db0f7fb 3.4.2 2013-10-18 19:03:41 -07:00
Jonathan Ong 9bed2b80ee lint: remove unused stuff 2013-10-18 01:18:56 -07:00
Jonathan Ong bb157c0cbf replace old contributors info with github's contributors 2013-10-17 13:06:13 -07:00
Jonathan Ong 1ef05d4a28 downgrade commander. closes #1783 2013-10-17 12:57:39 -07:00
TJ Holowaychuk 0b88208022 Merge branch 'master' of github.com:visionmedia/express 2013-10-16 19:52:00 -07:00
TJ Holowaychuk c9d9ed3493 fix res.sendfile() callback
what the hell... I was just told readable streams have finish not end,
make up your mind node!
2013-10-17 02:51:01 +00:00
TJ Holowaychuk bd8b9f5781 Merge branch 'master' of github.com:visionmedia/express 2013-10-16 19:21:09 -07:00
TJ Holowaychuk 9cbcf23df0 docs 2013-10-16 19:17:49 -07:00
Jonathan Ong 36e42db05b mocha globals - readable-stream defines globals
isaac you bastard
2013-10-15 18:33:47 -07:00
Jonathan Ong 2bf6a1d813 3.4.1 2013-10-15 18:28:49 -07:00
Jonathan Ong e8373d3564 Merge pull request #1779 from visionmedia/jsonp-typeof-callback
check existence of jsonp callback
2013-10-15 18:22:01 -07:00
Jonathan Ong e218377a3d check existence of jsonp callback 2013-10-15 12:39:32 -07:00
Jonathan Ong 7d1aed4955 update commander. closes #1693
i hope this doesn't break anything
2013-10-14 21:22:19 -07:00
Jonathan Ong b4acbcf1fe use path.join for 'views' setting. closes #1427 2013-10-14 21:16:57 -07:00
Jonathan Ong 50cb62c5d2 fix tests for should.js 2013-10-14 18:35:46 -07:00
Jonathan Ong 4cf868bd74 Merge pull request #1776 from ykumar6/master
Add Runnable.com button
2013-10-14 18:33:34 -07:00
Yash Kumar baa5a7c3e9 Add Runnable.com button 2013-10-14 14:16:18 -07:00
Jonathan Ong ee228f7aea Merge pull request #1759 from muratgu/patch-1
fixes #1600
2013-09-19 12:43:42 -07:00
Jonathan Ong d5b11c7d1b Merge pull request #1760 from jseip1679/master
documentation language fix
2013-09-19 12:38:21 -07:00
Jake Seip ed7db34bab documentation language fix 2013-09-19 10:41:45 -07:00
muratgu 57e45e3af8 fixes #1600 2013-09-19 10:27:21 -07:00
Jonathan Ong 1dc46478cb README: add more links to expressjs.com 2013-09-17 00:35:23 -07:00
TJ Holowaychuk 113ed0927d fix test label typo 2013-09-16 23:34:16 +00:00
TJ Holowaychuk ab8be2d741 remove second signed cookie test
for now
2013-09-16 23:33:42 +00:00
TJ Holowaychuk 3b53b11fcd fix signed cookies test 2013-09-16 23:32:34 +00:00
TJ Holowaychuk 9fb661559b refactor signed cookie tests 2013-09-16 23:24:54 +00:00
Jonathan Ong 04882cf72c Merge pull request #1735 from lxe/malformed-capture-route
Wrapped encodeURIcomponent in try-catch to eliminate errors on malformed captures.
2013-09-16 15:32:57 -07:00
lxe 288176bbc9 Added safe encodeURIcomponent to eliminate errors on malformed captures. 2013-09-16 14:57:31 -04:00
Jonathan Ong 5638a4fc62 Merge pull request #1688 from menzoic/issue/menzoic-1
removed unnecessary require statement
2013-09-09 21:45:19 -07:00
TJ Holowaychuk 3b4ce91fa3 refactor res.format() with a little ocd 2013-09-08 09:30:59 -07:00
TJ Holowaychuk 1c87e5e9a8 Merge pull request #1747 from sorribas/master
res.format() now includes charset.
2013-09-08 09:30:23 -07:00
Eduardo Sorribas a887e6a881 Minor refactor of res.format 2013-09-08 02:34:52 -04:00
Eduardo Sorribas 69290cad6f res.format() now includes charset. Fixes #1744 2013-09-08 02:10:46 -04:00
Jonathan Ong b66c7da05f Merge pull request #1659 from dresende/patch-1
Fixes typo in index.js vhost example
2013-09-07 21:43:45 -07:00
Jonathan Ong 92ddf77453 Merge pull request #1729 from patelatharva/patch-1
Improved variable names and updated comments for better clarity of example
2013-09-07 21:43:06 -07:00
TJ Holowaychuk 8e2f538983 refactor res.links() 2013-09-07 15:26:12 -07:00
TJ Holowaychuk 2817d8caf2 Merge pull request #1746 from sorribas/master
Allow multiple call concatenation for res.links.
2013-09-07 15:24:50 -07:00
TJ Holowaychuk b7f08fb159 Release 3.4.0 2013-09-07 12:25:00 -07:00
TJ Holowaychuk 0c2768f5bd update connect 2013-09-07 12:24:24 -07:00
Eduardo Sorribas 09bede1a92 Fix the links test so it resets the header for each test. 2013-09-07 01:10:13 -04:00
Eduardo Sorribas 7059d3b71e Allow multiple call concatenation for res.links. Fixes #1683 2013-09-06 21:44:03 -04:00
cjihrig e5de08faa1 add res.vary(). Closes #1682 2013-09-02 09:10:14 -07:00
TJ Holowaychuk e43ff076fd Merge pull request #1740 from superic/master
Updated Util.isAbsolute(path) to return true for Azure absolute paths
2013-09-02 08:56:03 -07:00
TJ Holowaychuk 3ea7381dea Merge pull request #1711 from jonjenkins/master
Fixes from pull request #1643
2013-09-02 08:55:23 -07:00
TJ Holowaychuk f1c46f51e5 Release 3.3.8 2013-09-02 08:01:07 -07:00
TJ Holowaychuk 297fb4e0b0 update connect 2013-09-02 08:00:48 -07:00
Eric Willis 9e406dfee2 Updated Util.isAbsolute(path) to return true for Azure absolute paths
- Azure absolute paths look like \\ip_address\volume\guid\guid\site\wwwroot\...file.js.
  Changed Util.isAbsolute to return true for paths that start with two backslashes.
2013-08-31 16:16:49 -07:00
TJ Holowaychuk 30b7aa8a17 update connect 2013-08-28 10:03:42 -07:00
TJ Holowaychuk c1d16e0016 Release 3.3.7 2013-08-28 09:39:31 -07:00
TJ Holowaychuk 929ffb8d77 update connect 2013-08-28 09:37:45 -07:00
TJ Holowaychuk 197a2e3b54 Release 3.3.6 2013-08-27 13:49:09 -07:00
TJ Holowaychuk 6cf6c8b918 Revert "remove charset from json responses. Closes #1631"
This reverts commit 138d74aefa.
2013-08-27 13:48:18 -07:00
Atharva 058d7ec2ea Improved variable names and updated comments for better clarity of example 2013-08-24 16:44:44 +05:30
TJ Holowaychuk 752b5f705e Merge branch 'master' of github.com:visionmedia/express 2013-08-17 01:07:17 -07:00
TJ Holowaychuk e7fa579637 update license 2013-08-17 01:07:09 -07:00
TJ Holowaychuk 97781d4112 Merge pull request #1723 from gmethvin/accepts
Make req.accepts take an argument list
2013-08-16 16:32:48 -07:00
Greg Methvin 3ddd8e66a7 Make req.accepts take an argument list 2013-08-16 15:19:33 -07:00
TJ Holowaychuk 8a1e865e37 remove silly out-of-date dep badge 2013-08-15 08:18:01 -07:00
TJ Holowaychuk e850cb3ea3 Release 3.3.5 2013-08-11 07:50:51 +10:00
TJ Holowaychuk 13d3efe8df update fresh 2013-08-11 07:49:15 +10:00
TJ Holowaychuk d6ecf785a2 Merge pull request #1710 from hacksparrow/master
Fixed test cases for res.format
2013-08-09 15:03:45 -07:00
Jon Jenkins 19cb39869f Fixes from pull request #1643, array method correction 2013-08-04 12:46:50 -05:00
Hage Yaapa a38bdf6758 fixed test cases for res.format 2013-08-04 20:32:08 +05:30
Jon Jenkins bdbdab7fcc Fixes from pull request #1643 2013-08-03 16:33:15 -05:00
TJ Holowaychuk 5aa9670120 Merge pull request #1685 from CharlesHolbrow/master
Fix typo in app.param comment
2013-08-02 14:46:40 -07:00
TJ Holowaychuk 8ad8cb93cc refactor 2013-08-02 14:46:25 -07:00
TJ Holowaychuk 610e172fcf Merge pull request #1694 from kavu/add_disable_etag
Add application setting to disable ETag (again)
2013-08-02 14:45:37 -07:00
TJ Holowaychuk 6942070a21 add [dir] to express(1) --help output. Closes #1699 2013-08-02 14:44:52 -07:00
TJ Holowaychuk e283200511 remove comma-first from express(1)-generated app 2013-08-01 11:10:21 -07:00
Max Riveiro 54a192a5c5 Add application setting to disable ETag completely 2013-07-21 12:49:28 +04:00
TJ Holowaychuk c3bd65eda2 Revert "remove old OPTIONS default response"
This reverts commit 2bba69f633.
2013-07-16 11:22:02 -07:00
Esco Obong 7c2ed1d2d6 removed unnecessary require statement 2013-07-15 02:13:32 -04:00
Charles Holbrow 3de81e0147 Fix typo in app.param comment 2013-07-13 16:32:02 -07:00
Diogo Resende 7a31a1d311 Fixes typo in index.js vhost example 2013-06-23 23:23:58 +02:00
35 arquivos alterados com 679 adições e 232 exclusões
Ver Arquivo
+1 -1
Ver Arquivo
@@ -1,4 +1,4 @@
language: node_js
node_js:
- "0.8"
- "0.10"
- "0.10"
+70 -20
Ver Arquivo
@@ -1,27 +1,77 @@
3.3.4 / 2013-07-08
3.4.4 / 2013-10-29
==================
* update send and connect
* update connect
* update supertest
* update methods
* express(1): replace bodyParser() with urlencoded() and json() #1795 @chirag04
3.3.3 / 2013-07-04
3.4.3 / 2013-10-23
==================
* update connect
3.3.2 / 2013-07-03
3.4.2 / 2013-10-18
==================
* update connect
* downgrade commander
3.4.1 / 2013-10-15
==================
* update connect
* 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.links: allow multiple calls @1746 (@sorribas)
3.4.0 / 2013-09-07
==================
* add res.vary(). Closes #1682
* update connect
3.3.8 / 2013-09-02
==================
* update connect
3.3.7 / 2013-08-28
==================
* update connect
3.3.6 / 2013-08-27
==================
* Revert "remove charset from json responses. Closes #1631" (causes issues in some clients)
* add: req.accepts take an argument list
3.3.4 / 2013-07-08
==================
* update send and connect
3.3.3 / 2013-07-04
==================
* update connect
3.3.2 / 2013-07-03
==================
* update connect
* update send
* remove .version export
3.3.1 / 2013-06-27
3.3.1 / 2013-06-27
==================
* update connect
3.3.0 / 2013-06-26
3.3.0 / 2013-06-26
==================
* update connect
@@ -30,12 +80,12 @@
* change: return actual booleans from req.accept* functions
* fix jsonp callback array throw
3.2.6 / 2013-06-02
3.2.6 / 2013-06-02
==================
* update connect
3.2.5 / 2013-05-21
3.2.5 / 2013-05-21
==================
* update connect
@@ -43,23 +93,23 @@
* add: throw a meaningful error when there is no default engine
* change generation of ETags with res.send() to GET requests only. Closes #1619
3.2.4 / 2013-05-09
3.2.4 / 2013-05-09
==================
* fix `req.subdomains` when no Host is present
* fix `req.host` when no Host is present, return undefined
3.2.3 / 2013-05-07
3.2.3 / 2013-05-07
==================
* update connect / qs
3.2.2 / 2013-05-03
3.2.2 / 2013-05-03
==================
* update qs
3.2.1 / 2013-04-29
3.2.1 / 2013-04-29
==================
* add app.VERB() paths array deprecation warning
@@ -67,27 +117,27 @@
* update qs and remove all ~ semver crap
* fix: accept number as value of Signed Cookie
3.2.0 / 2013-04-15
3.2.0 / 2013-04-15
==================
* add "view" constructor setting to override view behaviour
* add req.acceptsEncoding(name)
* add req.acceptedEncodings
* revert cookie signature change causing session race conditions
* fix sorting of Accept values of the same quality
* fix sorting of Accept values of the same quality
3.1.2 / 2013-04-12
3.1.2 / 2013-04-12
==================
* add support for custom Accept parameters
* update cookie-signature
3.1.1 / 2013-04-01
3.1.1 / 2013-04-01
==================
* add X-Forwarded-Host support to `req.host`
* fix relative redirects
* update mkdirp
* fix relative redirects
* update mkdirp
* update buffer-crc32
* remove legacy app.configure() method from app template.
+1 -1
Ver Arquivo
@@ -1,6 +1,6 @@
(The MIT License)
Copyright (c) 2009-2011 TJ Holowaychuk <tj@vision-media.ca>
Copyright (c) 2009-2013 TJ Holowaychuk <tj@vision-media.ca>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
+1
Ver Arquivo
@@ -9,6 +9,7 @@ test: test-unit test-acceptance
test-unit:
@NODE_ENV=test ./node_modules/.bin/mocha \
--reporter $(REPORTER) \
--globals setImmediate,clearImmediate \
$(MOCHA_OPTS)
test-acceptance:
+10 -63
Ver Arquivo
@@ -1,6 +1,8 @@
![express logo](http://f.cl.ly/items/0V2S1n0K1i3y1c122g04/Screen%20Shot%202012-04-11%20at%209.59.42%20AM.png)
[![express logo](http://f.cl.ly/items/0V2S1n0K1i3y1c122g04/Screen%20Shot%202012-04-11%20at%209.59.42%20AM.png)](http://expressjs.com/)
Fast, unopinionated, minimalist web framework for [node](http://nodejs.org). [![Build Status](https://secure.travis-ci.org/visionmedia/express.png)](http://travis-ci.org/visionmedia/express) [![Dependency Status](https://gemnasium.com/visionmedia/express.png)](https://gemnasium.com/visionmedia/express)
Fast, unopinionated, minimalist web framework for [node](http://nodejs.org).
[![Build Status](https://secure.travis-ci.org/visionmedia/express.png)](http://travis-ci.org/visionmedia/express) [![Gittip](http://img.shields.io/gittip/visionmedia.png)](https://www.gittip.com/visionmedia/)
```js
var express = require('express');
@@ -60,6 +62,7 @@ app.listen(3000);
## More Information
* [Website and Documentation](http://expressjs.com/) stored at [visionmedia/expressjs.com](https://github.com/visionmedia/expressjs.com)
* Join #express on freenode
* [Google Group](http://groups.google.com/group/express-js) for discussion
* Follow [tjholowaychuk](http://twitter.com/tjholowaychuk) on twitter for updates
@@ -79,6 +82,10 @@ then run whichever tests you want:
$ node examples/content-negotiation
You can also view live examples here
<a href="https://runnable.com/express" target="_blank"><img src="https://runnable.com/external/styles/assets/runnablebtn.png" style="width:67px;height:25px;"></a>
## Running Tests
To run the test suite first invoke the following command within the repo, installing the development dependencies:
@@ -91,67 +98,7 @@ then run the tests:
## Contributors
```
project: express
commits: 3559
active : 468 days
files : 237
authors:
1891 Tj Holowaychuk 53.1%
1285 visionmedia 36.1%
182 TJ Holowaychuk 5.1%
54 Aaron Heckmann 1.5%
34 csausdev 1.0%
26 ciaranj 0.7%
21 Robert Sköld 0.6%
6 Guillermo Rauch 0.2%
3 Dav Glass 0.1%
3 Nick Poulden 0.1%
2 Randy Merrill 0.1%
2 Benny Wong 0.1%
2 Hunter Loftis 0.1%
2 Jake Gordon 0.1%
2 Brian McKinney 0.1%
2 Roman Shtylman 0.1%
2 Ben Weaver 0.1%
2 Dave Hoover 0.1%
2 Eivind Fjeldstad 0.1%
2 Daniel Shaw 0.1%
1 Matt Colyer 0.0%
1 Pau Ramon 0.0%
1 Pero Pejovic 0.0%
1 Peter Rekdal Sunde 0.0%
1 Raynos 0.0%
1 Teng Siong Ong 0.0%
1 Viktor Kelemen 0.0%
1 ctide 0.0%
1 8bitDesigner 0.0%
1 isaacs 0.0%
1 mgutz 0.0%
1 pikeas 0.0%
1 shuwatto 0.0%
1 tstrimple 0.0%
1 ewoudj 0.0%
1 Adam Sanderson 0.0%
1 Andrii Kostenko 0.0%
1 Andy Hiew 0.0%
1 Arpad Borsos 0.0%
1 Ashwin Purohit 0.0%
1 Benjen 0.0%
1 Darren Torpey 0.0%
1 Greg Ritter 0.0%
1 Gregory Ritter 0.0%
1 James Herdman 0.0%
1 Jim Snodgrass 0.0%
1 Joe McCann 0.0%
1 Jonathan Dumaine 0.0%
1 Jonathan Palardy 0.0%
1 Jonathan Zacsh 0.0%
1 Justin Lilly 0.0%
1 Ken Sato 0.0%
1 Maciej Małecki 0.0%
1 Masahiro Hayashi 0.0%
```
https://github.com/visionmedia/express/graphs/contributors
## License
+12 -11
Ver Arquivo
@@ -4,8 +4,7 @@
* Module dependencies.
*/
var exec = require('child_process').exec
, program = require('commander')
var program = require('commander')
, mkdirp = require('mkdirp')
, pkg = require('../package.json')
, version = pkg.version
@@ -16,6 +15,7 @@ var exec = require('child_process').exec
program
.version(version)
.usage('[options] [dir]')
.option('-s, --sessions', 'add session support')
.option('-e, --ejs', 'add ejs engine support (defaults to jade)')
.option('-J, --jshtml', 'add jshtml engine support (defaults to jade)')
@@ -208,21 +208,22 @@ var app = [
, ' * Module dependencies.'
, ' */'
, ''
, 'var express = require(\'express\')'
, ' , routes = require(\'./routes\')'
, ' , user = require(\'./routes/user\')'
, ' , http = require(\'http\')'
, ' , path = require(\'path\');'
, 'var express = require(\'express\');'
, 'var routes = require(\'./routes\');'
, 'var user = require(\'./routes/user\');'
, 'var http = require(\'http\');'
, 'var path = require(\'path\');'
, ''
, 'var app = express();'
, ''
, '// all environments'
, 'app.set(\'port\', process.env.PORT || 3000);'
, 'app.set(\'views\', __dirname + \'/views\');'
, 'app.set(\'views\', path.join(__dirname, \'views\'));'
, 'app.set(\'view engine\', \':TEMPLATE\');'
, 'app.use(express.favicon());'
, 'app.use(express.logger(\'dev\'));'
, 'app.use(express.bodyParser());'
, 'app.use(express.json());'
, 'app.use(express.urlencoded());'
, 'app.use(express.methodOverride());{sess}'
, 'app.use(app.router);{css}'
, 'app.use(express.static(path.join(__dirname, \'public\')));'
@@ -323,10 +324,10 @@ function createApplicationAt(path) {
// CSS Engine support
switch (program.css) {
case 'less':
app = app.replace('{css}', eol + 'app.use(require(\'less-middleware\')({ src: __dirname + \'/public\' }));');
app = app.replace('{css}', eol + 'app.use(require(\'less-middleware\')({ src: path.join(__dirname, \'public\') }));');
break;
case 'stylus':
app = app.replace('{css}', eol + 'app.use(require(\'stylus\').middleware(__dirname + \'/public\'));');
app = app.replace('{css}', eol + 'app.use(require(\'stylus\').middleware(path.join(__dirname, \'public\')));');
break;
default:
app = app.replace('{css}', '');
+8 -6
Ver Arquivo
@@ -1,8 +1,9 @@
var express = require('../../')
, app = module.exports = express()
, users = require('./db');
// so either you can deal with different types of formatting
// for expected response in index.js
app.get('/', function(req, res){
res.format({
html: function(){
@@ -24,12 +25,13 @@ app.get('/', function(req, res){
});
// or you could write a tiny middleware like
// this to abstract make things a bit more declarative:
// this to add a layer of abstraction
// and make things a bit more declarative:
function format(mod) {
var obj = require(mod);
function format(requestHandlerName) {
var requestHandler = require(requestHandlerName);
return function(req, res){
res.format(obj);
res.format(requestHandler);
}
}
@@ -38,4 +40,4 @@ app.get('/users', format('./users'));
if (!module.parent) {
app.listen(3000);
console.log('listening on port 3000');
}
}
+1 -1
Ver Arquivo
@@ -23,7 +23,7 @@ main.get('/', function(req, res){
});
main.get('/:sub', function(req, res){
res.send('requsted ' + req.params.sub);
res.send('requested ' + req.params.sub);
});
// Redirect app
+23 -5
Ver Arquivo
@@ -10,9 +10,7 @@ var connect = require('connect')
, locals = require('./utils').locals
, View = require('./view')
, utils = connect.utils
, path = require('path')
, http = require('http')
, join = path.join;
, http = require('http');
/**
* Application prototype.
@@ -46,6 +44,7 @@ app.init = function(){
app.defaultConfiguration = function(){
// default settings
this.enable('x-powered-by');
this.enable('etag');
this.set('env', process.env.NODE_ENV || 'development');
this.set('subdomain offset', 2);
debug('booting in %s mode', this.get('env'));
@@ -184,7 +183,7 @@ app.engine = function(ext, fn){
* could automatically load a user's information from the database without
* any additional code,
*
* The callback uses the samesignature as middleware, the only differencing
* The callback uses the same signature as middleware, the only difference
* being that the value of the placeholder is passed, in this case the _id_
* of the user. Once the `next()` function is invoked, just like middleware
* it will continue on to execute the route, or subsequent parameter functions.
@@ -502,7 +501,26 @@ app.render = function(name, options, fn){
// render
try {
view.render(opts, fn);
var view_stream = view.render(opts, fn);
// if the engine returned a stream AND user specified a function
// then we will capture data for user
if (view_stream && fn) {
var body = '';
view_stream.on('data', function(chunk) {
body += chunk;
});
view_stream.once('error', function(err) {
fn(err);
});
view_stream.once('end', function() {
fn(null, body);
});
}
return view_stream;
} catch (err) {
fn(err);
}
+4 -1
Ver Arquivo
@@ -63,6 +63,7 @@ req.header = function(name){
* The `type` value may be a single mime type string
* such as "application/json", the extension name
* such as "json", a comma-delimted list such as "json, html, text/plain",
* an argument list such as `"json", "html", "text/plain"`,
* or an array `["json", "html", "text/plain"]`. When a list
* or array is given the _best_ match, if any is returned.
*
@@ -89,6 +90,7 @@ req.header = function(name){
*
* // Accept: text/*;q=.5, application/json
* req.accepts(['html', 'json']);
* req.accepts('html', 'json');
* req.accepts('html, json');
* // => "json"
*
@@ -98,7 +100,8 @@ req.header = function(name){
*/
req.accepts = function(type){
return utils.accepts(type, this.get('Accept'));
var args = arguments.length > 1 ? [].slice.apply(arguments) : type;
return utils.accepts(args, this.get('Accept'));
};
/**
+104 -21
Ver Arquivo
@@ -14,9 +14,9 @@ var http = require('http')
, cookie = require('cookie')
, send = require('send')
, mime = connect.mime
, resolve = require('url').resolve
, basename = path.basename
, extname = path.extname
, join = path.join;
, extname = path.extname;
/**
* Response prototype.
@@ -55,7 +55,9 @@ res.status = function(code){
*/
res.links = function(links){
return this.set('Link', Object.keys(links).map(function(rel){
var link = this.get('Link') || '';
if (link) link += ', ';
return this.set('Link', link + Object.keys(links).map(function(rel){
return '<' + links[rel] + '>; rel="' + rel + '"';
}).join(', '));
};
@@ -82,6 +84,9 @@ res.send = function(body){
var head = 'HEAD' == req.method;
var len;
// settings
var app = this.app;
// allow status / body
if (2 == arguments.length) {
// res.send(body, status) backwards compat
@@ -128,7 +133,7 @@ res.send = function(body){
// ETag support
// TODO: W/ support
if (len > 1024 && 'GET' == req.method) {
if (app.settings.etag && len && 'GET' == req.method) {
if (!this.get('ETag')) {
this.set('ETag', etag(body));
}
@@ -185,6 +190,7 @@ res.json = function(obj){
var body = JSON.stringify(obj, replacer, spaces);
// content-type
this.charset = this.charset || 'utf-8';
this.get('Content-Type') || this.set('Content-Type', 'application/json');
return this.send(body);
@@ -233,10 +239,10 @@ res.jsonp = function(obj){
// jsonp
if (callback) {
if (callback instanceof Array) callback = callback[0];
if (Array.isArray(callback)) callback = callback[0];
this.set('Content-Type', 'text/javascript');
var cb = callback.replace(/[^\[\]\w$.]/g, '');
body = cb + ' && ' + cb + '(' + body + ');';
body = 'typeof ' + cb + ' === \'function\' && ' + cb + '(' + body + ');';
}
return this.send(body);
@@ -318,10 +324,10 @@ res.sendfile = function(path, options, fn){
}
// streaming
function stream() {
function stream(stream) {
if (done) return;
cleanup();
if (fn) self.on('finish', fn);
if (fn) stream.on('end', fn);
}
// cleanup
@@ -459,10 +465,13 @@ res.format = function(obj){
var key = req.accepts(keys);
this.set('Vary', 'Accept');
this.vary("Accept");
if (key) {
this.set('Content-Type', normalizeType(key).value);
var type = normalizeType(key).value;
var charset = mime.charsets.lookup(type);
if (charset) type += '; charset=' + charset;
this.set('Content-Type', type);
obj[key](req, this, next);
} else if (fn) {
fn();
@@ -625,7 +634,8 @@ res.cookie = function(name, val, options){
res.location = function(url){
var app = this.app
, req = this.req;
, req = this.req
, path;
// setup redirect map
var map = { back: req.get('Referrer') || '/' };
@@ -635,12 +645,11 @@ res.location = function(url){
// relative
if (!~url.indexOf('://') && 0 != url.indexOf('//')) {
var path
// relative to path
if ('.' == url[0]) {
path = req.originalUrl.split('?')[0]
url = path + ('/' == path[path.length - 1] ? '' : '/') + url;
path = req.originalUrl.split('?')[0];
path = path + ('/' == path[path.length - 1] ? '' : '/');
url = resolve(path, url);
// relative to mount-point
} else if ('/' != url[0]) {
path = app.path();
@@ -675,8 +684,7 @@ res.location = function(url){
*/
res.redirect = function(url){
var app = this.app
, head = 'HEAD' == this.req.method
var head = 'HEAD' == this.req.method
, status = 302
, body;
@@ -716,6 +724,44 @@ res.redirect = function(url){
this.end(head ? null : body);
};
/**
* Add `field` to Vary. If already present in the Vary set, then
* this call is simply ignored.
*
* @param {Array|String} field
* @param {ServerResponse} for chaining
* @api public
*/
res.vary = function(field){
var self = this;
// nothing
if (!field) return this;
// array
if (Array.isArray(field)) {
field.forEach(function(field){
self.vary(field);
});
return;
}
var vary = this.get('Vary');
// append
if (vary) {
vary = vary.split(/ *, */);
if (!~vary.indexOf(field)) vary.push(field);
this.set('Vary', vary.join(', '));
return this;
}
// set
this.set('Vary', field);
return this;
};
/**
* Render `view` with the given `options` and optional callback `fn`.
* When a callback function is given a response will _not_ be made
@@ -746,12 +792,49 @@ res.render = function(view, options, fn){
// merge res.locals
options._locals = self.locals;
// default callback to respond
fn = fn || function(err, str){
// support for non streaming view rendering
// if renderer uses streams, this will not be called
// see below for how streams are handled
var respond = fn || function(err, str){
if (view_stream) return;
if (err) return req.next(err);
self.send(str);
};
// render
app.render(view, options, fn);
var view_stream = app.render(view, options, respond);
// old style, will have already called respond for us
if (!view_stream) {
return;
}
// user wants to handle sending themselves
if (fn) {
var body = '';
view_stream.on('data', function(chunk) {
body += chunk;
});
view_stream.once('error', function(err) {
fn(err);
});
view_stream.once('end', function() {
fn(null, body);
});
return;
}
// set response headers
self.statusCode = 200;
if (!self.get('Content-Type')) {
self.charset = self.charset || 'utf-8';
self.type('html');
}
self.setHeader('Transfer-Encoding', 'chunked');
// start streaming the response
view_stream.pipe(self);
};
+39 -1
Ver Arquivo
@@ -103,6 +103,9 @@ Router.prototype._dispatch = function(req, res, next){
// match route
req.route = route = self.matchRequest(req, i);
// implied OPTIONS
if (!route && 'OPTIONS' == req.method) return self._options(req, res);
// no route
if (!route) return next(err);
debug('matched %s %s', route.method, route.path);
@@ -170,6 +173,41 @@ Router.prototype._dispatch = function(req, res, next){
})(0);
};
/**
* Respond to __OPTIONS__ method.
*
* @param {IncomingMessage} req
* @param {ServerResponse} res
* @api private
*/
Router.prototype._options = function(req, res){
var path = parse(req).pathname
, body = this._optionsFor(path).join(',');
res.set('Allow', body).send(body);
};
/**
* Return an array of HTTP verbs or "options" for `path`.
*
* @param {String} path
* @return {Array}
* @api private
*/
Router.prototype._optionsFor = function(path){
var self = this;
return methods.filter(function(method){
var routes = self.map[method];
if (!routes || 'options' == method) return;
for (var i = 0, len = routes.length; i < len; ++i) {
if (routes[i].match(path)) return true;
}
}).map(function(method){
return method.toUpperCase();
});
};
/**
* Attempt to match a route for `req`
* with optional starting index of `i`
@@ -245,7 +283,7 @@ Router.prototype.route = function(method, path, callbacks){
if (!path) throw new Error('Router#' + method + '() requires a path');
// ensure all callbacks are functions
callbacks.forEach(function(fn, i){
callbacks.forEach(function(fn){
if ('function' == typeof fn) return;
var type = {}.toString.call(fn);
var msg = '.' + method + '() requires callback functions but got a ' + type;
+1 -1
Ver Arquivo
@@ -58,7 +58,7 @@ Route.prototype.match = function(path){
var key = keys[i - 1];
var val = 'string' == typeof m[i]
? decodeURIComponent(m[i])
? utils.decode(m[i])
: m[i];
if (key) {
+21 -1
Ver Arquivo
@@ -34,7 +34,7 @@ exports.etag = function(body){
* @api private
*/
exports.locals = function(obj){
exports.locals = function(){
function locals(obj){
for (var key in obj) locals[key] = obj[key];
return obj;
@@ -54,6 +54,7 @@ exports.locals = function(obj){
exports.isAbsolute = function(path){
if ('/' == path[0]) return true;
if (':' == path[1] && '\\' == path[2]) return true;
if ('\\\\' == path.substring(0, 2)) return true; // Microsoft Azure absolute path
};
/**
@@ -311,3 +312,22 @@ exports.pathRegexp = function(path, keys, sensitive, strict) {
.replace(/\*/g, '(.*)');
return new RegExp('^' + path + '$', sensitive ? '' : 'i');
}
/**
* Decodes a URI component. Returns
* the original string if the component
* is malformed.
*
* @param {String} str
* @return {String}
* @api private
*/
exports.decode = function(str) {
try {
return decodeURIComponent(str);
} catch (e) {
return str;
}
}
+1 -1
Ver Arquivo
@@ -73,5 +73,5 @@ View.prototype.lookup = function(path){
*/
View.prototype.render = function(options, fn){
this.engine(this.path, options, fn);
return this.engine(this.path, options, fn);
};
+16 -16
Ver Arquivo
@@ -1,7 +1,7 @@
{
"name": "express",
"description": "Sinatra inspired web development framework",
"version": "3.3.4",
"version": "3.4.4",
"author": "TJ Holowaychuk <tj@vision-media.ca>",
"contributors": [
{
@@ -22,28 +22,28 @@
}
],
"dependencies": {
"connect": "2.8.4",
"commander": "1.2.0",
"connect": "2.11.0",
"commander": "1.3.2",
"range-parser": "0.0.4",
"mkdirp": "0.3.5",
"cookie": "0.1.0",
"buffer-crc32": "0.2.1",
"fresh": "0.1.0",
"methods": "0.0.1",
"send": "0.1.3",
"fresh": "0.2.0",
"methods": "0.1.0",
"send": "0.1.4",
"cookie-signature": "1.0.1",
"debug": "*"
"debug": ">= 0.7.3 < 1"
},
"devDependencies": {
"ejs": "*",
"mocha": "*",
"ejs": ">= 0.8.4 < 1",
"mocha": ">= 1.13.0 < 2",
"jade": "0.30.0",
"hjs": "*",
"stylus": "*",
"should": "*",
"connect-redis": "*",
"marked": "*",
"supertest": "0.6.0"
"hjs": ">= 0.0.6 < 1",
"stylus": ">= 0.39.1 < 1",
"should": ">= 2.0.2 < 3",
"connect-redis": ">= 1.4.5 < 2",
"marked": ">= 0.2.9 < 1",
"supertest": ">= 0.8.1 < 1"
},
"keywords": [
"express",
@@ -66,6 +66,6 @@
"test": "make test"
},
"engines": {
"node": "*"
"node": ">= 0.8.0"
}
}
+42
Ver Arquivo
@@ -1,5 +1,6 @@
var express = require('../')
, request = require('./support/http')
, fs = require('fs');
function render(path, options, fn) {
@@ -10,6 +11,10 @@ function render(path, options, fn) {
});
}
function streaming_render(path, options, fn) {
return fs.createReadStream(path, { encoding: 'utf-8' });
}
describe('app', function(){
describe('.engine(ext, fn)', function(){
it('should map a template engine', function(done){
@@ -76,5 +81,42 @@ describe('app', function(){
done();
})
})
it('should support streaming engines', function(done) {
var app = express();
app.set('views', __dirname + '/fixtures');
app.engine('.html', streaming_render);
app.set('view engine', '.html');
app.locals.user = { name: 'tobi' };
// using function should just call the function when done
app.render('user', function(err, str){
if (err) return done(err);
str.should.equal('<p>{{user.name}}</p>');
done();
})
});
it('should render a response using the streaming engine', function(done) {
var app = express();
app.set('views', __dirname + '/fixtures');
app.engine('.html', streaming_render);
app.set('view engine', '.html');
app.locals.user = { name: 'tobi' };
app.get('/', function(req, res) {
res.render('user');
});
request(app)
.get('/')
.expect(200)
.end(function(err, res) {
if (err) return done(err);
res.header['transfer-encoding'].should.equal('chunked');
res.text.should.equal('<p>{{user.name}}</p>');
done();
});
});
})
})
+37
Ver Arquivo
@@ -0,0 +1,37 @@
var express = require('../')
, request = require('./support/http');
describe('OPTIONS', function(){
it('should default to the routes defined', function(done){
var app = express();
app.del('/', function(){});
app.get('/users', function(req, res){});
app.put('/users', function(req, res){});
request(app)
.options('/users')
.expect('GET,PUT')
.expect('Allow', 'GET,PUT', done);
})
})
describe('app.options()', function(){
it('should override the default behavior', function(done){
var app = express();
app.options('/users', function(req, res){
res.set('Allow', 'GET');
res.send('GET');
});
app.get('/users', function(req, res){});
app.put('/users', function(req, res){});
request(app)
.options('/users')
.expect('GET')
.expect('Allow', 'GET', done);
})
})
+3 -3
Ver Arquivo
@@ -52,13 +52,13 @@ describe('app', function(){
app.get('/post/:id', function(req, res){
var id = req.params.id;
id.should.be.a('number');
id.should.be.a.Number;
res.send('' + id);
});
app.get('/user/:uid', function(req, res){
var id = req.params.id;
id.should.be.a('number');
id.should.be.a.Number;
res.send('' + id);
});
@@ -87,7 +87,7 @@ describe('app', function(){
app.get('/user/:id', function(req, res){
var id = req.params.id;
id.should.be.a('number');
id.should.be.a.Number;
res.send('' + id);
});
+12
Ver Arquivo
@@ -39,6 +39,18 @@ describe('app.router', function(){
.expect('foo/bar', done);
})
it('should accept params in malformed paths', function(done) {
var app = express();
app.get('/:name', function(req, res, next){
res.send(req.params.name);
});
request(app)
.get('/%foobar')
.expect('%foobar', done);
})
it('should be .use()able', function(done){
var app = express();
+4 -4
Ver Arquivo
@@ -15,19 +15,19 @@ describe('exports', function(){
})
it('should expose Router', function(){
express.Router.should.be.a('function');
express.Router.should.be.a.Function;
})
it('should expose the application prototype', function(){
express.application.set.should.be.a('function');
express.application.set.should.be.a.Function;
})
it('should expose the request prototype', function(){
express.request.accepts.should.be.a('function');
express.request.accepts.should.be.a.Function;
})
it('should expose the response prototype', function(){
express.response.send.should.be.a('function');
express.response.send.should.be.a.Function;
})
it('should permit modifying the .application prototype', function(){
+1
Ver Arquivo
@@ -29,6 +29,7 @@ describe('req', function(){
request(app)
.get('/')
.set('Accept-Encoding', '')
.expect(200, done);
})
})
+14 -1
Ver Arquivo
@@ -56,7 +56,20 @@ describe('req', function(){
.expect('html', done);
})
describe('.accept(types)', function(){
it('should accept an argument list of type names', function(done){
var app = express();
app.use(function(req, res, next){
res.end(req.accepts('json', 'html'));
});
request(app)
.get('/')
.set('Accept', 'application/json')
.expect('json', done);
})
describe('.accepts(types)', function(){
it('should return the first when Accept is not present', function(done){
var app = express();
+19 -40
Ver Arquivo
@@ -5,55 +5,34 @@ var express = require('../')
describe('req', function(){
describe('.signedCookies', function(){
it('should return a signed JSON cookie', function(done){
var app = express()
, cookieHeader
, val;
/* So we use the same serialization for expected results. */
var replacer = app.get('json replacer')
, spaces = app.get('json spaces');
var app = express();
app.use(express.cookieParser('secret'));
app.use(function(req, res){
res.send(req.signedCookies);
if ('/set' == req.path) {
res.cookie('obj', { foo: 'bar' }, { signed: true });
res.end();
} else {
res.send(req.signedCookies);
}
});
app.response.req = { secret: 'secret' };
app.response.cookie('obj', { foo: 'bar' }, { signed: true });
cookieHeader = app.response.get('set-cookie');
val = JSON.stringify({ obj: { foo: 'bar' } }, replacer, spaces);
request(app)
.get('/')
.set('Cookie', cookieHeader)
.expect(val, done);
})
.get('/set')
.end(function(err, res){
if (err) return done(err);
var cookie = res.header['set-cookie'];
it('should return a signed cookie', function(done){
var app = express()
, cookieHeader
, val;
/* So we use the same serialization for expected results. */
var replacer = app.get('json replacer')
, spaces = app.get('json spaces');
app.use(express.cookieParser('secret'));
app.use(function(req, res){
res.send(req.signedCookies);
request(app)
.get('/')
.set('Cookie', cookie)
.end(function(err, res){
if (err) return don(err);
res.body.should.eql({ obj: { foo: 'bar' } });
done();
});
});
app.response.req = { secret: 'secret' };
app.response.cookie('foo', 'bar', { signed: true });
cookieHeader = app.response.get('set-cookie');
val = JSON.stringify({ foo: 'bar' }, replacer, spaces);
request(app)
.get('/')
.set('Cookie', cookieHeader)
.expect(val, done);
})
})
})
+6 -6
Ver Arquivo
@@ -15,7 +15,7 @@ describe('req', function(){
request(app)
.get('/')
.set('Host', 'tobi.ferrets.example.com')
.expect('["ferrets","tobi"]', done);
.expect(["ferrets","tobi"], done);
})
})
@@ -30,7 +30,7 @@ describe('req', function(){
request(app)
.get('/')
.set('Host', 'example.com')
.expect('[]', done);
.expect([], done);
})
})
@@ -45,7 +45,7 @@ describe('req', function(){
request(app)
.get('/')
.expect('[]', done);
.expect([], done);
})
})
@@ -62,7 +62,7 @@ describe('req', function(){
request(app)
.get('/')
.set('Host', 'tobi.ferrets.sub.example.com')
.expect('["com","example","sub","ferrets","tobi"]', done);
.expect(["com","example","sub","ferrets","tobi"], done);
})
})
@@ -78,7 +78,7 @@ describe('req', function(){
request(app)
.get('/')
.set('Host', 'tobi.ferrets.sub.example.com')
.expect('["ferrets","tobi"]', done);
.expect(["ferrets","tobi"], done);
})
})
@@ -94,7 +94,7 @@ describe('req', function(){
request(app)
.get('/')
.set('Host', 'sub.example.com')
.expect('[]', done);
.expect([], done);
})
})
})
+21 -4
Ver Arquivo
@@ -53,7 +53,7 @@ app3.use(function(req, res, next){
})
});
describe('req', function(){
describe('res', function(){
describe('.format(obj)', function(){
describe('with canonicalized mime types', function(){
test(app);
@@ -79,24 +79,41 @@ function test(app) {
request(app)
.get('/')
.set('Accept', 'text/html; q=.5, application/json, */*; q=.1')
.expect('{"message":"hey"}', done);
.expect({"message":"hey"}, done);
})
it('should allow wildcard type/subtypes', function(done){
request(app)
.get('/')
.set('Accept', 'text/html; q=.5, application/*, */*; q=.1')
.expect('{"message":"hey"}', done);
.expect({"message":"hey"}, done);
})
it('should default the Content-Type', function(done){
request(app)
.get('/')
.set('Accept', 'text/html; q=.5, text/plain')
.expect('Content-Type', 'text/plain')
.expect('Content-Type', 'text/plain; charset=UTF-8')
.expect('hey', done);
})
it('should set the correct charset for the Content-Type', function() {
request(app)
.get('/')
.set('Accept', 'text/html')
.expect('Content-Type', 'text/html; charset=UTF-8');
request(app)
.get('/')
.set('Accept', 'text/plain')
.expect('Content-Type', 'text/plain; charset=UTF-8');
request(app)
.get('/')
.set('Accept', 'application/json')
.expect('Content-Type', 'application/json');
})
it('should Vary: Accept', function(done){
request(app)
.get('/')
+7 -7
Ver Arquivo
@@ -28,7 +28,7 @@ describe('res', function(){
request(app)
.get('/')
.end(function(err, res){
res.headers.should.have.property('content-type', 'application/json');
res.headers.should.have.property('content-type', 'application/json; charset=utf-8');
res.text.should.equal('null');
done();
})
@@ -46,13 +46,13 @@ describe('res', function(){
request(app)
.get('/')
.end(function(err, res){
res.headers.should.have.property('content-type', 'application/json');
res.headers.should.have.property('content-type', 'application/json; charset=utf-8');
res.text.should.equal('["foo","bar","baz"]');
done();
})
})
})
describe('when given an object', function(){
it('should respond with json', function(done){
var app = express();
@@ -64,7 +64,7 @@ describe('res', function(){
request(app)
.get('/')
.end(function(err, res){
res.headers.should.have.property('content-type', 'application/json');
res.headers.should.have.property('content-type', 'application/json; charset=utf-8');
res.text.should.equal('{"name":"tobi"}');
done();
})
@@ -125,7 +125,7 @@ describe('res', function(){
})
})
})
describe('.json(status, object)', function(){
it('should respond with json and set the .statusCode', function(done){
var app = express();
@@ -138,7 +138,7 @@ describe('res', function(){
.get('/')
.end(function(err, res){
res.statusCode.should.equal(201);
res.headers.should.have.property('content-type', 'application/json');
res.headers.should.have.property('content-type', 'application/json; charset=utf-8');
res.text.should.equal('{"id":1}');
done();
})
@@ -157,7 +157,7 @@ describe('res', function(){
.get('/')
.end(function(err, res){
res.statusCode.should.equal(201);
res.headers.should.have.property('content-type', 'application/json');
res.headers.should.have.property('content-type', 'application/json; charset=utf-8');
res.text.should.equal('{"id":1}');
done();
})
+24 -8
Ver Arquivo
@@ -16,11 +16,27 @@ describe('res', function(){
.get('/?callback=something')
.end(function(err, res){
res.headers.should.have.property('content-type', 'text/javascript; charset=utf-8');
res.text.should.equal('something && something({"count":1});');
res.text.should.equal('typeof something === \'function\' && something({"count":1});');
done();
})
})
it('should use first callback parameter with jsonp', function(done){
var app = express();
app.use(function(req, res){
res.jsonp({ count: 1 });
});
request(app)
.get('/?callback=something&callback=somethingelse')
.end(function(err, res){
res.headers.should.have.property('content-type', 'text/javascript; charset=utf-8');
res.text.should.equal('typeof something === \'function\' && something({"count":1});');
done();
})
})
it('should allow renaming callback', function(done){
var app = express();
@@ -34,10 +50,10 @@ describe('res', function(){
.get('/?clb=something')
.end(function(err, res){
res.headers.should.have.property('content-type', 'text/javascript; charset=utf-8');
res.text.should.equal('something && something({"count":1});');
res.text.should.equal('typeof something === \'function\' && something({"count":1});');
done();
})
})
})
it('should allow []', function(done){
var app = express();
@@ -50,7 +66,7 @@ describe('res', function(){
.get('/?callback=callbacks[123]')
.end(function(err, res){
res.headers.should.have.property('content-type', 'text/javascript; charset=utf-8');
res.text.should.equal('callbacks[123] && callbacks[123]({"count":1});');
res.text.should.equal('typeof callbacks[123] === \'function\' && callbacks[123]({"count":1});');
done();
})
})
@@ -66,7 +82,7 @@ describe('res', function(){
.get('/?callback=foo;bar()')
.end(function(err, res){
res.headers.should.have.property('content-type', 'text/javascript; charset=utf-8');
res.text.should.equal('foobar && foobar({});');
res.text.should.equal('typeof foobar === \'function\' && foobar({});');
done();
})
})
@@ -82,7 +98,7 @@ describe('res', function(){
.get('/?callback=foo')
.end(function(err, res){
res.headers.should.have.property('content-type', 'text/javascript; charset=utf-8');
res.text.should.equal('foo && foo({"str":"\\u2028 \\u2029 woot"});');
res.text.should.equal('typeof foo === \'function\' && foo({"str":"\\u2028 \\u2029 woot"});');
done();
});
});
@@ -122,7 +138,7 @@ describe('res', function(){
})
})
})
describe('when given an object', function(){
it('should respond with json', function(done){
var app = express();
@@ -195,7 +211,7 @@ describe('res', function(){
})
})
})
describe('.json(status, object)', function(){
it('should respond with json and set the .statusCode', function(done){
var app = express();
+22
Ver Arquivo
@@ -3,6 +3,11 @@ var express = require('../')
, res = express.response;
describe('res', function(){
beforeEach(function() {
res.removeHeader('link');
});
describe('.links(obj)', function(){
it('should set Link header field', function(){
res.links({
@@ -15,5 +20,22 @@ describe('res', function(){
'<http://api.example.com/users?page=2>; rel="next", '
+ '<http://api.example.com/users?page=5>; rel="last"');
})
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'
});
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"');
})
})
})
+19 -2
Ver Arquivo
@@ -64,7 +64,7 @@ describe('res', function(){
request(app)
.get('/post/1')
.end(function(err, res){
res.headers.should.have.property('location', '/post/1/./edit');
res.headers.should.have.property('location', '/post/1/edit');
done();
})
})
@@ -81,7 +81,24 @@ describe('res', function(){
request(app)
.get('/post/1')
.end(function(err, res){
res.headers.should.have.property('location', '/post/1/../new');
res.headers.should.have.property('location', '/post/new');
done();
})
})
})
describe('with leading ./ and containing ..', function(){
it('should construct path-relative urls', function(done){
var app = express();
app.use(function(req, res){
res.location('./skip/../../new').end();
});
request(app)
.get('/post/1')
.end(function(err, res){
res.headers.should.have.property('location', '/post/new');
done();
})
})
+5 -5
Ver Arquivo
@@ -210,17 +210,17 @@ describe('res', function(){
request(root)
.get('/depth1')
.end(function(err, res){
res.headers.should.have.property('location', '/depth1/./index');
res.headers.should.have.property('location', '/depth1/index');
request(root)
.get('/depth1/depth2')
.end(function(err, res){
res.headers.should.have.property('location', '/depth1/depth2/./index');
res.headers.should.have.property('location', '/depth1/depth2/index');
request(root)
.get('/depth1/depth2/depth3')
.end(function(err, res){
res.headers.should.have.property('location', '/depth1/depth2/depth3/./index');
res.headers.should.have.property('location', '/depth1/depth2/depth3/index');
done();
})
})
@@ -231,11 +231,11 @@ describe('res', function(){
request(root)
.get('/depth2')
.end(function(err, res){
res.headers.should.have.property('location', '/depth2/./index');
res.headers.should.have.property('location', '/depth2/index');
request(root)
.get('/depth3')
.end(function(err, res){
res.headers.should.have.property('location', '/depth3/./index');
res.headers.should.have.property('location', '/depth3/index');
done();
})
})
+74 -1
Ver Arquivo
@@ -202,7 +202,7 @@ describe('res', function(){
request(app)
.get('/')
.end(function(err, res){
res.headers.should.have.property('content-type', 'application/json');
res.headers.should.have.property('content-type', 'application/json; charset=utf-8');
res.text.should.equal('{"name":"tobi"}');
done();
})
@@ -318,4 +318,77 @@ describe('res', function(){
.get('/?callback=foo')
.expect('{"foo":"bar"}', done);
})
describe('"etag" setting', function(){
describe('when enabled', function(){
it('should send ETag even when content-length < 1024', function(done){
var app = express();
app.use(function(req, res){
res.send('kajdslfkasdf');
});
request(app)
.get('/')
.end(function(err, res){
res.headers.should.have.property('etag');
done();
});
})
it('should send ETag ', function(done){
var app = express();
app.use(function(req, res){
var str = Array(1024 * 2).join('-');
res.send(str);
});
request(app)
.get('/')
.end(function(err, res){
res.headers.should.have.property('etag', '"-1498647312"');
done();
});
});
});
describe('when disabled', function(){
it('should send no ETag', function(done){
var app = express();
app.use(function(req, res){
var str = Array(1024 * 2).join('-');
res.send(str);
});
app.disable('etag');
request(app)
.get('/')
.end(function(err, res){
res.headers.should.not.have.property('etag');
done();
});
});
it('should send ETag when manually set', function(done){
var app = express();
app.disable('etag');
app.use(function(req, res){
res.set('etag', 1);
res.send(200);
});
request(app)
.get('/')
.end(function(err, res){
res.headers.should.have.property('etag');
done();
});
});
});
})
})
+1 -1
Ver Arquivo
@@ -51,7 +51,7 @@ describe('res', function(){
.get('/')
.end(function(err, res){
assert(1 == calls, 'called too many times');
res.text.should.equal("ENOENT, stat 'test/fixtures/nope.html'");
res.text.should.startWith("ENOENT, stat");
res.statusCode.should.equal(200);
done();
});
+55
Ver Arquivo
@@ -0,0 +1,55 @@
var express = require('../')
, should = require('should');
function response() {
var res = Object.create(express.response);
res._headers = {};
return res;
}
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'));
})
})
describe('with an empty array', function(){
it('should not set Vary', function(){
var res = response();
res.vary([]);
should.not.exist(res.get('Vary'));
})
})
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');
})
})
describe('with a string', function(){
it('should set the value', function(){
var res = response();
res.vary('Accept');
res.get('Vary').should.equal('Accept');
})
})
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');
})
})
})