/*!1* accepts2* Copyright(c) 2014 Jonathan Ong3* Copyright(c) 2015 Douglas Christopher Wilson4* MIT Licensed5*/67'use strict'89/**10* Module dependencies.11* @private12*/1314var Negotiator = require('negotiator')15var mime = require('mime-types')1617/**18* Module exports.19* @public20*/2122module.exports = Accepts2324/**25* Create a new Accepts object for the given req.26*27* @param {object} req28* @public29*/3031function Accepts(req) {32if (!(this instanceof Accepts))33return new Accepts(req)3435this.headers = req.headers36this.negotiator = new Negotiator(req)37}3839/**40* Check if the given `type(s)` is acceptable, returning41* the best match when true, otherwise `undefined`, in which42* case you should respond with 406 "Not Acceptable".43*44* The `type` value may be a single mime type string45* such as "application/json", the extension name46* such as "json" or an array `["json", "html", "text/plain"]`. When a list47* or array is given the _best_ match, if any is returned.48*49* Examples:50*51* // Accept: text/html52* this.types('html');53* // => "html"54*55* // Accept: text/*, application/json56* this.types('html');57* // => "html"58* this.types('text/html');59* // => "text/html"60* this.types('json', 'text');61* // => "json"62* this.types('application/json');63* // => "application/json"64*65* // Accept: text/*, application/json66* this.types('image/png');67* this.types('png');68* // => undefined69*70* // Accept: text/*;q=.5, application/json71* this.types(['html', 'json']);72* this.types('html', 'json');73* // => "json"74*75* @param {String|Array} types...76* @return {String|Array|Boolean}77* @public78*/7980Accepts.prototype.type =81Accepts.prototype.types = function (types_) {82var types = types_8384// support flattened arguments85if (types && !Array.isArray(types)) {86types = new Array(arguments.length)87for (var i = 0; i < types.length; i++) {88types[i] = arguments[i]89}90}9192// no types, return all requested types93if (!types || types.length === 0) {94return this.negotiator.mediaTypes()95}9697if (!this.headers.accept) return types[0];98var mimes = types.map(extToMime);99var accepts = this.negotiator.mediaTypes(mimes.filter(validMime));100var first = accepts[0];101if (!first) return false;102return types[mimes.indexOf(first)];103}104105/**106* Return accepted encodings or best fit based on `encodings`.107*108* Given `Accept-Encoding: gzip, deflate`109* an array sorted by quality is returned:110*111* ['gzip', 'deflate']112*113* @param {String|Array} encodings...114* @return {String|Array}115* @public116*/117118Accepts.prototype.encoding =119Accepts.prototype.encodings = function (encodings_) {120var encodings = encodings_121122// support flattened arguments123if (encodings && !Array.isArray(encodings)) {124encodings = new Array(arguments.length)125for (var i = 0; i < encodings.length; i++) {126encodings[i] = arguments[i]127}128}129130// no encodings, return all requested encodings131if (!encodings || encodings.length === 0) {132return this.negotiator.encodings()133}134135return this.negotiator.encodings(encodings)[0] || false136}137138/**139* Return accepted charsets or best fit based on `charsets`.140*141* Given `Accept-Charset: utf-8, iso-8859-1;q=0.2, utf-7;q=0.5`142* an array sorted by quality is returned:143*144* ['utf-8', 'utf-7', 'iso-8859-1']145*146* @param {String|Array} charsets...147* @return {String|Array}148* @public149*/150151Accepts.prototype.charset =152Accepts.prototype.charsets = function (charsets_) {153var charsets = charsets_154155// support flattened arguments156if (charsets && !Array.isArray(charsets)) {157charsets = new Array(arguments.length)158for (var i = 0; i < charsets.length; i++) {159charsets[i] = arguments[i]160}161}162163// no charsets, return all requested charsets164if (!charsets || charsets.length === 0) {165return this.negotiator.charsets()166}167168return this.negotiator.charsets(charsets)[0] || false169}170171/**172* Return accepted languages or best fit based on `langs`.173*174* Given `Accept-Language: en;q=0.8, es, pt`175* an array sorted by quality is returned:176*177* ['es', 'pt', 'en']178*179* @param {String|Array} langs...180* @return {Array|String}181* @public182*/183184Accepts.prototype.lang =185Accepts.prototype.langs =186Accepts.prototype.language =187Accepts.prototype.languages = function (languages_) {188var languages = languages_189190// support flattened arguments191if (languages && !Array.isArray(languages)) {192languages = new Array(arguments.length)193for (var i = 0; i < languages.length; i++) {194languages[i] = arguments[i]195}196}197198// no languages, return all requested languages199if (!languages || languages.length === 0) {200return this.negotiator.languages()201}202203return this.negotiator.languages(languages)[0] || false204}205206/**207* Convert extnames to mime.208*209* @param {String} type210* @return {String}211* @private212*/213214function extToMime(type) {215return type.indexOf('/') === -1216? mime.lookup(type)217: type218}219220/**221* Check if mime is valid.222*223* @param {String} type224* @return {String}225* @private226*/227228function validMime(type) {229return typeof type === 'string';230}231232233