| /*! | 
|  * vary | 
|  * Copyright(c) 2014-2017 Douglas Christopher Wilson | 
|  * MIT Licensed | 
|  */ | 
|   | 
| 'use strict' | 
|   | 
| /** | 
|  * Module exports. | 
|  */ | 
|   | 
| module.exports = vary | 
| module.exports.append = append | 
|   | 
| /** | 
|  * RegExp to match field-name in RFC 7230 sec 3.2 | 
|  * | 
|  * field-name    = token | 
|  * token         = 1*tchar | 
|  * tchar         = "!" / "#" / "$" / "%" / "&" / "'" / "*" | 
|  *               / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" | 
|  *               / DIGIT / ALPHA | 
|  *               ; any VCHAR, except delimiters | 
|  */ | 
|   | 
| var FIELD_NAME_REGEXP = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/ | 
|   | 
| /** | 
|  * Append a field to a vary header. | 
|  * | 
|  * @param {String} header | 
|  * @param {String|Array} field | 
|  * @return {String} | 
|  * @public | 
|  */ | 
|   | 
| function append (header, field) { | 
|   if (typeof header !== 'string') { | 
|     throw new TypeError('header argument is required') | 
|   } | 
|   | 
|   if (!field) { | 
|     throw new TypeError('field argument is required') | 
|   } | 
|   | 
|   // get fields array | 
|   var fields = !Array.isArray(field) | 
|     ? parse(String(field)) | 
|     : field | 
|   | 
|   // assert on invalid field names | 
|   for (var j = 0; j < fields.length; j++) { | 
|     if (!FIELD_NAME_REGEXP.test(fields[j])) { | 
|       throw new TypeError('field argument contains an invalid header name') | 
|     } | 
|   } | 
|   | 
|   // existing, unspecified vary | 
|   if (header === '*') { | 
|     return header | 
|   } | 
|   | 
|   // enumerate current values | 
|   var val = header | 
|   var vals = parse(header.toLowerCase()) | 
|   | 
|   // unspecified vary | 
|   if (fields.indexOf('*') !== -1 || vals.indexOf('*') !== -1) { | 
|     return '*' | 
|   } | 
|   | 
|   for (var i = 0; i < fields.length; i++) { | 
|     var fld = fields[i].toLowerCase() | 
|   | 
|     // append value (case-preserving) | 
|     if (vals.indexOf(fld) === -1) { | 
|       vals.push(fld) | 
|       val = val | 
|         ? val + ', ' + fields[i] | 
|         : fields[i] | 
|     } | 
|   } | 
|   | 
|   return val | 
| } | 
|   | 
| /** | 
|  * Parse a vary header into an array. | 
|  * | 
|  * @param {String} header | 
|  * @return {Array} | 
|  * @private | 
|  */ | 
|   | 
| function parse (header) { | 
|   var end = 0 | 
|   var list = [] | 
|   var start = 0 | 
|   | 
|   // gather tokens | 
|   for (var i = 0, len = header.length; i < len; i++) { | 
|     switch (header.charCodeAt(i)) { | 
|       case 0x20: /*   */ | 
|         if (start === end) { | 
|           start = end = i + 1 | 
|         } | 
|         break | 
|       case 0x2c: /* , */ | 
|         list.push(header.substring(start, end)) | 
|         start = end = i + 1 | 
|         break | 
|       default: | 
|         end = i + 1 | 
|         break | 
|     } | 
|   } | 
|   | 
|   // final token | 
|   list.push(header.substring(start, end)) | 
|   | 
|   return list | 
| } | 
|   | 
| /** | 
|  * Mark that a request is varied on a header field. | 
|  * | 
|  * @param {Object} res | 
|  * @param {String|Array} field | 
|  * @public | 
|  */ | 
|   | 
| function vary (res, field) { | 
|   if (!res || !res.getHeader || !res.setHeader) { | 
|     // quack quack | 
|     throw new TypeError('res argument is required') | 
|   } | 
|   | 
|   // get existing header | 
|   var val = res.getHeader('Vary') || '' | 
|   var header = Array.isArray(val) | 
|     ? val.join(', ') | 
|     : String(val) | 
|   | 
|   // set new header | 
|   if ((val = append(header, field))) { | 
|     res.setHeader('Vary', val) | 
|   } | 
| } |