opusdev/vector-similarity-api
1
1/*!2 * vary3 * Copyright(c) 2014-2017 Douglas Christopher Wilson4 * MIT Licensed5 */6 7'use strict'8 9/**10 * Module exports.11 */12 13module.exports = vary14module.exports.append = append15 16/**17 * RegExp to match field-name in RFC 7230 sec 3.218 *19 * field-name = token20 * token = 1*tchar21 * tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*"22 * / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"23 * / DIGIT / ALPHA24 * ; any VCHAR, except delimiters25 */26 27var FIELD_NAME_REGEXP = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/28 29/**30 * Append a field to a vary header.31 *32 * @param {String} header33 * @param {String|Array} field34 * @return {String}35 * @public36 */37 38function append (header, field) {39 if (typeof header !== 'string') {40 throw new TypeError('header argument is required')41 }42 43 if (!field) {44 throw new TypeError('field argument is required')45 }46 47 // get fields array48 var fields = !Array.isArray(field)49 ? parse(String(field))50 : field51 52 // assert on invalid field names53 for (var j = 0; j < fields.length; j++) {54 if (!FIELD_NAME_REGEXP.test(fields[j])) {55 throw new TypeError('field argument contains an invalid header name')56 }57 }58 59 // existing, unspecified vary60 if (header === '*') {61 return header62 }63 64 // enumerate current values65 var val = header66 var vals = parse(header.toLowerCase())67 68 // unspecified vary69 if (fields.indexOf('*') !== -1 || vals.indexOf('*') !== -1) {70 return '*'71 }72 73 for (var i = 0; i < fields.length; i++) {74 var fld = fields[i].toLowerCase()75 76 // append value (case-preserving)77 if (vals.indexOf(fld) === -1) {78 vals.push(fld)79 val = val80 ? val + ', ' + fields[i]81 : fields[i]82 }83 }84 85 return val86}87 88/**89 * Parse a vary header into an array.90 *91 * @param {String} header92 * @return {Array}93 * @private94 */95 96function parse (header) {97 var end = 098 var list = []99 var start = 0100 101 // gather tokens102 for (var i = 0, len = header.length; i < len; i++) {103 switch (header.charCodeAt(i)) {104 case 0x20: /* */105 if (start === end) {106 start = end = i + 1107 }108 break109 case 0x2c: /* , */110 list.push(header.substring(start, end))111 start = end = i + 1112 break113 default:114 end = i + 1115 break116 }117 }118 119 // final token120 list.push(header.substring(start, end))121 122 return list123}124 125/**126 * Mark that a request is varied on a header field.127 *128 * @param {Object} res129 * @param {String|Array} field130 * @public131 */132 133function vary (res, field) {134 if (!res || !res.getHeader || !res.setHeader) {135 // quack quack136 throw new TypeError('res argument is required')137 }138 139 // get existing header140 var val = res.getHeader('Vary') || ''141 var header = Array.isArray(val)142 ? val.join(', ')143 : String(val)144 145 // set new header146 if ((val = append(header, field))) {147 res.setHeader('Vary', val)148 }149}150 