raspberryGPIOhtmlserver/node_modules/connect/lib/utils.js
node_modules/connect/lib/utils.jsRaw
1
2/*!
3 * Connect - utils
4 * Copyright(c) 2010 Sencha Inc.
5 * Copyright(c) 2011 TJ Holowaychuk
6 * MIT Licensed
7 */
8
9/**
10 * Module dependencies.
11 */
12
13var http = require('http')
14 , crypto = require('crypto')
15 , parse = require('url').parse
16 , signature = require('cookie-signature')
17 , nodeVersion = process.versions.node.split('.');
18
19// pause is broken in node < 0.10
20exports.brokenPause = parseInt(nodeVersion[0], 10) === 0
21 && parseInt(nodeVersion[1], 10) < 10;
22
23/**
24 * Return `true` if the request has a body, otherwise return `false`.
25 *
26 * @param {IncomingMessage} req
27 * @return {Boolean}
28 * @api private
29 */
30
31exports.hasBody = function(req) {
32 return 'transfer-encoding' in req.headers || 'content-length' in req.headers;
33};
34
35/**
36 * Extract the mime type from the given request's
37 * _Content-Type_ header.
38 *
39 * @param {IncomingMessage} req
40 * @return {String}
41 * @api private
42 */
43
44exports.mime = function(req) {
45 var str = req.headers['content-type'] || '';
46 return str.split(';')[0];
47};
48
49/**
50 * Generate an `Error` from the given status `code`
51 * and optional `msg`.
52 *
53 * @param {Number} code
54 * @param {String} msg
55 * @return {Error}
56 * @api private
57 */
58
59exports.error = function(code, msg){
60 var err = new Error(msg || http.STATUS_CODES[code]);
61 err.status = code;
62 return err;
63};
64
65/**
66 * Return md5 hash of the given string and optional encoding,
67 * defaulting to hex.
68 *
69 * utils.md5('wahoo');
70 * // => "e493298061761236c96b02ea6aa8a2ad"
71 *
72 * @param {String} str
73 * @param {String} encoding
74 * @return {String}
75 * @api private
76 */
77
78exports.md5 = function(str, encoding){
79 return crypto
80 .createHash('md5')
81 .update(str)
82 .digest(encoding || 'hex');
83};
84
85/**
86 * Merge object b with object a.
87 *
88 * var a = { foo: 'bar' }
89 * , b = { bar: 'baz' };
90 *
91 * utils.merge(a, b);
92 * // => { foo: 'bar', bar: 'baz' }
93 *
94 * @param {Object} a
95 * @param {Object} b
96 * @return {Object}
97 * @api private
98 */
99
100exports.merge = function(a, b){
101 if (a && b) {
102 for (var key in b) {
103 a[key] = b[key];
104 }
105 }
106 return a;
107};
108
109/**
110 * Escape the given string of `html`.
111 *
112 * @param {String} html
113 * @return {String}
114 * @api private
115 */
116
117exports.escape = function(html){
118 return String(html)
119 .replace(/&(?!\w+;)/g, '&')
120 .replace(/</g, '<')
121 .replace(/>/g, '>')
122 .replace(/"/g, '"');
123};
124
125
126/**
127 * Return a unique identifier with the given `len`.
128 *
129 * utils.uid(10);
130 * // => "FDaS435D2z"
131 *
132 * @param {Number} len
133 * @return {String}
134 * @api private
135 */
136
137exports.uid = function(len) {
138 return crypto.randomBytes(Math.ceil(len * 3 / 4))
139 .toString('base64')
140 .slice(0, len)
141 .replace(/\//g, '-')
142 .replace(/\+/g, '_');
143};
144
145/**
146 * Sign the given `val` with `secret`.
147 *
148 * @param {String} val
149 * @param {String} secret
150 * @return {String}
151 * @api private
152 */
153
154exports.sign = function(val, secret){
155 console.warn('do not use utils.sign(), use https://github.com/visionmedia/node-cookie-signature')
156 return val + '.' + crypto
157 .createHmac('sha256', secret)
158 .update(val)
159 .digest('base64')
160 .replace(/=+$/, '');
161};
162
163/**
164 * Unsign and decode the given `val` with `secret`,
165 * returning `false` if the signature is invalid.
166 *
167 * @param {String} val
168 * @param {String} secret
169 * @return {String|Boolean}
170 * @api private
171 */
172
173exports.unsign = function(val, secret){
174 console.warn('do not use utils.unsign(), use https://github.com/visionmedia/node-cookie-signature')
175 var str = val.slice(0, val.lastIndexOf('.'));
176 return exports.sign(str, secret) == val
177 ? str
178 : false;
179};
180
181/**
182 * Parse signed cookies, returning an object
183 * containing the decoded key/value pairs,
184 * while removing the signed key from `obj`.
185 *
186 * @param {Object} obj
187 * @return {Object}
188 * @api private
189 */
190
191exports.parseSignedCookies = function(obj, secret){
192 var ret = {};
193 Object.keys(obj).forEach(function(key){
194 var val = obj[key];
195 if (0 == val.indexOf('s:')) {
196 val = signature.unsign(val.slice(2), secret);
197 if (val) {
198 ret[key] = val;
199 delete obj[key];
200 }
201 }
202 });
203 return ret;
204};
205
206/**
207 * Parse a signed cookie string, return the decoded value
208 *
209 * @param {String} str signed cookie string
210 * @param {String} secret
211 * @return {String} decoded value
212 * @api private
213 */
214
215exports.parseSignedCookie = function(str, secret){
216 return 0 == str.indexOf('s:')
217 ? signature.unsign(str.slice(2), secret)
218 : str;
219};
220
221/**
222 * Parse JSON cookies.
223 *
224 * @param {Object} obj
225 * @return {Object}
226 * @api private
227 */
228
229exports.parseJSONCookies = function(obj){
230 Object.keys(obj).forEach(function(key){
231 var val = obj[key];
232 var res = exports.parseJSONCookie(val);
233 if (res) obj[key] = res;
234 });
235 return obj;
236};
237
238/**
239 * Parse JSON cookie string
240 *
241 * @param {String} str
242 * @return {Object} Parsed object or null if not json cookie
243 * @api private
244 */
245
246exports.parseJSONCookie = function(str) {
247 if (0 == str.indexOf('j:')) {
248 try {
249 return JSON.parse(str.slice(2));
250 } catch (err) {
251 // no op
252 }
253 }
254};
255
256/**
257 * Pause `data` and `end` events on the given `obj`.
258 * Middleware performing async tasks _should_ utilize
259 * this utility (or similar), to re-emit data once
260 * the async operation has completed, otherwise these
261 * events may be lost. Pause is only required for
262 * node versions less than 10, and is replaced with
263 * noop's otherwise.
264 *
265 * var pause = utils.pause(req);
266 * fs.readFile(path, function(){
267 * next();
268 * pause.resume();
269 * });
270 *
271 * @param {Object} obj
272 * @return {Object}
273 * @api private
274 */
275
276exports.pause = exports.brokenPause
277 ? require('pause')
278 : function () {
279 return {
280 end: noop,
281 resume: noop
282 }
283 }
284
285/**
286 * Strip `Content-*` headers from `res`.
287 *
288 * @param {ServerResponse} res
289 * @api private
290 */
291
292exports.removeContentHeaders = function(res){
293 Object.keys(res._headers).forEach(function(field){
294 if (0 == field.indexOf('content')) {
295 res.removeHeader(field);
296 }
297 });
298};
299
300/**
301 * Check if `req` is a conditional GET request.
302 *
303 * @param {IncomingMessage} req
304 * @return {Boolean}
305 * @api private
306 */
307
308exports.conditionalGET = function(req) {
309 return req.headers['if-modified-since']
310 || req.headers['if-none-match'];
311};
312
313/**
314 * Respond with 401 "Unauthorized".
315 *
316 * @param {ServerResponse} res
317 * @param {String} realm
318 * @api private
319 */
320
321exports.unauthorized = function(res, realm) {
322 res.statusCode = 401;
323 res.setHeader('WWW-Authenticate', 'Basic realm="' + realm + '"');
324 res.end('Unauthorized');
325};
326
327/**
328 * Respond with 304 "Not Modified".
329 *
330 * @param {ServerResponse} res
331 * @param {Object} headers
332 * @api private
333 */
334
335exports.notModified = function(res) {
336 exports.removeContentHeaders(res);
337 res.statusCode = 304;
338 res.end();
339};
340
341/**
342 * Return an ETag in the form of `"<size>-<mtime>"`
343 * from the given `stat`.
344 *
345 * @param {Object} stat
346 * @return {String}
347 * @api private
348 */
349
350exports.etag = function(stat) {
351 return '"' + stat.size + '-' + Number(stat.mtime) + '"';
352};
353
354/**
355 * Parse the given Cache-Control `str`.
356 *
357 * @param {String} str
358 * @return {Object}
359 * @api private
360 */
361
362exports.parseCacheControl = function(str){
363 var directives = str.split(',')
364 , obj = {};
365
366 for(var i = 0, len = directives.length; i < len; i++) {
367 var parts = directives[i].split('=')
368 , key = parts.shift().trim()
369 , val = parseInt(parts.shift(), 10);
370
371 obj[key] = isNaN(val) ? true : val;
372 }
373
374 return obj;
375};
376
377/**
378 * Parse the `req` url with memoization.
379 *
380 * @param {ServerRequest} req
381 * @return {Object}
382 * @api private
383 */
384
385exports.parseUrl = function(req){
386 var parsed = req._parsedUrl;
387 if (parsed && parsed.href == req.url) {
388 return parsed;
389 } else {
390 return req._parsedUrl = parse(req.url);
391 }
392};
393
394/**
395 * Parse byte `size` string.
396 *
397 * @param {String} size
398 * @return {Number}
399 * @api private
400 */
401
402exports.parseBytes = require('bytes');
403
404function noop() {}