| /*! |
| * 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 |
| } |
| } |