You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					150 lines
				
				2.9 KiB
			
		
		
			
		
	
	
					150 lines
				
				2.9 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								/*!
							 | 
						||
| 
								 | 
							
								 * 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)
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 |