3 * Copyright(c) 2014 Douglas Christopher Wilson
14 * Module dependencies.
17 var crc = require('crc').crc32
18 var crypto = require('crypto')
19 var Stats = require('fs').Stats
25 var crc32threshold = 1000 // 1KB
26 var NULL = new Buffer([0])
27 var toString = Object.prototype.toString
30 * Create a simple ETag.
32 * @param {string|Buffer|Stats} entity
33 * @param {object} [options]
34 * @param {boolean} [options.weak]
39 function etag(entity, options) {
41 throw new TypeError('argument entity is required')
44 var isStats = isstats(entity)
45 var weak = options && typeof options.weak === 'boolean'
49 // support fs.Stats object
51 return stattag(entity, weak)
54 if (typeof entity !== 'string' && !Buffer.isBuffer(entity)) {
55 throw new TypeError('argument entity must be string, Buffer, or fs.Stats')
68 * Determine if object is a Stats object.
75 function isstats(obj) {
77 if (obj === null || typeof obj !== 'object') {
82 if (obj instanceof Stats) {
87 return 'atime' in obj && toString.call(obj.atime) === '[object Date]'
88 && 'ctime' in obj && toString.call(obj.ctime) === '[object Date]'
89 && 'mtime' in obj && toString.call(obj.mtime) === '[object Date]'
90 && 'ino' in obj && typeof obj.ino === 'number'
91 && 'size' in obj && typeof obj.size === 'number'
95 * Generate a tag for a stat.
97 * @param {Buffer} entity
102 function stattag(stat, weak) {
103 var mtime = stat.mtime.toISOString()
104 var size = stat.size.toString(16)
107 return 'W/"' + size + '-' + crc(mtime) + '"'
112 .update('file', 'utf8')
114 .update(size, 'utf8')
116 .update(mtime, 'utf8')
119 return '"' + hash + '"'
123 * Generate a strong hash.
125 * @param {Buffer} entity
130 function stronghash(entity) {
131 if (entity.length === 0) {
133 return '1B2M2Y8AsgTpgAmY7PhCfg=='
138 .update(entity, 'utf8')
143 * Generate a weak hash.
145 * @param {Buffer} entity
150 function weakhash(entity) {
151 if (entity.length === 0) {
156 var len = typeof entity === 'string'
157 ? Buffer.byteLength(entity, 'utf8')
160 if (len <= crc32threshold) {
161 // crc32 plus length when it's fast
162 // crc(str) only accepts utf-8 encoding
163 return len.toString(16) + '-' + crc(entity).toString(16)
166 // use md4 for long strings
169 .update(entity, 'utf8')