UNPKG

5.61 kBJavaScriptView Raw
1/*!
2 * express
3 * Copyright(c) 2009-2013 TJ Holowaychuk
4 * Copyright(c) 2014-2015 Douglas Christopher Wilson
5 * MIT Licensed
6 */
7
8/**
9 * Module dependencies.
10 * @api private
11 */
12
13var contentDisposition = require('content-disposition')
14var contentType = require('content-type')
15var deprecate = require('depd')('express')
16var mime = require('send').mime
17var basename = require('path').basename
18var etag = require('etag')
19var proxyaddr = require('proxy-addr')
20var qs = require('qs')
21var querystring = require('querystring')
22
23/**
24 * Return strong ETag for `body`.
25 *
26 * @param {String|Buffer} body
27 * @param {String} [encoding]
28 * @return {String}
29 * @api private
30 */
31
32exports.etag = function(body, encoding) {
33 var buf = !Buffer.isBuffer(body) ? new Buffer(body, encoding) : body
34
35 return etag(buf, { weak: false })
36}
37
38/**
39 * Return weak ETag for `body`.
40 *
41 * @param {String|Buffer} body
42 * @param {String} [encoding]
43 * @return {String}
44 * @api private
45 */
46
47exports.wetag = function wetag(body, encoding) {
48 var buf = !Buffer.isBuffer(body) ? new Buffer(body, encoding) : body
49
50 return etag(buf, { weak: true })
51}
52
53/**
54 * Check if `path` looks absolute.
55 *
56 * @param {String} path
57 * @return {Boolean}
58 * @api private
59 */
60
61exports.isAbsolute = function(path) {
62 if ('/' == path[0]) return true
63 if (':' == path[1] && '\\' == path[2]) return true
64 if ('\\\\' == path.substring(0, 2)) return true // Microsoft Azure absolute path
65}
66
67/**
68 * Flatten the given `arr`.
69 *
70 * @param {Array} arr
71 * @return {Array}
72 * @api private
73 */
74
75exports.flatten = function(arr, ret) {
76 ret = ret || []
77 var len = arr.length
78 for (var i = 0; i < len; ++i) {
79 if (Array.isArray(arr[i])) {
80 exports.flatten(arr[i], ret)
81 } else {
82 ret.push(arr[i])
83 }
84 }
85 return ret
86}
87
88/**
89 * Normalize the given `type`, for example "html" becomes "text/html".
90 *
91 * @param {String} type
92 * @return {Object}
93 * @api private
94 */
95
96exports.normalizeType = function(type) {
97 return ~type.indexOf('/')
98 ? acceptParams(type)
99 : { value: mime.lookup(type), params: {} }
100}
101
102/**
103 * Normalize `types`, for example "html" becomes "text/html".
104 *
105 * @param {Array} types
106 * @return {Array}
107 * @api private
108 */
109
110exports.normalizeTypes = function(types) {
111 var ret = []
112
113 for (var i = 0; i < types.length; ++i) {
114 ret.push(exports.normalizeType(types[i]))
115 }
116
117 return ret
118}
119
120/**
121 * Generate Content-Disposition header appropriate for the filename.
122 * non-ascii filenames are urlencoded and a filename* parameter is added
123 *
124 * @param {String} filename
125 * @return {String}
126 * @api private
127 */
128
129exports.contentDisposition = deprecate.function(
130 contentDisposition,
131 'utils.contentDisposition: use content-disposition npm module instead'
132)
133
134/**
135 * Parse accept params `str` returning an
136 * object with `.value`, `.quality` and `.params`.
137 * also includes `.originalIndex` for stable sorting
138 *
139 * @param {String} str
140 * @return {Object}
141 * @api private
142 */
143
144function acceptParams(str, index) {
145 var parts = str.split(/ *; */)
146 var ret = { value: parts[0], quality: 1, params: {}, originalIndex: index }
147
148 for (var i = 1; i < parts.length; ++i) {
149 var pms = parts[i].split(/ *= */)
150 if ('q' == pms[0]) {
151 ret.quality = parseFloat(pms[1])
152 } else {
153 ret.params[pms[0]] = pms[1]
154 }
155 }
156
157 return ret
158}
159
160/**
161 * Compile "etag" value to function.
162 *
163 * @param {Boolean|String|Function} val
164 * @return {Function}
165 * @api private
166 */
167
168exports.compileETag = function(val) {
169 var fn
170
171 if (typeof val === 'function') {
172 return val
173 }
174
175 switch (val) {
176 case true:
177 fn = exports.wetag
178 break
179 case false:
180 break
181 case 'strong':
182 fn = exports.etag
183 break
184 case 'weak':
185 fn = exports.wetag
186 break
187 default:
188 throw new TypeError('unknown value for etag function: ' + val)
189 }
190
191 return fn
192}
193
194/**
195 * Compile "query parser" value to function.
196 *
197 * @param {String|Function} val
198 * @return {Function}
199 * @api private
200 */
201
202exports.compileQueryParser = function compileQueryParser(val) {
203 var fn
204
205 if (typeof val === 'function') {
206 return val
207 }
208
209 switch (val) {
210 case true:
211 fn = querystring.parse
212 break
213 case false:
214 fn = newObject
215 break
216 case 'extended':
217 fn = qs.parse
218 break
219 case 'simple':
220 fn = querystring.parse
221 break
222 default:
223 throw new TypeError('unknown value for query parser function: ' + val)
224 }
225
226 return fn
227}
228
229/**
230 * Compile "proxy trust" value to function.
231 *
232 * @param {Boolean|String|Number|Array|Function} val
233 * @return {Function}
234 * @api private
235 */
236
237exports.compileTrust = function(val) {
238 if (typeof val === 'function') return val
239
240 if (val === true) {
241 // Support plain true/false
242 return function() {
243 return true
244 }
245 }
246
247 if (typeof val === 'number') {
248 // Support trusting hop count
249 return function(a, i) {
250 return i < val
251 }
252 }
253
254 if (typeof val === 'string') {
255 // Support comma-separated values
256 val = val.split(/ *, */)
257 }
258
259 return proxyaddr.compile(val || [])
260}
261
262/**
263 * Set the charset in a given Content-Type string.
264 *
265 * @param {String} type
266 * @param {String} charset
267 * @return {String}
268 * @api private
269 */
270
271exports.setCharset = function setCharset(type, charset) {
272 if (!type || !charset) {
273 return type
274 }
275
276 // parse type
277 var parsed = contentType.parse(type)
278
279 // set charset
280 parsed.parameters.charset = charset
281
282 // format type
283 return contentType.format(parsed)
284}
285
286/**
287 * Return new empty object.
288 *
289 * @return {Object}
290 * @api private
291 */
292
293function newObject() {
294 return {}
295}