3 * Copyright(c) 2014-2015 Douglas Christopher Wilson
17 * Module dependencies.
21 var crypto = require('crypto')
22 var Stats = require('fs').Stats
29 var base64PadCharRegExp = /=+$/
30 var toString = Object.prototype.toString
33 * Generate an entity tag.
35 * @param {Buffer|string} entity
40 function entitytag(entity) {
41 if (entity.length === 0) {
43 return '"0-1B2M2Y8AsgTpgAmY7PhCfg"'
46 // compute hash of entity
49 .update(entity, 'utf8')
51 .replace(base64PadCharRegExp, '')
53 // compute length of entity
54 var len = typeof entity === 'string'
55 ? Buffer.byteLength(entity, 'utf8')
58 return '"' + len.toString(16) + '-' + hash + '"'
62 * Create a simple ETag.
64 * @param {string|Buffer|Stats} entity
65 * @param {object} [options]
66 * @param {boolean} [options.weak]
71 function etag(entity, options) {
73 throw new TypeError('argument entity is required')
76 // support fs.Stats object
77 var isStats = isstats(entity)
78 var weak = options && typeof options.weak === 'boolean'
83 if (!isStats && typeof entity !== 'string' && !Buffer.isBuffer(entity)) {
84 throw new TypeError('argument entity must be string, Buffer, or fs.Stats')
87 // generate entity tag
98 * Determine if object is a Stats object.
100 * @param {object} obj
105 function isstats(obj) {
107 if (typeof Stats === 'function' && obj instanceof Stats) {
112 return obj && typeof obj === 'object'
113 && 'ctime' in obj && toString.call(obj.ctime) === '[object Date]'
114 && 'mtime' in obj && toString.call(obj.mtime) === '[object Date]'
115 && 'ino' in obj && typeof obj.ino === 'number'
116 && 'size' in obj && typeof obj.size === 'number'
120 * Generate a tag for a stat.
122 * @param {object} stat
127 function stattag(stat) {
128 var mtime = stat.mtime.getTime().toString(16)
129 var size = stat.size.toString(16)
131 return '"' + size + '-' + mtime + '"'