forked from expressjs/body-parser
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
266 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,264 @@ | ||
/*! | ||
* type-is | ||
* Copyright(c) 2014 Jonathan Ong | ||
* Copyright(c) 2014-2015 Douglas Christopher Wilson | ||
* MIT Licensed | ||
*/ | ||
|
||
'use strict' | ||
|
||
/** | ||
* Module dependencies. | ||
* @private | ||
*/ | ||
|
||
var typer = require('media-typer') | ||
|
||
/** | ||
* Module exports. | ||
* @public | ||
*/ | ||
|
||
module.exports = typeofrequest | ||
module.exports.is = typeis | ||
module.exports.hasBody = hasbody | ||
module.exports.normalize = normalize | ||
module.exports.match = mimeMatch | ||
|
||
/** | ||
* Compare a `value` content-type with `types`. | ||
* Each `type` can be an extension like `html`, | ||
* a special shortcut like `multipart` or `urlencoded`, | ||
* or a mime type. | ||
* | ||
* If no types match, `false` is returned. | ||
* Otherwise, the first `type` that matches is returned. | ||
* | ||
* @param {String} value | ||
* @param {Array} types | ||
* @public | ||
*/ | ||
|
||
function typeis (value, types_) { | ||
var i | ||
var types = types_ | ||
|
||
// remove parameters and normalize | ||
var val = tryNormalizeType(value) | ||
|
||
// no type or invalid | ||
if (!val) { | ||
return false | ||
} | ||
|
||
// support flattened arguments | ||
if (types && !Array.isArray(types)) { | ||
types = new Array(arguments.length - 1) | ||
for (i = 0; i < types.length; i++) { | ||
types[i] = arguments[i + 1] | ||
} | ||
} | ||
|
||
// no types, return the content type | ||
if (!types || !types.length) { | ||
return val | ||
} | ||
|
||
var type | ||
for (i = 0; i < types.length; i++) { | ||
if (mimeMatch(normalize(type = types[i]), val)) { | ||
return type[0] === '+' || type.indexOf('*') !== -1 | ||
? val | ||
: type | ||
} | ||
} | ||
|
||
// no matches | ||
return false | ||
} | ||
|
||
/** | ||
* Check if a request has a request body. | ||
* A request with a body __must__ either have `transfer-encoding` | ||
* or `content-length` headers set. | ||
* http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.3 | ||
* | ||
* @param {Object} request | ||
* @return {Boolean} | ||
* @public | ||
*/ | ||
|
||
function hasbody (req) { | ||
return req.headers['transfer-encoding'] !== undefined || | ||
!isNaN(req.headers['content-length']) | ||
} | ||
|
||
/** | ||
* Check if the incoming request contains the "Content-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: | ||
* | ||
* // With Content-Type: text/html; charset=utf-8 | ||
* this.is('html'); // => 'html' | ||
* this.is('text/html'); // => 'text/html' | ||
* this.is('text/*', 'application/json'); // => 'text/html' | ||
* | ||
* // When Content-Type is application/json | ||
* this.is('json', 'urlencoded'); // => 'json' | ||
* this.is('application/json'); // => 'application/json' | ||
* this.is('html', 'application/*'); // => 'application/json' | ||
* | ||
* this.is('html'); // => false | ||
* | ||
* @param {String|Array} types... | ||
* @return {String|false|null} | ||
* @public | ||
*/ | ||
|
||
function typeofrequest (req, types_) { | ||
var types = types_ | ||
|
||
// no body | ||
if (!hasbody(req)) { | ||
return null | ||
} | ||
|
||
// support flattened arguments | ||
if (arguments.length > 2) { | ||
types = new Array(arguments.length - 1) | ||
for (var i = 0; i < types.length; i++) { | ||
types[i] = arguments[i + 1] | ||
} | ||
} | ||
|
||
// request content type | ||
var value = req.headers['content-type'] | ||
|
||
return typeis(value, types) | ||
} | ||
|
||
/** | ||
* Normalize a mime type. | ||
* If it's a shorthand, expand it to a valid mime type. | ||
* | ||
* In general, you probably want: | ||
* | ||
* var type = is(req, ['urlencoded', 'json', 'multipart']); | ||
* | ||
* Then use the appropriate body parsers. | ||
* These three are the most common request body types | ||
* and are thus ensured to work. | ||
* | ||
* @param {String} type | ||
* @return {String|false|null} | ||
* @public | ||
*/ | ||
|
||
function normalize (type) { | ||
if (typeof type !== 'string') { | ||
// invalid type | ||
return false | ||
} | ||
|
||
switch (type) { | ||
case 'urlencoded': | ||
return 'application/x-www-form-urlencoded' | ||
case 'multipart': | ||
return 'multipart/*' | ||
} | ||
|
||
if (type[0] === '+') { | ||
// "+json" -> "*/*+json" expando | ||
return '*/*' + type | ||
} | ||
|
||
return type | ||
} | ||
|
||
/** | ||
* Check if `expected` mime type | ||
* matches `actual` mime type with | ||
* wildcard and +suffix support. | ||
* | ||
* @param {String} expected | ||
* @param {String} actual | ||
* @return {Boolean} | ||
* @public | ||
*/ | ||
|
||
function mimeMatch (expected, actual) { | ||
// invalid type | ||
if (expected === false) { | ||
return false | ||
} | ||
|
||
// split types | ||
var actualParts = actual.split('/') | ||
var expectedParts = expected.split('/') | ||
|
||
// invalid format | ||
if (actualParts.length !== 2 || expectedParts.length !== 2) { | ||
return false | ||
} | ||
|
||
// validate type | ||
if (expectedParts[0] !== '*' && expectedParts[0] !== actualParts[0]) { | ||
return false | ||
} | ||
|
||
// validate suffix wildcard | ||
if (expectedParts[1].substr(0, 2) === '*+') { | ||
return expectedParts[1].length <= actualParts[1].length + 1 && | ||
expectedParts[1].substr(1) === actualParts[1].substr(1 - expectedParts[1].length) | ||
} | ||
|
||
// validate subtype | ||
if (expectedParts[1] !== '*' && expectedParts[1] !== actualParts[1]) { | ||
return false | ||
} | ||
|
||
return true | ||
} | ||
|
||
/** | ||
* Normalize a type and remove parameters. | ||
* | ||
* @param {string} value | ||
* @return {string} | ||
* @private | ||
*/ | ||
|
||
function normalizeType (value) { | ||
// parse the type | ||
var type = typer.parse(value) | ||
|
||
// remove the parameters | ||
type.parameters = undefined | ||
|
||
// reformat it | ||
return typer.format(type) | ||
} | ||
|
||
/** | ||
* Try to normalize a type and remove parameters. | ||
* | ||
* @param {string} value | ||
* @return {string} | ||
* @private | ||
*/ | ||
|
||
function tryNormalizeType (value) { | ||
if (!value) { | ||
return null | ||
} | ||
|
||
try { | ||
return normalizeType(value) | ||
} catch (err) { | ||
return null | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters