index.js 5.1 KB

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