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