comparison node_modules/express/lib/utils.js @ 73:0c3a2942ddee

now using express to server static content
author Rob Canning <rc@kiben.net>
date Sun, 29 Jun 2014 12:11:51 +0000
parents
children
comparison
equal deleted inserted replaced
72:9af4250ff7d5 73:0c3a2942ddee
1 /**
2 * Module dependencies.
3 */
4
5 var mime = require('send').mime;
6 var crc32 = require('buffer-crc32');
7 var crypto = require('crypto');
8 var basename = require('path').basename;
9 var deprecate = require('util').deprecate;
10 var proxyaddr = require('proxy-addr');
11
12 /**
13 * Simple detection of charset parameter in content-type
14 */
15 var charsetRegExp = /;\s*charset\s*=/;
16
17 /**
18 * Deprecate function, like core `util.deprecate`,
19 * but with NODE_ENV and color support.
20 *
21 * @param {Function} fn
22 * @param {String} msg
23 * @return {Function}
24 * @api private
25 */
26
27 exports.deprecate = function(fn, msg){
28 if (process.env.NODE_ENV === 'test') return fn;
29
30 // prepend module name
31 msg = 'express: ' + msg;
32
33 if (process.stderr.isTTY) {
34 // colorize
35 msg = '\x1b[31;1m' + msg + '\x1b[0m';
36 }
37
38 return deprecate(fn, msg);
39 };
40
41 /**
42 * Return strong ETag for `body`.
43 *
44 * @param {String|Buffer} body
45 * @param {String} [encoding]
46 * @return {String}
47 * @api private
48 */
49
50 exports.etag = function etag(body, encoding){
51 if (body.length === 0) {
52 // fast-path empty body
53 return '"1B2M2Y8AsgTpgAmY7PhCfg=="'
54 }
55
56 var hash = crypto
57 .createHash('md5')
58 .update(body, encoding)
59 .digest('base64')
60 return '"' + hash + '"'
61 };
62
63 /**
64 * Return weak ETag for `body`.
65 *
66 * @param {String|Buffer} body
67 * @param {String} [encoding]
68 * @return {String}
69 * @api private
70 */
71
72 exports.wetag = function wetag(body, encoding){
73 if (body.length === 0) {
74 // fast-path empty body
75 return 'W/"0-0"'
76 }
77
78 var buf = Buffer.isBuffer(body)
79 ? body
80 : new Buffer(body, encoding)
81 var len = buf.length
82 return 'W/"' + len.toString(16) + '-' + crc32.unsigned(buf) + '"'
83 };
84
85 /**
86 * Check if `path` looks absolute.
87 *
88 * @param {String} path
89 * @return {Boolean}
90 * @api private
91 */
92
93 exports.isAbsolute = function(path){
94 if ('/' == path[0]) return true;
95 if (':' == path[1] && '\\' == path[2]) return true;
96 if ('\\\\' == path.substring(0, 2)) return true; // Microsoft Azure absolute path
97 };
98
99 /**
100 * Flatten the given `arr`.
101 *
102 * @param {Array} arr
103 * @return {Array}
104 * @api private
105 */
106
107 exports.flatten = function(arr, ret){
108 ret = ret || [];
109 var len = arr.length;
110 for (var i = 0; i < len; ++i) {
111 if (Array.isArray(arr[i])) {
112 exports.flatten(arr[i], ret);
113 } else {
114 ret.push(arr[i]);
115 }
116 }
117 return ret;
118 };
119
120 /**
121 * Normalize the given `type`, for example "html" becomes "text/html".
122 *
123 * @param {String} type
124 * @return {Object}
125 * @api private
126 */
127
128 exports.normalizeType = function(type){
129 return ~type.indexOf('/')
130 ? acceptParams(type)
131 : { value: mime.lookup(type), params: {} };
132 };
133
134 /**
135 * Normalize `types`, for example "html" becomes "text/html".
136 *
137 * @param {Array} types
138 * @return {Array}
139 * @api private
140 */
141
142 exports.normalizeTypes = function(types){
143 var ret = [];
144
145 for (var i = 0; i < types.length; ++i) {
146 ret.push(exports.normalizeType(types[i]));
147 }
148
149 return ret;
150 };
151
152 /**
153 * Generate Content-Disposition header appropriate for the filename.
154 * non-ascii filenames are urlencoded and a filename* parameter is added
155 *
156 * @param {String} filename
157 * @return {String}
158 * @api private
159 */
160
161 exports.contentDisposition = function(filename){
162 var ret = 'attachment';
163 if (filename) {
164 filename = basename(filename);
165 // if filename contains non-ascii characters, add a utf-8 version ala RFC 5987
166 ret = /[^\040-\176]/.test(filename)
167 ? 'attachment; filename="' + encodeURI(filename) + '"; filename*=UTF-8\'\'' + encodeURI(filename)
168 : 'attachment; filename="' + filename + '"';
169 }
170
171 return ret;
172 };
173
174 /**
175 * Parse accept params `str` returning an
176 * object with `.value`, `.quality` and `.params`.
177 * also includes `.originalIndex` for stable sorting
178 *
179 * @param {String} str
180 * @return {Object}
181 * @api private
182 */
183
184 function acceptParams(str, index) {
185 var parts = str.split(/ *; */);
186 var ret = { value: parts[0], quality: 1, params: {}, originalIndex: index };
187
188 for (var i = 1; i < parts.length; ++i) {
189 var pms = parts[i].split(/ *= */);
190 if ('q' == pms[0]) {
191 ret.quality = parseFloat(pms[1]);
192 } else {
193 ret.params[pms[0]] = pms[1];
194 }
195 }
196
197 return ret;
198 }
199
200 /**
201 * Compile "etag" value to function.
202 *
203 * @param {Boolean|String|Function} val
204 * @return {Function}
205 * @api private
206 */
207
208 exports.compileETag = function(val) {
209 var fn;
210
211 if (typeof val === 'function') {
212 return val;
213 }
214
215 switch (val) {
216 case true:
217 fn = exports.wetag;
218 break;
219 case false:
220 break;
221 case 'strong':
222 fn = exports.etag;
223 break;
224 case 'weak':
225 fn = exports.wetag;
226 break;
227 default:
228 throw new TypeError('unknown value for etag function: ' + val);
229 }
230
231 return fn;
232 }
233
234 /**
235 * Compile "proxy trust" value to function.
236 *
237 * @param {Boolean|String|Number|Array|Function} val
238 * @return {Function}
239 * @api private
240 */
241
242 exports.compileTrust = function(val) {
243 if (typeof val === 'function') return val;
244
245 if (val === true) {
246 // Support plain true/false
247 return function(){ return true };
248 }
249
250 if (typeof val === 'number') {
251 // Support trusting hop count
252 return function(a, i){ return i < val };
253 }
254
255 if (typeof val === 'string') {
256 // Support comma-separated values
257 val = val.split(/ *, */);
258 }
259
260 return proxyaddr.compile(val || []);
261 }
262
263 /**
264 * Set the charset in a given Content-Type string.
265 *
266 * @param {String} type
267 * @param {String} charset
268 * @return {String}
269 * @api private
270 */
271
272 exports.setCharset = function(type, charset){
273 if (!type || !charset) return type;
274
275 var exists = charsetRegExp.test(type);
276
277 // removing existing charset
278 if (exists) {
279 var parts = type.split(';');
280
281 for (var i = 1; i < parts.length; i++) {
282 if (charsetRegExp.test(';' + parts[i])) {
283 parts.splice(i, 1);
284 break;
285 }
286 }
287
288 type = parts.join(';');
289 }
290
291 return type + '; charset=' + charset;
292 };