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
|
}
|