3 * Copyright(c) 2014-2016 Douglas Christopher Wilson
17 * Module dependencies.
21 var crypto = require('crypto')
22 var Stats = require('fs').Stats
29 var toString = Object.prototype.toString
32 * Generate an entity tag.
34 * @param {Buffer|string} entity
39 function entitytag (entity) {
40 if (entity.length === 0) {
42 return '"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"'
45 // compute hash of entity
48 .update(entity, 'utf8')
52 // compute length of entity
53 var len = typeof entity === 'string'
54 ? Buffer.byteLength(entity, 'utf8')
57 return '"' + len.toString(16) + '-' + hash + '"'
61 * Create a simple ETag.
63 * @param {string|Buffer|Stats} entity
64 * @param {object} [options]
65 * @param {boolean} [options.weak]
70 function etag (entity, options) {
72 throw new TypeError('argument entity is required')
75 // support fs.Stats object
76 var isStats = isstats(entity)
77 var weak = options && typeof options.weak === 'boolean'
82 if (!isStats && typeof entity !== 'string' && !Buffer.isBuffer(entity)) {
83 throw new TypeError('argument entity must be string, Buffer, or fs.Stats')
86 // generate entity tag
97 * Determine if object is a Stats object.
104 function isstats (obj) {
106 if (typeof Stats === 'function' && obj instanceof Stats) {
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'
119 * Generate a tag for a stat.
121 * @param {object} stat
126 function stattag (stat) {
127 var mtime = stat.mtime.getTime().toString(16)
128 var size = stat.size.toString(16)
130 return '"' + size + '-' + mtime + '"'