3 * Copyright(c) 2014-2015 Douglas Christopher Wilson
13 module.exports = vary;
14 module.exports.append = append;
17 * RegExp to match field-name in RFC 7230 sec 3.2
21 * tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*"
22 * / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
24 * ; any VCHAR, except delimiters
27 var fieldNameRegExp = /^[!#$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+$/
30 * Append a field to a vary header.
32 * @param {String} header
33 * @param {String|Array} field
38 function append(header, field) {
39 if (typeof header !== 'string') {
40 throw new TypeError('header argument is required');
44 throw new TypeError('field argument is required');
48 var fields = !Array.isArray(field)
49 ? parse(String(field))
52 // assert on invalid field names
53 for (var i = 0; i < fields.length; i++) {
54 if (!fieldNameRegExp.test(fields[i])) {
55 throw new TypeError('field argument contains an invalid header name');
59 // existing, unspecified vary
64 // enumerate current values
66 var vals = parse(header.toLowerCase());
69 if (fields.indexOf('*') !== -1 || vals.indexOf('*') !== -1) {
73 for (var i = 0; i < fields.length; i++) {
74 var fld = fields[i].toLowerCase();
76 // append value (case-preserving)
77 if (vals.indexOf(fld) === -1) {
80 ? val + ', ' + fields[i]
89 * Parse a vary header into an array.
91 * @param {String} header
96 function parse(header) {
97 return header.trim().split(/ *, */);
101 * Mark that a request is varied on a header field.
103 * @param {Object} res
104 * @param {String|Array} field
108 function vary(res, field) {
109 if (!res || !res.getHeader || !res.setHeader) {
111 throw new TypeError('res argument is required');
114 // get existing header
115 var val = res.getHeader('Vary') || ''
116 var header = Array.isArray(val)
121 if ((val = append(header, field))) {
122 res.setHeader('Vary', val);