twitst4tz

twitter statistics web application
Log | Files | Refs | README | LICENSE

utils.js (5972B)


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