req.is(): make better

closes #105 and #106
This commit is contained in:
Jonathan Ong 2013-11-28 00:13:13 -08:00
parent 1b9960a28e
commit 8717a3ad2b
3 changed files with 122 additions and 52 deletions

View file

@ -152,26 +152,24 @@ this.body = yield db.find('something');
### req.is(type) ### req.is(type)
Check if the incoming request contains the `Content-Type` Check if the incoming request contains the "Content-Type"
header field, and it contains the give mime `type`. header field, and it contains any of the give mime `type`s.
If there is no request body, `null` is returned.
If there is no content type, `false` is returned.
Otherwise, it returns the first `type` that matches.
```js ```js
// With Content-Type: text/html; charset=utf-8 // With Content-Type: text/html; charset=utf-8
this.is('html'); this.is('html'); // => 'html'
this.is('.html'); this.is('text/html'); // => 'text/html'
this.is('text/html'); this.is('text/*', 'text/html'); // => 'text/*'
this.is('text/*');
// => true
// When Content-Type is application/json // When Content-Type is application/json
this.is('json'); this.is('json', 'urlencoded'); // => 'json'
this.is('.json'); this.is('application/json'); // => 'application/json'
this.is('application/json'); this.is('html', 'application/*'); // => 'application/*'
this.is('application/*');
// => true
this.is('html'); this.is('html'); // => false
// => false
``` ```
### req.accepts(types) ### req.accepts(types)

View file

@ -487,49 +487,63 @@ module.exports = {
/** /**
* Check if the incoming request contains the "Content-Type" * Check if the incoming request contains the "Content-Type"
* header field, and it contains the give mime `type`. * header field, and it contains any of the give mime `type`s.
* If there is no request body, `null` is returned.
* If there is no content type, `false` is returned.
* Otherwise, it returns the first `type` that matches.
* *
* Examples: * Examples:
* *
* // With Content-Type: text/html; charset=utf-8 * // With Content-Type: text/html; charset=utf-8
* this.is('html'); * this.is('html'); // => 'html'
* this.is('text/html'); * this.is('text/html'); // => 'text/html'
* this.is('text/*'); * this.is('text/*', 'text/html'); // => 'text/*'
* // => true
* *
* // When Content-Type is application/json * // When Content-Type is application/json
* this.is('json'); * this.is('json', 'urlencoded'); // => 'json'
* this.is('application/json'); * this.is('application/json'); // => 'application/json'
* this.is('application/*'); * this.is('html', 'application/*'); // => 'application/*'
* // => true
* *
* this.is('html'); * this.is('html'); // => false
* // => false
* *
* @param {String} type * @param {String|Array} types...
* @return {Boolean} * @return {String|false|null}
* @api public * @api public
*/ */
is: function(type){ is: function(types){
// no request body
if (!(this.length || 'transfer-encoding' in this.header)) return null;
var ct = this.type; var ct = this.type;
// request body without a content type?
if (!ct) return false; if (!ct) return false;
ct = ct.split(';')[0]; ct = ct.split(';')[0];
if (!types) return ct;
// extension given if (!Array.isArray(types)) types = [].slice.call(arguments);
if (!~type.indexOf('/')) type = mime.lookup(type); var type, mt, cts;
for (var i = 0; i < types.length; i++) {
// type or subtype match type = types[i];
if (~type.indexOf('*')) { // exact match
type = type.split('/'); if (type == ct) return type;
ct = ct.split('/'); // convert to a valid mime type
if ('*' == type[0] && type[1] == ct[1]) return true; switch (type) {
if ('*' == type[1] && type[0] == ct[0]) return true; case 'urlencoded':
return false; mt = 'application/x-www-form-urlencoded';
break;
default:
mt = ~type.indexOf('/') ? type : mime.lookup(type);
}
// mime types match
if (mt == ct) return type;
// type or subtype match
if (!~type.indexOf('*')) continue;
mt = mt.split('/');
cts = cts || ct.split('/');
if ('*' == mt[0] && mt[1] == cts[1]) return type;
if ('*' == mt[1] && mt[0] == cts[0]) return type;
} }
// no matches
// exact match return false;
return type == ct;
}, },
/** /**

View file

@ -1,38 +1,96 @@
var should = require('should');
var context = require('../context'); var context = require('../context');
describe('ctx.is(type)', function(){ describe('ctx.is(type)', function(){
it('should ignore params', function(){ it('should ignore params', function(){
var ctx = context(); var ctx = context();
ctx.header['content-type'] = 'text/html; charset=utf-8'; ctx.header['content-type'] = 'text/html; charset=utf-8';
ctx.is('text/*').should.be.true; ctx.header['transfer-encoding'] = 'chunked';
ctx.is('text/*').should.equal('text/*');
}) })
describe('given a mime', function(){ describe('when no body is given', function(){
it('should check the type', function(){ it('should return null', function(){
var ctx = context();
should(ctx.is()).null;
should(ctx.is('image/*')).null;
should(ctx.is('text/*', 'image/*')).null;
})
})
describe('when no content type is given', function(){
it('should return false', function(){
var ctx = context();
ctx.header['transfer-encoding'] = 'chunked';
ctx.is().should.be.false;
ctx.is('image/*').should.be.false;
ctx.is('text/*', 'image/*').should.be.false;
})
})
describe('give no types', function(){
it('should return the mime type', function(){
var ctx = context(); var ctx = context();
ctx.header['content-type'] = 'image/png'; ctx.header['content-type'] = 'image/png';
ctx.header['transfer-encoding'] = 'chunked';
ctx.is('image/png').should.be.true; ctx.is().should.equal('image/png');
ctx.is('image/*').should.be.true; })
ctx.is('*/png').should.be.true; })
describe('given one type', function(){
it('should return the type or false', function(){
var ctx = context();
ctx.header['content-type'] = 'image/png';
ctx.header['transfer-encoding'] = 'chunked';
ctx.is('png').should.equal('png');
ctx.is('.png').should.equal('.png');
ctx.is('image/png').should.equal('image/png');
ctx.is('image/*').should.equal('image/*');
ctx.is('*/png').should.equal('*/png');
ctx.is('jpeg').should.be.false;
ctx.is('.jpeg').should.be.false;
ctx.is('image/jpeg').should.be.false; ctx.is('image/jpeg').should.be.false;
ctx.is('text/*').should.be.false; ctx.is('text/*').should.be.false;
ctx.is('*/jpeg').should.be.false; ctx.is('*/jpeg').should.be.false;
}) })
}) })
describe('given an extension', function(){ describe('given multiple types', function(){
it('should check the type', function(){ it('should return the first match or false', function(){
var ctx = context(); var ctx = context();
ctx.header['content-type'] = 'image/png'; ctx.header['content-type'] = 'image/png';
ctx.header['transfer-encoding'] = 'chunked';
ctx.is('png').should.be.true; ctx.is('png').should.equal('png');
ctx.is('.png').should.be.true; ctx.is('.png').should.equal('.png');
ctx.is('text/*', 'image/*').should.equal('image/*');
ctx.is('image/*', 'text/*').should.equal('image/*');
ctx.is('image/*', 'image/png').should.equal('image/*');
ctx.is('image/png', 'image/*').should.equal('image/png');
ctx.is('jpeg').should.be.false; ctx.is('jpeg').should.be.false;
ctx.is('.jpeg').should.be.false; ctx.is('.jpeg').should.be.false;
ctx.is('text/*', 'application/*').should.be.false;
ctx.is('text/html', 'text/plain', 'application/json').should.be.false;
})
})
describe('when Content-Type: application/x-www-form-urlencoded', function(){
it('should match `urlencoded', function(){
var ctx = context();
ctx.header['content-type'] = 'application/x-www-form-urlencoded';
ctx.header['transfer-encoding'] = 'chunked';
ctx.is('urlencoded').should.equal('urlencoded');
ctx.is('json', 'urlencoded').should.equal('urlencoded');
ctx.is('urlencoded', 'json').should.equal('urlencoded');
}) })
}) })
}) })