Compare commits

...

26 Commits
3.1.2 ... 3.2.1

Author SHA1 Message Date
TJ Holowaychuk
9f06d9b03f Release 3.2.1 2013-04-29 19:17:08 -07:00
TJ Holowaychuk
3fb7c4e1db update connect 2013-04-29 19:16:33 -07:00
TJ Holowaychuk
d0e49f1a8a update qs and remove all ~ semver crap 2013-04-26 13:12:33 -07:00
TJ Holowaychuk
ea2664a4b8 Merge branch 'master' of github.com:visionmedia/express 2013-04-25 16:29:50 -07:00
TJ Holowaychuk
da6524bd06 Merge pull request #1589 from hacksparrow/master
Signed cookies can now accept numbers as values, like unsigned cookies
2013-04-25 16:29:39 -07:00
TJ Holowaychuk
a231406931 Merge branch 'master' of github.com:visionmedia/express 2013-04-25 16:26:44 -07:00
Hack Sparrow
6d39ed8ef7 Accept number as value of Signed Cookie 2013-04-23 22:53:35 +05:30
TJ Holowaychuk
f2563f4dde Merge pull request #1586 from yields/master
removed some spaces from bin/express
2013-04-21 18:18:19 -07:00
Amir Abu Shareb
3df265b36a remove spaces when a session is enabled. 2013-04-21 15:41:42 +03:00
TJ Holowaychuk
e382e6adc7 update supertest dev dep 2013-04-16 06:49:56 -07:00
TJ Holowaychuk
91c71d6c2e add app.VERB() paths array deprecation warning 2013-04-15 15:18:28 -07:00
TJ Holowaychuk
0d40c65b7f Release 3.2.0 2013-04-15 12:34:41 -07:00
TJ Holowaychuk
58f2057ba7 revert cookie signature change causing session race conditions 2013-04-15 12:33:12 -07:00
TJ Holowaychuk
37179109db Revert "fix res.cookie() tests"
This reverts commit ed273448b9.
2013-04-15 12:29:42 -07:00
TJ Holowaychuk
579857cfaa fix example port 2013-04-13 10:14:23 -07:00
Caridy Patino
0b4e2df480 add "view" constructor setting to override view behaviour 2013-04-13 09:53:50 -07:00
TJ Holowaychuk
49cc1a70b1 Merge pull request #1571 from jlubawy/master
Change to crypto.pbkdf2 in Node v0.10 broke auth example
2013-04-13 09:35:11 -07:00
TJ Holowaychuk
f8a33d137a refactor 2013-04-13 09:16:15 -07:00
TJ Holowaychuk
2db135dfc7 Merge pull request #1566 from daguej/v8-context-fix
Possible fix for #1557
2013-04-13 09:14:41 -07:00
TJ Holowaychuk
99bc628ad1 fix long list params test 2013-04-13 09:07:48 -07:00
TJ Holowaychuk
5ba6c301d7 Merge pull request #1578 from Notificare/master
Correct sorting of long list of accept header
2013-04-13 09:06:09 -07:00
silentjohnny
88273a59f8 Added originalIndex to parseQuality to correctly sort long lists (v8 does unstable quicksort for length > 10) 2013-04-13 12:36:35 +02:00
TJ Holowaychuk
2e53cb72ec add req.acceptsEncoding(name) 2013-04-12 12:56:50 -07:00
TJ Holowaychuk
3b1597d79e add req.acceptedEncodings 2013-04-12 12:55:53 -07:00
Josh Lubawy
ee9d50c128 Modified hash to return base64 encoded strings. 2013-04-04 23:26:27 -07:00
Josh Dague
57e48c4767 Possible fix for #1557, allows routes to be created using literal regexes across V8 contexts. Removes all uses of instanceof. 2013-04-01 14:03:32 -04:00
18 changed files with 310 additions and 96 deletions

View File

@@ -1,4 +1,21 @@
3.2.1 / 2013-04-29
==================
* add app.VERB() paths array deprecation warning
* update connect
* update qs and remove all ~ semver crap
* fix: accept number as value of Signed Cookie
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
3.1.2 / 2013-04-12
==================

View File

@@ -334,7 +334,7 @@ function createApplicationAt(path) {
// Session support
app = app.replace('{sess}', program.sessions
? eol + ' app.use(express.cookieParser(\'your secret here\'));' + eol + ' app.use(express.session());'
? eol + 'app.use(express.cookieParser(\'your secret here\'));' + eol + 'app.use(express.session());'
: '');
// Template support

View File

@@ -31,7 +31,9 @@ var iterations = 12000;
exports.hash = function (pwd, salt, fn) {
if (3 == arguments.length) {
crypto.pbkdf2(pwd, salt, iterations, len, fn);
crypto.pbkdf2(pwd, salt, iterations, len, function(err, hash){
fn(err, (new Buffer(hash, 'binary')).toString('base64'));
});
} else {
fn = salt;
crypto.randomBytes(len, function(err, salt){
@@ -39,8 +41,8 @@ exports.hash = function (pwd, salt, fn) {
salt = salt.toString('base64');
crypto.pbkdf2(pwd, salt, iterations, len, function(err, hash){
if (err) return fn(err);
fn(null, salt, hash);
fn(null, salt, (new Buffer(hash, 'binary')).toString('base64'));
});
});
}
};
};

View File

@@ -3,7 +3,7 @@
* Module dependencies.
*/
var express = require('../../')
var express = require('../..')
, fs = require('fs')
, md = require('github-flavored-markdown').parse;
@@ -42,4 +42,4 @@ app.get('/fail', function(req, res){
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}
}

View File

@@ -0,0 +1,52 @@
/**
* Module dependencies.
*/
var http = require('http')
, path = require('path')
, extname = path.extname
/**
* Expose `GithubView`.
*/
module.exports = GithubView;
/**
* Custom view that fetches and renders
* remove github templates. You could
* render templates from a database etc.
*/
function GithubView(name, options){
this.name = name;
options = options || {};
this.engine = options.engines[extname(name)];
// "root" is the app.set('views') setting, however
// in your own implementation you could ignore this
this.path = '/' + options.root + '/master/' + name;
}
/**
* Render the view.
*/
GithubView.prototype.render = function(options, fn){
var self = this;
var opts = {
host: 'rawgithub.com',
port: 80,
path: this.path,
method: 'GET'
};
http.request(opts, function(res) {
var buf = '';
res.setEncoding('utf8');
res.on('data', function(str){ buf += str });
res.on('end', function(){
self.engine(buf, options, fn);
});
}).end();
};

View File

@@ -0,0 +1,47 @@
/**
* Module dependencies.
*/
var express = require('../../')
, http = require('http')
, GithubView = require('./github-view')
, md = require('github-flavored-markdown').parse;
var app = module.exports = express();
// register .md as an engine in express view system
app.engine('md', function(str, options, fn){
try {
var html = md(str);
html = html.replace(/\{([^}]+)\}/g, function(_, name){
return options[name] || '';
})
fn(null, html);
} catch(err) {
fn(err);
}
})
// pointing to a particular github repo to load files from it
app.set('views', 'visionmedia/express');
// register a new view constructor
app.set('view', GithubView);
app.get('/', function(req, res){
// rendering a view relative to the repo.
// app.locals, res.locals, and locals passed
// work like they normally would
res.render('examples/markdown/views/index.md', { title: 'Example' });
})
app.get('/Readme.md', function(req, res){
// rendering a view from https://github.com/visionmedia/express/blob/master/Readme.md
res.render('Readme.md');
})
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}

View File

@@ -79,6 +79,7 @@ app.defaultConfiguration = function(){
this.locals.settings = this.settings;
// default configuration
this.set('view', View);
this.set('views', process.cwd() + '/views');
this.set('jsonp callback name', 'callback');
@@ -401,6 +402,11 @@ methods.forEach(function(method){
app[method] = function(path){
if ('get' == method && 1 == arguments.length) return this.set(path);
// deprecated
if (Array.isArray(path)) {
console.trace('passing an array to app.VERB() is deprecated and will be removed in 4.0');
}
// if no router attached yet, attach the router
if (!this._usedRouter) this.use(this.router);
@@ -479,7 +485,7 @@ app.render = function(name, options, fn){
// view
if (!view) {
view = new View(name, {
view = new (this.get('view'))(name, {
defaultEngine: this.get('view engine'),
root: this.get('views'),
engines: engines

View File

@@ -20,7 +20,7 @@ exports = module.exports = createApplication;
* Framework version.
*/
exports.version = '3.1.2';
exports.version = '3.2.0';
/**
* Expose mime.

View File

@@ -101,6 +101,18 @@ req.accepts = function(type){
return utils.accepts(type, this.get('Accept'));
};
/**
* Check if the given `encoding` is accepted.
*
* @param {String} encoding
* @return {Boolean}
* @api public
*/
req.acceptsEncoding = function(encoding){
return ~this.acceptedEncodings.indexOf(encoding);
};
/**
* Check if the given `charset` is acceptable,
* otherwise you should respond with 406 "Not Acceptable".
@@ -159,6 +171,24 @@ req.range = function(size){
return parseRange(size, range);
};
/**
* Return an array of encodings.
*
* Examples:
*
* ['gzip', 'deflate']
*
* @return {Array}
* @api public
*/
req.__defineGetter__('acceptedEncodings', function(){
var accept = this.get('Accept-Encoding');
return accept
? accept.trim().split(/ *, */)
: [];
});
/**
* Return an array of Accepted media types
* ordered from highest quality to lowest.

View File

@@ -580,6 +580,7 @@ res.cookie = function(name, val, options){
var secret = this.req.secret;
var signed = options.signed;
if (signed && !secret) throw new Error('connect.cookieParser("secret") required for signed cookies');
if ('number' == typeof val) val = val.toString();
if ('object' == typeof val) val = 'j:' + JSON.stringify(val);
if (signed) val = 's:' + sign(val, secret);
if ('maxAge' in options) {

View File

@@ -6,6 +6,12 @@
var mime = require('connect').mime
, crc32 = require('buffer-crc32');
/**
* toString ref.
*/
var toString = {}.toString;
/**
* Return ETag for `body`.
*
@@ -217,22 +223,27 @@ exports.parseParams = function(str){
return obj.quality;
})
.sort(function(a, b){
return b.quality - a.quality;
if (a.quality === b.quality) {
return a.originalIndex - b.originalIndex;
} else {
return b.quality - a.quality;
}
});
};
/**
* Parse accept params `str` returning an
* object with `.value`, `.quality` and `.params`.
* also includes `.originalIndex` for stable sorting
*
* @param {String} str
* @return {Object}
* @api private
*/
function acceptParams(str) {
function acceptParams(str, index) {
var parts = str.split(/ *; */);
var ret = { value: parts[0], quality: 1, params: {} };
var ret = { value: parts[0], quality: 1, params: {}, originalIndex: index };
for (var i = 1; i < parts.length; ++i) {
var pms = parts[i].split(/ *= */);
@@ -280,7 +291,7 @@ exports.escape = function(html) {
*/
exports.pathRegexp = function(path, keys, sensitive, strict) {
if (path instanceof RegExp) return path;
if (toString.call(path) == '[object RegExp]') return path;
if (Array.isArray(path)) path = '(' + path.join('|') + ')';
path = path
.concat(strict ? '' : '/?')

View File

@@ -1,7 +1,7 @@
{
"name": "express",
"description": "Sinatra inspired web development framework",
"version": "3.1.2",
"version": "3.2.1",
"author": "TJ Holowaychuk <tj@vision-media.ca>",
"contributors": [
{
@@ -22,17 +22,18 @@
}
],
"dependencies": {
"connect": "2.7.5",
"connect": "2.7.7",
"commander": "0.6.1",
"range-parser": "0.0.4",
"mkdirp": "~0.3.4",
"mkdirp": "0.3.4",
"cookie": "0.0.5",
"buffer-crc32": "~0.2.1",
"buffer-crc32": "0.2.1",
"fresh": "0.1.0",
"methods": "0.0.1",
"send": "0.1.0",
"cookie-signature": "1.0.0",
"debug": "*"
"cookie-signature": "1.0.1",
"debug": "*",
"qs": "0.6.1"
},
"devDependencies": {
"ejs": "*",
@@ -43,7 +44,7 @@
"should": "*",
"connect-redis": "*",
"github-flavored-markdown": "*",
"supertest": "0.0.1"
"supertest": "0.6.0"
},
"keywords": [
"express",

View File

@@ -8,7 +8,7 @@ describe('app', function(){
var app = express();
app.param(function(name, regexp){
if (regexp instanceof RegExp) {
if (Object.prototype.toString.call(regexp) == '[object RegExp]') { // See #1557
return function(req, res, next, val){
var captures;
if (captures = regexp.exec(String(val))) {

View File

@@ -14,7 +14,7 @@ describe('app', function(){
done();
})
})
it('should support absolute paths with "view engine"', function(done){
var app = express();
@@ -40,7 +40,7 @@ describe('app', function(){
done();
})
})
it('should support index.<engine>', function(done){
var app = express();
@@ -109,8 +109,31 @@ describe('app', function(){
})
})
})
describe('when a "view" constructor is given', function(){
it('should create an instance of it', function(done){
var app = express();
function View(name, options){
this.name = name;
this.path = 'path is required by application.js as a signal of success even though it is not used there.';
}
View.prototype.render = function(options, fn){
fn(null, 'abstract engine');
};
app.set('view', View);
app.render('something', function(err, str){
if (err) return done(err);
str.should.equal('abstract engine');
done();
})
})
})
})
describe('.render(name, options, fn)', function(){
it('should render the template', function(done){
var app = express();
@@ -125,7 +148,7 @@ describe('app', function(){
done();
})
})
it('should expose app.locals', function(done){
var app = express();
@@ -138,7 +161,7 @@ describe('app', function(){
done();
})
})
it('should give precedence to app.render() locals', function(done){
var app = express();

View File

@@ -48,7 +48,7 @@ describe('app.router', function(){
calls.push('before');
next();
});
app.use(app.router);
app.use(function(req, res, next){
@@ -68,7 +68,7 @@ describe('app.router', function(){
done();
})
})
it('should be auto .use()d on the first app.VERB() call', function(done){
var app = express();
@@ -78,7 +78,7 @@ describe('app.router', function(){
calls.push('before');
next();
});
app.get('/', function(req, res, next){
calls.push('GET /')
next();
@@ -109,7 +109,7 @@ describe('app.router', function(){
.get('/user/12?foo=bar')
.expect('user', done);
})
it('should populate req.params with the captures', function(done){
var app = express();
@@ -124,24 +124,6 @@ describe('app.router', function(){
.expect('editing user 10', done);
})
})
describe('when given an array', function(){
it('should match all paths in the array', function(done){
var app = express();
app.get(['/one', '/two'], function(req, res){
res.end('works');
});
request(app)
.get('/one')
.expect('works', function() {
request(app)
.get('/two')
.expect('works', done);
});
})
})
describe('case sensitivity', function(){
it('should be disabled by default', function(done){
@@ -155,7 +137,7 @@ describe('app.router', function(){
.get('/USER')
.expect('tj', done);
})
describe('when "case sensitive routing" is enabled', function(){
it('should match identical casing', function(done){
var app = express();
@@ -170,7 +152,7 @@ describe('app.router', function(){
.get('/uSer')
.expect('tj', done);
})
it('should not match otherwise', function(done){
var app = express();
@@ -199,7 +181,7 @@ describe('app.router', function(){
.get('/user/')
.expect('tj', done);
})
describe('when "strict routing" is enabled', function(){
it('should match trailing slashes', function(done){
var app = express();
@@ -214,7 +196,7 @@ describe('app.router', function(){
.get('/user/')
.expect('tj', done);
})
it('should match no slashes', function(done){
var app = express();
@@ -228,7 +210,7 @@ describe('app.router', function(){
.get('/user')
.expect('tj', done);
})
it('should fail when omitting the trailing slash', function(done){
var app = express();
@@ -242,7 +224,7 @@ describe('app.router', function(){
.get('/user')
.expect(404, done);
})
it('should fail when adding the trailing slash', function(done){
var app = express();
@@ -275,7 +257,7 @@ describe('app.router', function(){
.expect(404, done);
});
})
it('should allow literal "."', function(done){
var app = express();
@@ -303,7 +285,7 @@ describe('app.router', function(){
.get('/user/tj.json')
.expect('tj', done);
})
it('should work with several', function(done){
var app = express();
@@ -346,7 +328,7 @@ describe('app.router', function(){
.get('/api/users/0.json')
.expect('users/0.json', done);
})
it('should not be greedy immediately after param', function(done){
var app = express();
@@ -370,7 +352,7 @@ describe('app.router', function(){
.get('/user/122/aaa')
.expect('122', done);
})
it('should span multiple segments', function(done){
var app = express();
@@ -382,7 +364,7 @@ describe('app.router', function(){
.get('/file/javascripts/jquery.js')
.expect('javascripts/jquery.js', done);
})
it('should be optional', function(done){
var app = express();
@@ -394,7 +376,7 @@ describe('app.router', function(){
.get('/file/')
.expect('', done);
})
it('should require a preceeding /', function(done){
var app = express();
@@ -420,7 +402,7 @@ describe('app.router', function(){
.get('/user/tj')
.expect('tj', done);
})
it('should match a single segment only', function(done){
var app = express();
@@ -432,7 +414,7 @@ describe('app.router', function(){
.get('/user/tj/edit')
.expect(404, done);
})
it('should allow several capture groups', function(done){
var app = express();
@@ -459,7 +441,7 @@ describe('app.router', function(){
.get('/user/tj')
.expect('viewing tj', done);
})
it('should populate the capture group', function(done){
var app = express();
@@ -473,7 +455,7 @@ describe('app.router', function(){
.expect('editing tj', done);
})
})
describe('.:name', function(){
it('should denote a format', function(done){
var app = express();
@@ -491,7 +473,7 @@ describe('app.router', function(){
});
})
})
describe('.:name?', function(){
it('should denote an optional format', function(done){
var app = express();
@@ -509,7 +491,7 @@ describe('app.router', function(){
});
})
})
describe('when next() is called', function(){
it('should continue lookup', function(done){
var app = express()
@@ -528,7 +510,7 @@ describe('app.router', function(){
calls.push('/foo');
next();
});
app.get('/foo', function(req, res, next){
calls.push('/foo 2');
res.end('done');
@@ -542,7 +524,7 @@ describe('app.router', function(){
})
})
})
describe('when next(err) is called', function(){
it('should break out of app.router', function(done){
var app = express()
@@ -561,7 +543,7 @@ describe('app.router', function(){
calls.push('/foo');
next(new Error('fail'));
});
app.get('/foo', function(req, res, next){
assert(0);
});

View File

@@ -0,0 +1,36 @@
var express = require('../')
, request = require('./support/http');
describe('req', function(){
describe('.acceptedEncodings', function(){
it('should return an array of accepted encodings', function(done){
var app = express();
app.use(function(req, res){
req.acceptedEncodings.should.eql(['gzip', 'deflate']);
res.end();
});
request(app)
.get('/')
.set('Accept-Encoding', ' gzip, deflate')
.expect(200, done);
})
describe('when Accept-Encoding is not present', function(){
it('should default to []', function(done){
var app = express();
app.use(function(req, res){
req.acceptedEncodings.should.have.length(0);
res.end();
});
request(app)
.get('/')
.expect(200, done);
})
})
})
})

View File

@@ -39,7 +39,7 @@ describe('res', function(){
done();
})
})
it('should allow multiple calls', function(done){
var app = express();
@@ -58,7 +58,7 @@ describe('res', function(){
})
})
})
describe('.cookie(name, string, options)', function(){
it('should set params', function(done){
var app = express();
@@ -76,7 +76,7 @@ describe('res', function(){
done();
})
})
describe('maxAge', function(){
it('should set relative expires', function(done){
var app = express();
@@ -164,7 +164,7 @@ describe('res', function(){
request(app)
.get('/')
.end(function(err, res){
var val = ['name=s%3Atobi.z6Nfs5haoP4UAqCcr497ZljiIbrNqn8EjjM10baIYvvG32lReGseC3v2T79fecY4G%2FLdEm9fpTihvlEMVuNjGw; Path=/'];
var val = ['name=s%3Atobi.xJjV2iZ6EI7C8E5kzwbfA9PVLl1ZR07UTnuTgQQ4EnQ; Path=/'];
res.headers['set-cookie'].should.eql(val);
done();
})

View File

@@ -6,7 +6,7 @@ describe('utils.etag(body)', function(){
var str = 'Hello CRC';
var strUTF8 = '<!DOCTYPE html>\n<html>\n<head>\n</head>\n<body><p>自動販売</p></body></html>';
it('should support strings', function(){
utils.etag(str).should.eql('"-2034458343"');
})
@@ -27,7 +27,7 @@ describe('utils.isAbsolute()', function(){
assert(utils.isAbsolute('c:\\'));
assert(!utils.isAbsolute(':\\'));
})
it('should unices', function(){
assert(utils.isAbsolute('/foo/bar'));
assert(!utils.isAbsolute('foo/bar'));
@@ -52,32 +52,32 @@ describe('utils.escape(html)', function(){
describe('utils.parseParams(str)', function(){
it('should default quality to 1', function(){
utils.parseParams('text/html')
.should.eql([{ value: 'text/html', quality: 1, params: {}}]);
.should.eql([{ value: 'text/html', quality: 1, params: {}, originalIndex: 0 }]);
})
it('should parse qvalues', function(){
utils.parseParams('text/html; q=0.5')
.should.eql([{ value: 'text/html', quality: 0.5, params: {}}]);
.should.eql([{ value: 'text/html', quality: 0.5, params: {}, originalIndex: 0 }]);
utils.parseParams('text/html; q=.2')
.should.eql([{ value: 'text/html', quality: 0.2, params: {}}]);
.should.eql([{ value: 'text/html', quality: 0.2, params: {}, originalIndex: 0 }]);
})
it('should parse accept parameters', function(){
utils.parseParams('application/json; ver=2.0')
.should.eql([{ value: 'application/json', quality: 1, params: {ver: "2.0"}}]);
.should.eql([{ value: 'application/json', quality: 1, params: {ver: "2.0"}, originalIndex: 0 }]);
utils.parseParams('text/html; q=0.5; level=2')
.should.eql([{ value: 'text/html', quality: 0.5, params: {level: "2"}}]);
.should.eql([{ value: 'text/html', quality: 0.5, params: {level: "2"}, originalIndex: 0 }]);
utils.parseParams('text/html;q=.2;ver=beta')
.should.eql([{ value: 'text/html', quality: 0.2, params: {ver: "beta"}}]);
.should.eql([{ value: 'text/html', quality: 0.2, params: {ver: "beta"}, originalIndex: 0 }]);
})
it('should work with messed up whitespace', function(){
utils.parseParams('text/html ; q = .2')
.should.eql([{ value: 'text/html', quality: 0.2, params: {}}]);
.should.eql([{ value: 'text/html', quality: 0.2, params: {}, originalIndex: 0 }]);
})
it('should work with multiples', function(){
var str = 'da, en;q=.5, en-gb;q=.8';
var arr = utils.parseParams(str);
@@ -85,7 +85,13 @@ describe('utils.parseParams(str)', function(){
arr[1].value.should.equal('en-gb');
arr[2].value.should.equal('en');
})
it('should work with long lists', function(){
var str = 'en, nl, fr, de, ja, it, es, pt, pt-PT, da, fi, nb, sv, ko, zh-Hans, zh-Hant, ru, pl';
var arr = utils.parseParams(str).map(function(o){ return o.value });
arr.should.eql(str.split(', '));
})
it('should sort by quality', function(){
var str = 'text/plain;q=.2, application/json, text/html;q=0.5';
var arr = utils.parseParams(str);
@@ -93,7 +99,7 @@ describe('utils.parseParams(str)', function(){
arr[1].value.should.equal('text/html');
arr[2].value.should.equal('text/plain');
})
it('should exclude those with a quality of 0', function(){
var str = 'text/plain;q=.2, application/json, text/html;q=0';
var arr = utils.parseParams(str);
@@ -106,7 +112,7 @@ describe('utils.parseAccept(str)', function(){
var arr = utils.parseAccept('text/html');
arr[0].type.should.equal('text');
})
it('should provide .subtype', function(){
var arr = utils.parseAccept('text/html');
arr[0].subtype.should.equal('html');
@@ -120,7 +126,7 @@ describe('utils.accepts(type, str)', function(){
.should.equal('text/html');
})
})
describe('when a string is empty', function(){
it('should return the value', function(){
utils.accepts('text/html', '')
@@ -166,44 +172,44 @@ describe('utils.accepts(type, str)', function(){
utils.accepts('text/html', 'text/plain, text/html')
.should.equal('text/html');
})
it('should return undefined otherwise', function(){
assert(null == utils.accepts('text/html', 'text/plain, application/json'));
})
})
describe('when accepting */subtype', function(){
it('should return the value when present', function(){
utils.accepts('text/html', 'text/*')
.should.equal('text/html');
})
it('should return undefined otherwise', function(){
assert(null == utils.accepts('text/html', 'image/*'));
})
})
describe('when accepting type/*', function(){
it('should return the value when present', function(){
utils.accepts('text/html', '*/html')
.should.equal('text/html');
})
it('should return undefined otherwise', function(){
assert(null == utils.accepts('text/html', '*/json'));
})
})
describe('when an extension is given', function(){
it('should return the value when present', function(){
utils.accepts('html', 'text/html, application/json')
.should.equal('html');
})
it('should return undefined otherwise', function(){
assert(null == utils.accepts('html', 'text/plain, application/json'));
})
it('should support *', function(){
utils.accepts('html', 'text/*')
.should.equal('html');
@@ -212,4 +218,4 @@ describe('utils.accepts(type, str)', function(){
.should.equal('html');
})
})
})
})