Comparar commits

...

45 Commits

Autor SHA1 Mensagem Data
TJ Holowaychuk 2787bd5bf0 Release 3.0.0beta2 2012-06-06 14:46:52 -07:00
TJ Holowaychuk 6aaa7dc26d Added + support to the router 2012-06-06 14:38:22 -07:00
TJ Holowaychuk ebf60d2340 coerce res.cookie values to strings 2012-06-06 12:34:51 -07:00
TJ Holowaychuk 02d43846f6 fixing cookies for connect 2.3.1 2012-06-06 12:25:14 -07:00
TJ Holowaychuk 8930cd563c update connect dep 2012-06-06 12:00:35 -07:00
TJ Holowaychuk 2b90cd7d51 Added req.host 2012-06-05 19:24:49 -07:00
TJ Holowaychuk d5fde6a4b9 added test to illustrate req.params as an array 2012-06-05 19:02:28 -07:00
TJ Holowaychuk 99b2e0fa08 refactored req.param() 2012-06-05 18:59:26 -07:00
TJ Holowaychuk ebcb1ca90e Changed req.param() to check route first
body / query-string taking precedence is a little sketchy
but you should use this method sparingly, think of it
as PHPs $_REQUEST
2012-06-05 18:51:42 -07:00
TJ Holowaychuk 1763b073f9 docs 2012-06-04 09:48:19 -07:00
TJ Holowaychuk 908e467548 docs 2012-06-02 20:04:51 -07:00
TJ Holowaychuk 3c6ad5350b Release 3.0.0beta1 2012-06-01 12:27:19 -07:00
TJ Holowaychuk 0ff3aa4b20 update deps 2012-06-01 12:24:17 -07:00
TJ Holowaychuk fd42b5c42c mention res.format() callback 2012-06-01 09:15:35 -07:00
TJ Holowaychuk 1311f2ac25 Fixed res.redirect() 406. Closes #1154 2012-06-01 09:14:27 -07:00
TJ Holowaychuk 82a9817061 Release 3.0.0alpha5 2012-05-30 16:48:22 -07:00
TJ Holowaychuk 685eec0149 assertion for req.get() => undefined. Closes #1152 2012-05-30 14:25:43 -07:00
TJ Holowaychuk 910dae16ab misc refactor 2012-05-29 18:51:08 -07:00
TJ Holowaychuk fd53197b46 Added req.ip tests 2012-05-29 18:46:37 -07:00
TJ Holowaychuk d84d0b69ef Added req.ip 2012-05-29 18:46:07 -07:00
TJ Holowaychuk b694ba27be Changed: dont reverse req.ips
parse them as-is. im impartial about
the ordering but this spares some CPU. if you
prefer the other way let me know
2012-05-29 18:41:00 -07:00
TJ Holowaychuk e3cbac2d77 Fixed setting check for req.ips 2012-05-29 18:36:46 -07:00
TJ Holowaychuk bbaa295ee2 Merge branch 'master' of github.com:visionmedia/express 2012-05-27 11:53:06 -07:00
TJ Holowaychuk 1150a88001 Added { signed: true } option to res.cookie() 2012-05-27 11:51:32 -07:00
TJ Holowaychuk 58cfd60000 moved executable css middleware lower 2012-05-21 20:40:49 -03:00
TJ Holowaychuk fcf268742d update commander 2012-05-16 21:34:29 -03:00
TJ Holowaychuk 30d71c8f8f ocd 2012-05-14 08:49:37 -07:00
TJ Holowaychuk c3f9398b12 Merge pull request #1135 from adrianolaru/jade-default-doctype
Changed jade default doctype to html5
2012-05-12 06:32:38 -07:00
Adrian Olaru f1ac6ab764 changed jade default doctype to html5 2012-05-12 16:19:02 +03:00
TJ Holowaychuk d6ca5f71bc Added test for res.sendfile() express.static() options 2012-05-10 18:00:41 -07:00
TJ Holowaychuk cdca9cf88f Added res.download() body test 2012-05-10 17:15:50 -07:00
TJ Holowaychuk 5840b42f4a Added res.download() tests 2012-05-10 17:11:43 -07:00
TJ Holowaychuk a5be68b5b2 refactored res.get() tests 2012-05-10 13:59:27 -07:00
TJ Holowaychuk 9fda13bc25 Added url rewriting test 2012-05-10 13:13:03 -07:00
TJ Holowaychuk 125dd7a594 Prepared release 3.0.0alpha4 2012-05-09 15:18:21 -07:00
TJ Holowaychuk df2584cc3b Added: allow [] in jsonp callback. Closes #1128 2012-05-09 09:39:52 -07:00
TJ Holowaychuk 4de95c0e7b connect 2.2.2 2012-05-07 13:58:17 -07:00
TJ Holowaychuk 9ed1f2a446 Removed blog example
need a better one
2012-05-07 12:52:56 -07:00
TJ Holowaychuk 833a4873a4 misc refactor of blog example 2012-05-07 12:44:03 -07:00
TJ Holowaychuk 6ca1807372 Merge branch 'master' of github.com:visionmedia/express 2012-05-07 12:01:19 -07:00
TJ Holowaychuk 9da3e9ccc7 Merge pull request #1127 from benatkin/template-port-from-env
get port from env in template (fix for #1118)
2012-05-07 11:59:32 -07:00
Ben Atkin 5f65c36171 use get() with single argument to read setting vars 2012-05-07 12:51:41 -06:00
Ben Atkin d64bb2f886 use process.env.PORT. fix for #1118 2012-05-06 23:49:06 -06:00
TJ Holowaychuk 8235af47fe Merge pull request #1124 from pyrotechnick/patch-1
path.existsSync is deprecated. It is now called `fs.existsSync`.
2012-05-04 08:59:10 -07:00
Nicholas Kinsey 908f3da3da path.existsSync is deprecated. It is now called fs.existsSync. 2012-05-05 00:32:53 +10:00
34 arquivos alterados com 446 adições e 609 exclusões
+30
Ver Arquivo
@@ -1,4 +1,34 @@
3.0.0beta2 / 2012-06-06
==================
* Added `+` support to the router
* Added `req.host`
* Changed `req.param()` to check route first
* Update connect dep
3.0.0beta1 / 2012-06-01
==================
* Added `res.format()` callback to override default 406 behaviour
* Fixed `res.redirect()` 406. Closes #1154
3.0.0alpha5 / 2012-05-30
==================
* Added `req.ip`
* Added `{ signed: true }` option to `res.cookie()`
* Removed `res.signedCookie()`
* Changed: dont reverse `req.ips`
* Fixed "trust proxy" setting check for `req.ips`
3.0.0alpha4 / 2012-05-09
==================
* Added: allow `[]` in jsonp callback. Closes #1128
* Added `PORT` env var support in generated template. Closes #1118 [benatkin]
* Updated: connect 2.2.2
3.0.0alpha3 / 2012-05-04
==================
+1 -1
Ver Arquivo
@@ -77,7 +77,7 @@ app.listen(3000);
First install the dev dependencies to install all the example / test suite deps:
$ cd express
$ npm install -d
$ npm install
then run whichever tests you want:
+7 -6
Ver Arquivo
@@ -57,7 +57,7 @@ var index = [
*/
var jadeLayout = [
'!!!'
'doctype 5'
, 'html'
, ' head'
, ' title= title'
@@ -181,13 +181,14 @@ var app = [
, 'var app = express();'
, ''
, 'app.configure(function(){'
, ' app.set(\'port\', process.env.PORT || 3000);'
, ' app.set(\'views\', __dirname + \'/views\');'
, ' app.set(\'view engine\', \':TEMPLATE\');'
, ' app.use(express.favicon());'
, ' app.use(express.logger(\'dev\'));{css}'
, ' app.use(express.logger(\'dev\'));'
, ' app.use(express.bodyParser());'
, ' app.use(express.methodOverride());{sess}'
, ' app.use(app.router);'
, ' app.use(app.router);{css}'
, ' app.use(express.static(__dirname + \'/public\'));'
, '});'
, ''
@@ -197,9 +198,9 @@ var app = [
, ''
, 'app.get(\'/\', routes.index);'
, ''
, 'http.createServer(app).listen(3000);'
, ''
, 'console.log("Express server listening on port 3000");'
, 'http.createServer(app).listen(app.get(\'port\'), function(){'
, ' console.log("Express server listening on port " + app.get(\'port\'));'
, '});'
, ''
].join(eol);
-50
Ver Arquivo
@@ -1,50 +0,0 @@
/**
* Module dependencies.
*/
var express = require('../../')
, app = module.exports = express();
// config
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
// middleware
app.configure('development',function(){
app.use(express.logger('dev'));
})
app.configure(function(){
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser('keyboard cat'));
app.use(express.session());
app.use(app.router);
app.use(express.static(__dirname + '/public'));
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
// Locals
app.locals.use(function(req, res){
// expose "error" and "message" to all
// views that are rendered.
res.locals.error = req.session.error || '';
res.locals.message = req.session.message || '';
// remove them so they're not displayed on subsequent renders
delete req.session.error;
delete req.session.message;
});
// Routes
require('./routes/site')(app);
require('./routes/post')(app);
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}
-67
Ver Arquivo
@@ -1,67 +0,0 @@
// Fake data store
var ids = 0
, db = {};
var Post = exports = module.exports = function Post(title, body) {
this.id = ++ids;
this.title = title;
this.body = body;
this.createdAt = new Date;
};
Post.prototype.save = function(fn){
db[this.id] = this;
fn();
};
Post.prototype.validate = function(fn){
if (!this.title) return fn(new Error('title required'));
if (!this.body) return fn(new Error('body required'));
if (this.body.length < 10) {
return fn(new Error(
'body should be at least 10 characters long, was only ' + this.body.length));
}
fn();
};
Post.prototype.update = function(data, fn){
this.updatedAt = new Date;
for (var key in data) {
if (undefined != data[key]) {
this[key] = data[key];
}
}
this.save(fn);
};
Post.prototype.destroy = function(fn){
exports.destroy(this.id, fn);
};
exports.count = function(fn){
fn(null, Object.keys(db).length);
};
exports.all = function(fn){
var arr = Object.keys(db).reduce(function(arr, id){
arr.push(db[id]);
return arr;
}, []);
fn(null, arr);
};
exports.get = function(id, fn){
fn(null, db[id]);
};
exports.destroy = function(id, fn) {
if (db[id]) {
delete db[id];
fn();
} else {
fn(new Error('post ' + id + ' does not exist'));
}
};
-56
Ver Arquivo
@@ -1,56 +0,0 @@
body {
font: 13px "Helvetica Neue", Arial, sans-serif;
color: #111;
padding: 60px 80px;
}
h1, h2 {
color: #c00;
}
a {
color: #c00;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
label {
padding: 6px 0;
display: block;
text-transform: lowercase;
}
textarea,
input {
outline: none;
padding: 5px;
background: #f1f1f1;
border: 1px solid #aaa;
}
textarea:focus,
input:focus {
background: #fff;
}
textarea {
width: 500px;
height: 200px;
}
a.edit {
margin-left: 10px;
font-size: 11px;
font-weight: normal;
}
.date {
font-size: 11px;
}
p.error,
p.message {
padding: 10px;
border: 1px solid;
}
p.error {
background: #FDEAE7;
color: #E4250C;
}
p.message {
color: #2EBBE6;
background: #F7FBFD;
}
-96
Ver Arquivo
@@ -1,96 +0,0 @@
/**
* Module dependencies.
*/
var basicAuth = require('../../../lib/express').basicAuth
, Post = require('../models/post');
module.exports = function(app){
/**
* Apply basic auth to all post related routes
*/
app.all('/post(/*)?', basicAuth(function(user, pass){
return 'admin' == user && 'express' == pass;
}));
/**
* Map :post to the database, loading
* every time :post is present.
*/
app.param('post', function(req, res, next, id){
Post.get(id, function(err, post){
if (err) return next(err);
if (!post) return next(new Error('failed to load post ' + id));
req.post = post;
next();
});
});
/**
* Add a post.
*/
app.get('/post/add', function(req, res){
res.render('post/form', { post: {}});
});
/**
* Save a post.
*/
app.post('/post', function(req, res){
var data = req.body.post || {}
, post = new Post(data.title, data.body);
post.validate(function(err){
if (err) {
req.session.error = err.message;
return res.redirect('back');
}
post.save(function(err){
req.session.message = 'Successfully created the post.';
res.redirect('/post/' + post.id);
});
});
});
/**
* Display the post.
*/
app.get('/post/:post', function(req, res){
res.render('post', { post: req.post });
});
/**
* Display the post edit form.
*/
app.get('/post/:post/edit', function(req, res){
res.render('post/form', { post: req.post });
});
/**
* Update post. Typically a data layer would handle this stuff.
*/
app.put('/post/:post', function(req, res, next){
var post = req.post;
post.validate(function(err){
if (err) {
req.session.error = err.message;
return res.redirect('back');
}
post.update(req.body.post, function(err){
if (err) return next(err);
req.session.message = 'Successfully updated post';
res.redirect('back');
});
});
});
};
-19
Ver Arquivo
@@ -1,19 +0,0 @@
/**
* Module dependencies.
*/
var Post = require('../models/post');
module.exports = function(app){
app.get('/', function(req, res){
Post.count(function(err, count){
Post.all(function(err, posts){
res.render('index', {
count: count
, posts: posts
});
});
});
});
};
-22
Ver Arquivo
@@ -1,22 +0,0 @@
extends layout
block content
h1 Blog
if count
p Display all #{count} post(s)
#posts
each post in posts
include post/index
else
p
| It looks like you have no posts!
p
| Click
a(href='/post/add') here
| to create a post. Login
| as
em "admin"
| and
em "express"
| .
-8
Ver Arquivo
@@ -1,8 +0,0 @@
!!! 5
html
head
title Blog
link(rel='stylesheet', href='/style.css')
body
#container
block content
-6
Ver Arquivo
@@ -1,6 +0,0 @@
if error
p.error= error
if message
p.message= message
-22
Ver Arquivo
@@ -1,22 +0,0 @@
extends ../layout
block content
if post.title
h1 Editing #{post.title}
else
h1 New Post
include ../messages
form#post(action='/post' + (post.title ? '/' + post.id : ''), method='post')
if post.title
input(type='hidden', name='_method', value='put')
p
label(for='post[title]') Title:
input(type='text', name='post[title]', value=post.title)
p
label(for='post[body]') Body:
textarea(name='post[body]')= post.body || ''
p
input(type='submit', value=post.title ? 'Update' : 'Create')
-18
Ver Arquivo
@@ -1,18 +0,0 @@
extends ../layout
block content
.post
// title
h2
= post.title
a.edit(href='/post/' + post.id + '/edit') Edit
include ../messages
// dates
p.date.created Created at #{post.createdAt}
if post.updatedAt
p.date.updated Updated at #{post.updatedAt}
// body
pre.body= post.body
+1 -1
Ver Arquivo
@@ -22,7 +22,7 @@ exports = module.exports = createApplication;
* Framework version.
*/
exports.version = '3.0.0alpha3';
exports.version = '3.0.0beta2';
/**
* Create an express application.
+35 -28
Ver Arquivo
@@ -208,8 +208,8 @@ req.__defineGetter__('acceptedCharsets', function(){
/**
* Return the value of param `name` when present or `defaultValue`.
*
* - Checks body params, ex: id=12, {"id":12}
* - Checks route placeholders, ex: _/user/:id_
* - Checks body params, ex: id=12, {"id":12}
* - Checks query string params, ex: ?id=12
*
* To utilize request bodies, `req.body`
@@ -223,19 +223,12 @@ req.__defineGetter__('acceptedCharsets', function(){
*/
req.param = function(name, defaultValue){
// req.body
if (this.body && undefined !== this.body[name]) return this.body[name];
// route params
if (this.params
&& this.params.hasOwnProperty(name)
&& undefined !== this.params[name]) {
return this.params[name];
}
// query-string
if (undefined !== this.query[name]) return this.query[name];
var params = this.params || {};
var body = this.body || {};
var query = this.query || {};
if (null != params[name] && params.hasOwnProperty(name)) return params[name];
if (null != body[name]) return body[name];
if (null != query[name]) return query[name];
return defaultValue;
};
@@ -260,17 +253,6 @@ req.param = function(name, defaultValue){
* req.is('html');
* // => false
*
* Now within our route callbacks, we can use to to assert content types
* such as "image/jpeg", "image/png" as shown here:
*
* app.post('/image/upload', function(req, res, next){
* if (req.is('image/*')) {
* // do something
* } else {
* next();
* }
* });
*
* @param {String} type
* @return {Boolean}
* @api public
@@ -325,12 +307,25 @@ req.__defineGetter__('secure', function(){
return 'https' == this.protocol;
});
/**
* Return the remote address, or when
* "trust proxy" is `true` return
* the upstream addr.
*
* @return {String}
* @api public
*/
req.__defineGetter__('ip', function(){
return this.ips[0] || this.connection.remoteAddress;
});
/**
* When "trust proxy" is `true`, parse
* the "X-Forwarded-For" ip address list.
*
* For example if the value were "client, proxy1, proxy2"
* you would receive the array `["proxy2", "proxy1", "client"]`
* you would receive the array `["client", "proxy1", "proxy2"]`
* where "proxy2" is the furthest down-stream.
*
* @return {Array}
@@ -338,9 +333,10 @@ req.__defineGetter__('secure', function(){
*/
req.__defineGetter__('ips', function(){
var trustProxy = this.app.get('trust proxy');
var val = this.get('X-Forwarded-For');
return val
? val.split(/ *, */).reverse()
return trustProxy && val
? val.split(/ *, */)
: [];
});
@@ -372,6 +368,17 @@ req.__defineGetter__('path', function(){
return parse(this).pathname;
});
/**
* Parse the "Host" header field hostname.
*
* @return {String}
* @api public
*/
req.__defineGetter__('host', function(){
return this.get('Host').split(':')[0];
});
/**
* Check if the request is fresh, aka
* Last-Modified and/or the ETag
+25 -24
Ver Arquivo
@@ -12,6 +12,7 @@ var fs = require('fs')
, normalizeTypes = require('./utils').normalizeTypes
, statusCodes = http.STATUS_CODES
, send = connect.static.send
, cookie = require('cookie')
, crc = require('crc')
, mime = require('mime')
, basename = path.basename
@@ -159,7 +160,7 @@ res.json = function(obj){
if (callback && jsonp) {
this.set('Content-Type', 'text/javascript');
body = callback.replace(/[^\w$.]/g, '') + '(' + body + ');';
body = callback.replace(/[^[]\w$.]/g, '') + '(' + body + ');';
}
return this.send(body);
@@ -251,7 +252,7 @@ res.sendfile = function(path, options, fn){
* when the data transfer is complete, or when an error has
* ocurred. Be sure to check `res.headerSent` if you plan to respond.
*
* This method uses `res.attachment()` and `res.sendfile()`.
* This method uses `res.sendfile()`.
*
* @param {String} path
* @param {String|Function} filename or fn
@@ -266,7 +267,9 @@ res.download = function(path, filename, fn){
filename = null;
}
return this.attachment(filename || path).sendfile(path, fn);
filename = filename || path;
this.set('Content-Disposition', 'attachment; filename="' + basename(filename) + '"');
return this.sendfile(path, fn);
};
/**
@@ -339,12 +342,19 @@ res.type = function(type){
* }
* });
*
* By default Express passes an `Error`
* with a `.status` of 406 to `next(err)`
* if a match is not made, however you may
* provide an optional callback `fn` to
* be invoked instead.
*
* @param {Object} obj
* @param {Function} fn
* @return {ServerResponse} for chaining
* @api public
*/
res.format = function(obj){
res.format = function(obj, fn){
var keys = Object.keys(obj)
, req = this.req
, next = req.next
@@ -355,6 +365,8 @@ res.format = function(obj){
if (key) {
this.set('Content-Type', normalizeType(key));
obj[key](req, this, next);
} else if (fn) {
fn();
} else {
var err = new Error('Not Acceptable');
err.status = 406;
@@ -438,30 +450,13 @@ res.clearCookie = function(name, options){
: opts);
};
/**
* Set a signed cookie with the given `name` and `val`.
* See `res.cookie()` for details.
*
* @param {String} name
* @param {String|Object} val
* @param {Object} options
* @api public
*/
res.signedCookie = function(name, val, options){
var secret = this.req.secret;
if (!secret) throw new Error('connect.cookieParser("secret") required for signed cookies');
if ('object' == typeof val) val = 'j:' + JSON.stringify(val);
val = utils.sign(val, secret);
return this.cookie(name, val, options);
};
/**
* Set cookie `name` to `val`, with the given `options`.
*
* Options:
*
* - `maxAge` max-age in milliseconds, converted to `expires`
* - `signed` sign the cookie
* - `path` defaults to "/"
*
* Examples:
@@ -480,11 +475,14 @@ res.signedCookie = function(name, val, options){
res.cookie = function(name, val, options){
options = options || {};
var secret = this.req.secret;
var signed = options.signed;
if (signed && !secret) throw new Error('connect.cookieParser("secret") required for signed cookies');
if ('object' == typeof val) val = 'j:' + JSON.stringify(val);
if (signed) val = utils.sign(val, secret);
if ('maxAge' in options) options.expires = new Date(Date.now() + options.maxAge);
if (null == options.path) options.path = '/';
var cookie = utils.serializeCookie(name, val, options);
this.set('Set-Cookie', cookie);
this.set('Set-Cookie', cookie.serialize(name, String(val), options));
return this;
};
@@ -566,11 +564,14 @@ res.redirect = function(url){
html: function(){
body = '<p>' + statusCodes[status] + '. Redirecting to <a href="' + url + '">' + url + '</a></p>';
}
}, function(){
body = '';
})
// Respond
this.statusCode = status;
this.set('Location', url);
this.set('Content-Length', Buffer.byteLength(body));
this.end(head ? null : body);
};
+2
Ver Arquivo
@@ -264,6 +264,7 @@ exports.pathRegexp = function(path, keys, sensitive, strict) {
path = path
.concat(strict ? '' : '/?')
.replace(/\/\(/g, '(?:/')
.replace(/\+/g, '__plus__')
.replace(/(\/)?(\.)?:(\w+)(?:(\(.*?\)))?(\?)?/g, function(_, slash, format, key, capture, optional){
keys.push({ name: key, optional: !! optional });
slash = slash || '';
@@ -275,6 +276,7 @@ exports.pathRegexp = function(path, keys, sensitive, strict) {
+ (optional || '');
})
.replace(/([\/.])/g, '\\$1')
.replace(/__plus__/g, '(.+)')
.replace(/\*/g, '(.*)');
return new RegExp('^' + path + '$', sensitive ? '' : 'i');
}
+2 -2
Ver Arquivo
@@ -1,14 +1,14 @@
/**
* Module dependencies.
*/
var path = require('path')
, fs = require('fs')
, utils = require('./utils')
, dirname = path.dirname
, basename = path.basename
, extname = path.extname
, exists = path.existsSync
, exists = fs.existsSync || path.existsSync
, join = path.join;
/**
+5 -4
Ver Arquivo
@@ -1,7 +1,7 @@
{
"name": "express",
"description": "Sinatra inspired web development framework",
"version": "3.0.0alpha3",
"version": "3.0.0beta2",
"author": "TJ Holowaychuk <tj@vision-media.ca>",
"contributors": [
{ "name": "TJ Holowaychuk", "email": "tj@vision-media.ca" },
@@ -10,10 +10,11 @@
{ "name": "Guillermo Rauch", "email": "rauchg@gmail.com" }
],
"dependencies": {
"connect": "2.2.1",
"commander": "0.5.2",
"connect": "2.3.1",
"commander": "0.6.1",
"mime": "1.2.5",
"mkdirp": "0.3.1",
"mkdirp": "0.3.2",
"cookie": "0.0.3",
"crc": "0.2.0",
"debug": "*"
},
-79
Ver Arquivo
@@ -1,79 +0,0 @@
var app = require('../../examples/blog')
, request = require('../support/http');
var authorization = 'Basic ' + Buffer('admin:express').toString('base64');
function redirects(to,fn){
return function(res){
res.statusCode.should.equal(302)
res.headers.should.have.property('location').match(to);
fn()
}
}
describe('blog', function(){
describe('GET /', function(){
it('should have no posts', function(done){
request(app)
.get('/')
.expect(/you have no posts/, done)
})
})
describe('GET /post/add', function(){
it('should require auth', function(done){
request(app)
.get('/post/add')
.expect(401, done)
})
it('should login', function(done){
request(app)
.get('/post/add')
.set('Authorization', authorization)
.expect(/<h1>New Post<\/h1>/, done)
})
})
describe('POST /post', function(){
it('should require auth', function(done){
request(app)
.post('/post')
.expect(401, done)
})
it('should redirect to / with no title or body', function(done){
request(app)
.post('/post')
.set('Authorization', authorization)
.end(redirects(/\/$/, done))
})
it('should redirect to / with no body', function(done){
request(app)
.post('/post')
.set('Authorization', authorization)
.set('Content-Type', 'application/x-www-form-urlencoded')
.write('post[title]=Kittens')
.end(redirects(/\/$/, done))
})
it('should redirect to /post/:post when successful', function(done){
request(app)
.post('/post')
.set('Authorization', authorization)
.set('Content-Type', 'application/x-www-form-urlencoded')
.write('post[title]=Kittens&post[body]=In+very+large+baskets')
.end(redirects(/\/post\/\d+$/, done))
})
})
describe('GET /', function(){
it('should now list 1 post',function(done){
request(app)
.get('/')
.expect(/Display all 1 post/, done)
})
})
})
+41 -18
Ver Arquivo
@@ -256,23 +256,6 @@ describe('app.router', function(){
})
})
it('should allow escaped regexp', function(done){
var app = express();
app.get('/user/\\d+', function(req, res){
res.end('woot');
});
request(app)
.get('/user/10')
.end(function(res){
res.statusCode.should.equal(200);
request(app)
.get('/user/tj')
.expect(404, done);
});
})
it('should allow literal "."', function(done){
var app = express();
@@ -288,10 +271,32 @@ describe('app.router', function(){
.expect('users from 1 to 50', done);
})
describe('*', function(){
describe('+', function(){
it('should denote a greedy capture group', function(done){
var app = express();
app.get('/blog+', function(req, res){
res.end(req.params[0] || 'nothing');
});
request(app)
.get('/blog')
.expect(404, function(){
request(app)
.get('/blog/post')
.expect(200, function(){
request(app)
.get('/blog-admin')
.expect(200, done)
})
});
})
})
describe('*', function(){
it('should denote an optional greedy capture group', function(done){
var app = express();
app.get('/user/*.json', function(req, res){
res.end(req.params[0]);
});
@@ -551,4 +556,22 @@ describe('app.router', function(){
})
})
})
it('should allow rewriting of the url', function(done){
var app = express();
app.get('/account/edit', function(req, res, next){
req.user = { id: 12 }; // faux authenticated user
req.url = '/user/' + req.user.id + '/edit';
next();
});
app.get('/user/:id/edit', function(req, res){
res.send('editing user ' + req.params.id);
});
request(app)
.get('/account/edit')
.expect('editing user 12', done);
})
})
+3 -1
Ver Arquivo
@@ -1,6 +1,7 @@
var express = require('../')
, request = require('./support/http');
, request = require('./support/http')
, assert = require('assert');
describe('req', function(){
describe('.get(field)', function(){
@@ -8,6 +9,7 @@ describe('req', function(){
var app = express();
app.use(function(req, res){
assert(req.get('Something-Else') === undefined);
res.end(req.get('Content-Type'));
});
+18
Ver Arquivo
@@ -0,0 +1,18 @@
var express = require('../');
function req(ret) {
return {
get: function(){ return ret }
, __proto__: express.request
};
}
describe('req', function(){
describe('.host', function(){
it('should return hostname', function(){
req('example.com:3000').host.should.equal('example.com');
req('example.com').host.should.equal('example.com');
})
})
})
+57
Ver Arquivo
@@ -0,0 +1,57 @@
var express = require('../')
, request = require('./support/http');
describe('req', function(){
describe('.ip', function(){
describe('when X-Forwarded-For is present', function(){
describe('when "trust proxy" is enabled', function(){
it('should return the client addr', function(done){
var app = express();
app.enable('trust proxy');
app.use(function(req, res, next){
res.send(req.ip);
});
request(app)
.get('/')
.set('X-Forwarded-For', 'client, p1, p2')
.expect('client', done);
})
})
describe('when "trust proxy" is disabled', function(){
it('should return the remote address', function(done){
var app = express();
app.use(function(req, res, next){
res.send(req.ip);
});
request(app)
.get('/')
.set('X-Forwarded-For', 'client, p1, p2')
.expect('127.0.0.1', done);
})
})
})
describe('when X-Forwarded-For is not present', function(){
it('should return the remote address', function(done){
var app = express();
app.enable('trust proxy');
app.use(function(req, res, next){
res.send(req.ip);
});
request(app)
.get('/')
.expect('127.0.0.1', done);
})
})
})
})
+28 -9
Ver Arquivo
@@ -5,17 +5,36 @@ var express = require('../')
describe('req', function(){
describe('.ips', function(){
describe('when X-Forwarded-For is present', function(){
it('should return an array of the specified addresses', function(done){
var app = express();
describe('when "trust proxy" is enabled', function(){
it('should return an array of the specified addresses', function(done){
var app = express();
app.use(function(req, res, next){
res.send(req.ips);
});
app.enable('trust proxy');
request(app)
.get('/')
.set('X-Forwarded-For', 'client, p1, p2')
.expect('["p2","p1","client"]', done);
app.use(function(req, res, next){
res.send(req.ips);
});
request(app)
.get('/')
.set('X-Forwarded-For', 'client, p1, p2')
.expect('["client","p1","p2"]', done);
})
})
describe('when "trust proxy" is disabled', function(){
it('should return an empty array', function(done){
var app = express();
app.use(function(req, res, next){
res.send(req.ips);
});
request(app)
.get('/')
.set('X-Forwarded-For', 'client, p1, p2')
.expect('[]', done);
})
})
})
+2 -2
Ver Arquivo
@@ -59,13 +59,13 @@ describe('req', function(){
var app = express();
app.get('/user/:name', function(req, res){
res.end(req.param('name'));
res.end(req.param('filter') + req.param('name'));
});
request(app)
.get('/user/tj')
.end(function(res){
res.body.should.equal('tj');
res.body.should.equal('undefinedtj');
done();
})
})
+2 -2
Ver Arquivo
@@ -14,7 +14,7 @@ describe('res', function(){
request(app)
.get('/')
.end(function(res){
var val = 'sid=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT';
var val = 'sid=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT';
res.headers['set-cookie'].should.eql([val]);
done();
})
@@ -32,7 +32,7 @@ describe('res', function(){
request(app)
.get('/')
.end(function(res){
var val = 'sid=; path=/admin; expires=Thu, 01 Jan 1970 00:00:00 GMT';
var val = 'sid=; Path=/admin; Expires=Thu, 01 Jan 1970 00:00:00 GMT';
res.headers['set-cookie'].should.eql([val]);
done();
})
+47 -5
Ver Arquivo
@@ -1,6 +1,7 @@
var express = require('../')
, request = require('./support/http');
, request = require('./support/http')
, cookie = require('cookie');
describe('res', function(){
describe('.cookie(name, object)', function(){
@@ -14,7 +15,7 @@ describe('res', function(){
request(app)
.get('/')
.end(function(res){
var val = ['user=j%3A%7B%22name%22%3A%22tobi%22%7D; path=/'];
var val = ['user=j:{%22name%22:%22tobi%22}; Path=/'];
res.headers['set-cookie'].should.eql(val);
done();
})
@@ -32,7 +33,7 @@ describe('res', function(){
request(app)
.get('/')
.end(function(res){
var val = ['name=tobi; path=/'];
var val = ['name=tobi; Path=/'];
res.headers['set-cookie'].should.eql(val);
done();
})
@@ -50,7 +51,7 @@ describe('res', function(){
request(app)
.get('/')
.end(function(res){
var val = ['name=tobi; path=/', 'age=1; path=/'];
var val = ['name=tobi; Path=/', 'age=1; Path=/'];
res.headers['set-cookie'].should.eql(val);
done();
})
@@ -69,7 +70,7 @@ describe('res', function(){
request(app)
.get('/')
.end(function(res){
var val = ['name=tobi; path=/; httpOnly; secure'];
var val = ['name=tobi; Path=/; HttpOnly; Secure'];
res.headers['set-cookie'].should.eql(val);
done();
})
@@ -92,5 +93,46 @@ describe('res', function(){
})
})
})
describe('signed', function(){
it('should generate a signed JSON cookie', function(done){
var app = express();
app.use(express.cookieParser('foo bar baz'));
app.use(function(req, res){
res.cookie('user', { name: 'tobi' }, { signed: true }).end();
});
request(app)
.get('/')
.end(function(res){
var val = res.headers['set-cookie'][0];
val = cookie.parse(val.split('.')[0]);
val.user.should.equal('j:{"name":"tobi"}');
done();
})
})
})
describe('.signedCookie(name, string)', function(){
it('should set a signed cookie', function(done){
var app = express();
app.use(express.cookieParser('foo bar baz'));
app.use(function(req, res){
res.cookie('name', 'tobi', { signed: true }).end();
});
request(app)
.get('/')
.end(function(res){
var val = ['name=tobi.xJjV2iZ6EI7C8E5kzwbfA9PVLl1ZR07UTnuTgQQ4EnQ; Path=/'];
res.headers['set-cookie'].should.eql(val);
done();
})
})
})
})
})
+79
Ver Arquivo
@@ -0,0 +1,79 @@
var express = require('../')
, request = require('./support/http')
, assert = require('assert');
describe('res', function(){
describe('.download(path)', function(){
it('should transfer as an attachment', function(done){
var app = express();
app.use(function(req, res){
res.download('test/fixtures/user.html');
});
request(app)
.get('/')
.end(function(res){
res.should.have.header('Content-Type', 'text/html; charset=UTF-8');
res.should.have.header('Content-Disposition', 'attachment; filename="user.html"');
res.body.should.equal('<p>{{user.name}}</p>');
done();
});
})
})
describe('.download(path, filename)', function(){
it('should provide an alternate filename', function(done){
var app = express();
app.use(function(req, res){
res.download('test/fixtures/user.html', 'document');
});
request(app)
.get('/')
.end(function(res){
res.should.have.header('Content-Type', 'text/html; charset=UTF-8');
res.should.have.header('Content-Disposition', 'attachment; filename="document"');
done();
});
})
})
describe('.download(path, fn)', function(){
it('should invoke the callback', function(done){
var app = express()
, calls = 0;
app.use(function(req, res){
res.download('test/fixtures/user.html', done);
});
request(app)
.get('/')
.end(function(res){
res.should.have.header('Content-Type', 'text/html; charset=UTF-8');
res.should.have.header('Content-Disposition', 'attachment; filename="user.html"');
});
})
})
describe('.download(path, filename, fn)', function(){
it('should invoke the callback', function(done){
var app = express()
, calls = 0;
app.use(function(req, res){
res.download('test/fixtures/user.html', 'document', done);
});
request(app)
.get('/')
.end(function(res){
res.should.have.header('Content-Type', 'text/html; charset=UTF-8');
res.should.have.header('Content-Disposition', 'attachment; filename="document"');
});
})
})
})
+6 -15
Ver Arquivo
@@ -1,23 +1,14 @@
var express = require('../')
, request = require('./support/http');
, res = express.response;
describe('res', function(){
describe('.get(field)', function(){
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.end(res.get('Content-Type'));
});
request(app)
.get('/')
.end(function(res){
res.body.should.equal('text/x-foo');
done();
})
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');
})
})
})
+16 -1
Ver Arquivo
@@ -9,7 +9,6 @@ describe('res', function(){
it('should respond with jsonp', function(done){
var app = express();
// app.enable('jsonp callback');
app.use(function(req, res){
res.json({ count: 1 });
});
@@ -22,6 +21,22 @@ describe('res', function(){
done();
})
})
it('should allow []', function(done){
var app = express();
app.use(function(req, res){
res.json({ count: 1 });
});
request(app)
.get('/?callback=callbacks[123]')
.end(function(res){
res.headers.should.have.property('content-type', 'text/javascript; charset=utf-8');
res.body.should.equal('callbacks[123]({"count":1});');
done();
})
})
})
describe('when given primitives', function(){
+23
Ver Arquivo
@@ -248,9 +248,32 @@ describe('res', function(){
.set('Accept', 'text/plain, */*')
.end(function(res){
res.headers.should.have.property('location', 'http://google.com');
res.headers.should.have.property('content-length', '51');
res.body.should.equal('Moved Temporarily. Redirecting to http://google.com');
done();
})
})
})
describe('when accepting neither text or html', function(){
it('should respond with an empty body', function(done){
var app = express();
app.use(function(req, res){
res.redirect('http://google.com');
});
request(app)
.get('/')
.set('Accept', 'foo/bar')
.end(function(res){
res.should.have.status(302);
res.headers.should.have.property('location', 'http://google.com');
res.headers.should.not.have.property('content-type');
res.headers.should.have.property('content-length', '0');
res.body.should.equal('');
done();
})
})
})
})
+16 -1
Ver Arquivo
@@ -24,7 +24,22 @@ describe('res', function(){
done();
});
})
it('should utilize the same options as express.static()', function(done){
var app = express();
app.use(function(req, res){
res.sendfile('test/fixtures/user.html', { maxAge: 60000 });
});
request(app)
.get('/')
.end(function(res){
res.should.have.header('Cache-Control', 'public, max-age=60');
done();
});
})
it('should invoke the callback on 404', function(done){
var app = express()
, calls = 0;
-46
Ver Arquivo
@@ -1,46 +0,0 @@
var express = require('../')
, request = require('./support/http');
describe('res', function(){
describe('.signedCookie(name, object)', function(){
it('should generate a signed JSON cookie', function(done){
var app = express();
app.use(express.cookieParser('foo bar baz'));
app.use(function(req, res){
res.signedCookie('user', { name: 'tobi' }).end();
});
request(app)
.get('/')
.end(function(res){
var val = res.headers['set-cookie'][0];
val = decodeURIComponent(val.split('.')[0]);
val.should.equal('user=j:{"name":"tobi"}');
done();
})
})
})
describe('.signedCookie(name, string)', function(){
it('should set a signed cookie', function(done){
var app = express();
app.use(express.cookieParser('foo bar baz'));
app.use(function(req, res){
res.signedCookie('name', 'tobi').end();
});
request(app)
.get('/')
.end(function(res){
var val = ['name=tobi.xJjV2iZ6EI7C8E5kzwbfA9PVLl1ZR07UTnuTgQQ4EnQ; path=/'];
res.headers['set-cookie'].should.eql(val);
done();
})
})
})
})