You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
131 lines
2.4 KiB
131 lines
2.4 KiB
/*! |
|
* etag |
|
* Copyright(c) 2014-2016 Douglas Christopher Wilson |
|
* MIT Licensed |
|
*/ |
|
|
|
'use strict' |
|
|
|
/** |
|
* Module exports. |
|
* @public |
|
*/ |
|
|
|
module.exports = etag |
|
|
|
/** |
|
* Module dependencies. |
|
* @private |
|
*/ |
|
|
|
var crypto = require('crypto') |
|
var Stats = require('fs').Stats |
|
|
|
/** |
|
* Module variables. |
|
* @private |
|
*/ |
|
|
|
var toString = Object.prototype.toString |
|
|
|
/** |
|
* Generate an entity tag. |
|
* |
|
* @param {Buffer|string} entity |
|
* @return {string} |
|
* @private |
|
*/ |
|
|
|
function entitytag (entity) { |
|
if (entity.length === 0) { |
|
// fast-path empty |
|
return '"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"' |
|
} |
|
|
|
// compute hash of entity |
|
var hash = crypto |
|
.createHash('sha1') |
|
.update(entity, 'utf8') |
|
.digest('base64') |
|
.substring(0, 27) |
|
|
|
// compute length of entity |
|
var len = typeof entity === 'string' |
|
? Buffer.byteLength(entity, 'utf8') |
|
: entity.length |
|
|
|
return '"' + len.toString(16) + '-' + hash + '"' |
|
} |
|
|
|
/** |
|
* Create a simple ETag. |
|
* |
|
* @param {string|Buffer|Stats} entity |
|
* @param {object} [options] |
|
* @param {boolean} [options.weak] |
|
* @return {String} |
|
* @public |
|
*/ |
|
|
|
function etag (entity, options) { |
|
if (entity == null) { |
|
throw new TypeError('argument entity is required') |
|
} |
|
|
|
// support fs.Stats object |
|
var isStats = isstats(entity) |
|
var weak = options && typeof options.weak === 'boolean' |
|
? options.weak |
|
: isStats |
|
|
|
// validate argument |
|
if (!isStats && typeof entity !== 'string' && !Buffer.isBuffer(entity)) { |
|
throw new TypeError('argument entity must be string, Buffer, or fs.Stats') |
|
} |
|
|
|
// generate entity tag |
|
var tag = isStats |
|
? stattag(entity) |
|
: entitytag(entity) |
|
|
|
return weak |
|
? 'W/' + tag |
|
: tag |
|
} |
|
|
|
/** |
|
* Determine if object is a Stats object. |
|
* |
|
* @param {object} obj |
|
* @return {boolean} |
|
* @api private |
|
*/ |
|
|
|
function isstats (obj) { |
|
// genuine fs.Stats |
|
if (typeof Stats === 'function' && obj instanceof Stats) { |
|
return true |
|
} |
|
|
|
// quack quack |
|
return obj && typeof obj === 'object' && |
|
'ctime' in obj && toString.call(obj.ctime) === '[object Date]' && |
|
'mtime' in obj && toString.call(obj.mtime) === '[object Date]' && |
|
'ino' in obj && typeof obj.ino === 'number' && |
|
'size' in obj && typeof obj.size === 'number' |
|
} |
|
|
|
/** |
|
* Generate a tag for a stat. |
|
* |
|
* @param {object} stat |
|
* @return {string} |
|
* @private |
|
*/ |
|
|
|
function stattag (stat) { |
|
var mtime = stat.mtime.getTime().toString(16) |
|
var size = stat.size.toString(16) |
|
|
|
return '"' + size + '-' + mtime + '"' |
|
}
|
|
|