second
[josuexyz/.git] / node_modules / etag / index.js
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 }