arnaucube
arnaucube/comunicationLeapPublic Self-hosted repository
comunicationLeap/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, '&amp;')
120    .replace(/</g, '&lt;')
121    .replace(/>/g, '&gt;')
122    .replace(/"/g, '&quot;');
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() {}