Spaces:
Running
Running
/*! | |
* vary | |
* Copyright(c) 2014-2017 Douglas Christopher Wilson | |
* MIT Licensed | |
*/ | |
/** | |
* 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) | |
} | |
} | |