Permalink
Cannot retrieve contributors at this time
149 lines (124 sloc)
2.86 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /*! | |
| * 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) | |
| } | |
| } |