| /*! | 
|  * 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') | 
| var mime = require('mime-types') | 
|   | 
| /** | 
|  * 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 | 
|  * @private | 
|  */ | 
|   | 
| 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.indexOf('/') === -1 | 
|     ? mime.lookup(type) | 
|     : type | 
| } | 
|   | 
| /** | 
|  * Check if `expected` mime type | 
|  * matches `actual` mime type with | 
|  * wildcard and +suffix support. | 
|  * | 
|  * @param {String} expected | 
|  * @param {String} actual | 
|  * @return {Boolean} | 
|  * @private | 
|  */ | 
|   | 
| 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 | 
|   } | 
| } |