twitst4tz

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

index.js (2479B)


      1 /*!
      2  * etag
      3  * Copyright(c) 2014-2016 Douglas Christopher Wilson
      4  * MIT Licensed
      5  */
      6 
      7 'use strict'
      8 
      9 /**
     10  * Module exports.
     11  * @public
     12  */
     13 
     14 module.exports = etag
     15 
     16 /**
     17  * Module dependencies.
     18  * @private
     19  */
     20 
     21 var crypto = require('crypto')
     22 var Stats = require('fs').Stats
     23 
     24 /**
     25  * Module variables.
     26  * @private
     27  */
     28 
     29 var toString = Object.prototype.toString
     30 
     31 /**
     32  * Generate an entity tag.
     33  *
     34  * @param {Buffer|string} entity
     35  * @return {string}
     36  * @private
     37  */
     38 
     39 function entitytag (entity) {
     40   if (entity.length === 0) {
     41     // fast-path empty
     42     return '"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"'
     43   }
     44 
     45   // compute hash of entity
     46   var hash = crypto
     47     .createHash('sha1')
     48     .update(entity, 'utf8')
     49     .digest('base64')
     50     .substring(0, 27)
     51 
     52   // compute length of entity
     53   var len = typeof entity === 'string'
     54     ? Buffer.byteLength(entity, 'utf8')
     55     : entity.length
     56 
     57   return '"' + len.toString(16) + '-' + hash + '"'
     58 }
     59 
     60 /**
     61  * Create a simple ETag.
     62  *
     63  * @param {string|Buffer|Stats} entity
     64  * @param {object} [options]
     65  * @param {boolean} [options.weak]
     66  * @return {String}
     67  * @public
     68  */
     69 
     70 function etag (entity, options) {
     71   if (entity == null) {
     72     throw new TypeError('argument entity is required')
     73   }
     74 
     75   // support fs.Stats object
     76   var isStats = isstats(entity)
     77   var weak = options && typeof options.weak === 'boolean'
     78     ? options.weak
     79     : isStats
     80 
     81   // validate argument
     82   if (!isStats && typeof entity !== 'string' && !Buffer.isBuffer(entity)) {
     83     throw new TypeError('argument entity must be string, Buffer, or fs.Stats')
     84   }
     85 
     86   // generate entity tag
     87   var tag = isStats
     88     ? stattag(entity)
     89     : entitytag(entity)
     90 
     91   return weak
     92     ? 'W/' + tag
     93     : tag
     94 }
     95 
     96 /**
     97  * Determine if object is a Stats object.
     98  *
     99  * @param {object} obj
    100  * @return {boolean}
    101  * @api private
    102  */
    103 
    104 function isstats (obj) {
    105   // genuine fs.Stats
    106   if (typeof Stats === 'function' && obj instanceof Stats) {
    107     return true
    108   }
    109 
    110   // quack quack
    111   return obj && typeof obj === 'object' &&
    112     'ctime' in obj && toString.call(obj.ctime) === '[object Date]' &&
    113     'mtime' in obj && toString.call(obj.mtime) === '[object Date]' &&
    114     'ino' in obj && typeof obj.ino === 'number' &&
    115     'size' in obj && typeof obj.size === 'number'
    116 }
    117 
    118 /**
    119  * Generate a tag for a stat.
    120  *
    121  * @param {object} stat
    122  * @return {string}
    123  * @private
    124  */
    125 
    126 function stattag (stat) {
    127   var mtime = stat.mtime.getTime().toString(16)
    128   var size = stat.size.toString(16)
    129 
    130   return '"' + size + '-' + mtime + '"'
    131 }