index.js (5252B)
1 /*! 2 * accepts 3 * Copyright(c) 2014 Jonathan Ong 4 * Copyright(c) 2015 Douglas Christopher Wilson 5 * MIT Licensed 6 */ 7 8 'use strict' 9 10 /** 11 * Module dependencies. 12 * @private 13 */ 14 15 var Negotiator = require('negotiator') 16 var mime = require('mime-types') 17 18 /** 19 * Module exports. 20 * @public 21 */ 22 23 module.exports = Accepts 24 25 /** 26 * Create a new Accepts object for the given req. 27 * 28 * @param {object} req 29 * @public 30 */ 31 32 function Accepts (req) { 33 if (!(this instanceof Accepts)) { 34 return new Accepts(req) 35 } 36 37 this.headers = req.headers 38 this.negotiator = new Negotiator(req) 39 } 40 41 /** 42 * Check if the given `type(s)` is acceptable, returning 43 * the best match when true, otherwise `undefined`, in which 44 * case you should respond with 406 "Not Acceptable". 45 * 46 * The `type` value may be a single mime type string 47 * such as "application/json", the extension name 48 * such as "json" or an array `["json", "html", "text/plain"]`. When a list 49 * or array is given the _best_ match, if any is returned. 50 * 51 * Examples: 52 * 53 * // Accept: text/html 54 * this.types('html'); 55 * // => "html" 56 * 57 * // Accept: text/*, application/json 58 * this.types('html'); 59 * // => "html" 60 * this.types('text/html'); 61 * // => "text/html" 62 * this.types('json', 'text'); 63 * // => "json" 64 * this.types('application/json'); 65 * // => "application/json" 66 * 67 * // Accept: text/*, application/json 68 * this.types('image/png'); 69 * this.types('png'); 70 * // => undefined 71 * 72 * // Accept: text/*;q=.5, application/json 73 * this.types(['html', 'json']); 74 * this.types('html', 'json'); 75 * // => "json" 76 * 77 * @param {String|Array} types... 78 * @return {String|Array|Boolean} 79 * @public 80 */ 81 82 Accepts.prototype.type = 83 Accepts.prototype.types = function (types_) { 84 var types = types_ 85 86 // support flattened arguments 87 if (types && !Array.isArray(types)) { 88 types = new Array(arguments.length) 89 for (var i = 0; i < types.length; i++) { 90 types[i] = arguments[i] 91 } 92 } 93 94 // no types, return all requested types 95 if (!types || types.length === 0) { 96 return this.negotiator.mediaTypes() 97 } 98 99 // no accept header, return first given type 100 if (!this.headers.accept) { 101 return types[0] 102 } 103 104 var mimes = types.map(extToMime) 105 var accepts = this.negotiator.mediaTypes(mimes.filter(validMime)) 106 var first = accepts[0] 107 108 return first 109 ? types[mimes.indexOf(first)] 110 : false 111 } 112 113 /** 114 * Return accepted encodings or best fit based on `encodings`. 115 * 116 * Given `Accept-Encoding: gzip, deflate` 117 * an array sorted by quality is returned: 118 * 119 * ['gzip', 'deflate'] 120 * 121 * @param {String|Array} encodings... 122 * @return {String|Array} 123 * @public 124 */ 125 126 Accepts.prototype.encoding = 127 Accepts.prototype.encodings = function (encodings_) { 128 var encodings = encodings_ 129 130 // support flattened arguments 131 if (encodings && !Array.isArray(encodings)) { 132 encodings = new Array(arguments.length) 133 for (var i = 0; i < encodings.length; i++) { 134 encodings[i] = arguments[i] 135 } 136 } 137 138 // no encodings, return all requested encodings 139 if (!encodings || encodings.length === 0) { 140 return this.negotiator.encodings() 141 } 142 143 return this.negotiator.encodings(encodings)[0] || false 144 } 145 146 /** 147 * Return accepted charsets or best fit based on `charsets`. 148 * 149 * Given `Accept-Charset: utf-8, iso-8859-1;q=0.2, utf-7;q=0.5` 150 * an array sorted by quality is returned: 151 * 152 * ['utf-8', 'utf-7', 'iso-8859-1'] 153 * 154 * @param {String|Array} charsets... 155 * @return {String|Array} 156 * @public 157 */ 158 159 Accepts.prototype.charset = 160 Accepts.prototype.charsets = function (charsets_) { 161 var charsets = charsets_ 162 163 // support flattened arguments 164 if (charsets && !Array.isArray(charsets)) { 165 charsets = new Array(arguments.length) 166 for (var i = 0; i < charsets.length; i++) { 167 charsets[i] = arguments[i] 168 } 169 } 170 171 // no charsets, return all requested charsets 172 if (!charsets || charsets.length === 0) { 173 return this.negotiator.charsets() 174 } 175 176 return this.negotiator.charsets(charsets)[0] || false 177 } 178 179 /** 180 * Return accepted languages or best fit based on `langs`. 181 * 182 * Given `Accept-Language: en;q=0.8, es, pt` 183 * an array sorted by quality is returned: 184 * 185 * ['es', 'pt', 'en'] 186 * 187 * @param {String|Array} langs... 188 * @return {Array|String} 189 * @public 190 */ 191 192 Accepts.prototype.lang = 193 Accepts.prototype.langs = 194 Accepts.prototype.language = 195 Accepts.prototype.languages = function (languages_) { 196 var languages = languages_ 197 198 // support flattened arguments 199 if (languages && !Array.isArray(languages)) { 200 languages = new Array(arguments.length) 201 for (var i = 0; i < languages.length; i++) { 202 languages[i] = arguments[i] 203 } 204 } 205 206 // no languages, return all requested languages 207 if (!languages || languages.length === 0) { 208 return this.negotiator.languages() 209 } 210 211 return this.negotiator.languages(languages)[0] || false 212 } 213 214 /** 215 * Convert extnames to mime. 216 * 217 * @param {String} type 218 * @return {String} 219 * @private 220 */ 221 222 function extToMime (type) { 223 return type.indexOf('/') === -1 224 ? mime.lookup(type) 225 : type 226 } 227 228 /** 229 * Check if mime is valid. 230 * 231 * @param {String} type 232 * @return {String} 233 * @private 234 */ 235 236 function validMime (type) { 237 return typeof type === 'string' 238 }