Projekt

Obecné

Profil

Stáhnout (2.86 KB) Statistiky
| Větev: | Revize:
1
/*!
2
 * vary
3
 * Copyright(c) 2014-2017 Douglas Christopher Wilson
4
 * MIT Licensed
5
 */
6

    
7
'use strict'
8

    
9
/**
10
 * Module exports.
11
 */
12

    
13
module.exports = vary
14
module.exports.append = append
15

    
16
/**
17
 * RegExp to match field-name in RFC 7230 sec 3.2
18
 *
19
 * field-name    = token
20
 * token         = 1*tchar
21
 * tchar         = "!" / "#" / "$" / "%" / "&" / "'" / "*"
22
 *               / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
23
 *               / DIGIT / ALPHA
24
 *               ; any VCHAR, except delimiters
25
 */
26

    
27
var FIELD_NAME_REGEXP = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/
28

    
29
/**
30
 * Append a field to a vary header.
31
 *
32
 * @param {String} header
33
 * @param {String|Array} field
34
 * @return {String}
35
 * @public
36
 */
37

    
38
function 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 array
48
  var fields = !Array.isArray(field)
49
    ? parse(String(field))
50
    : field
51

    
52
  // assert on invalid field names
53
  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 vary
60
  if (header === '*') {
61
    return header
62
  }
63

    
64
  // enumerate current values
65
  var val = header
66
  var vals = parse(header.toLowerCase())
67

    
68
  // unspecified vary
69
  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 = val
80
        ? val + ', ' + fields[i]
81
        : fields[i]
82
    }
83
  }
84

    
85
  return val
86
}
87

    
88
/**
89
 * Parse a vary header into an array.
90
 *
91
 * @param {String} header
92
 * @return {Array}
93
 * @private
94
 */
95

    
96
function parse (header) {
97
  var end = 0
98
  var list = []
99
  var start = 0
100

    
101
  // gather tokens
102
  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 + 1
107
        }
108
        break
109
      case 0x2c: /* , */
110
        list.push(header.substring(start, end))
111
        start = end = i + 1
112
        break
113
      default:
114
        end = i + 1
115
        break
116
    }
117
  }
118

    
119
  // final token
120
  list.push(header.substring(start, end))
121

    
122
  return list
123
}
124

    
125
/**
126
 * Mark that a request is varied on a header field.
127
 *
128
 * @param {Object} res
129
 * @param {String|Array} field
130
 * @public
131
 */
132

    
133
function vary (res, field) {
134
  if (!res || !res.getHeader || !res.setHeader) {
135
    // quack quack
136
    throw new TypeError('res argument is required')
137
  }
138

    
139
  // get existing header
140
  var val = res.getHeader('Vary') || ''
141
  var header = Array.isArray(val)
142
    ? val.join(', ')
143
    : String(val)
144

    
145
  // set new header
146
  if ((val = append(header, field))) {
147
    res.setHeader('Vary', val)
148
  }
149
}
(4-4/5)