arnaucube
arnaucube/socketioMEANseedPublic Self-hosted repository
socketioMEANseed/server/node_modules/media-typer/index.js
server/node_modules/media-typer/index.jsRaw
  1/*!
  2 * media-typer
  3 * Copyright(c) 2014 Douglas Christopher Wilson
  4 * MIT Licensed
  5 */
  6
  7/**
  8 * RegExp to match *( ";" parameter ) in RFC 2616 sec 3.7
  9 *
 10 * parameter     = token "=" ( token | quoted-string )
 11 * token         = 1*<any CHAR except CTLs or separators>
 12 * separators    = "(" | ")" | "<" | ">" | "@"
 13 *               | "," | ";" | ":" | "\" | <">
 14 *               | "/" | "[" | "]" | "?" | "="
 15 *               | "{" | "}" | SP | HT
 16 * quoted-string = ( <"> *(qdtext | quoted-pair ) <"> )
 17 * qdtext        = <any TEXT except <">>
 18 * quoted-pair   = "\" CHAR
 19 * CHAR          = <any US-ASCII character (octets 0 - 127)>
 20 * TEXT          = <any OCTET except CTLs, but including LWS>
 21 * LWS           = [CRLF] 1*( SP | HT )
 22 * CRLF          = CR LF
 23 * CR            = <US-ASCII CR, carriage return (13)>
 24 * LF            = <US-ASCII LF, linefeed (10)>
 25 * SP            = <US-ASCII SP, space (32)>
 26 * SHT           = <US-ASCII HT, horizontal-tab (9)>
 27 * CTL           = <any US-ASCII control character (octets 0 - 31) and DEL (127)>
 28 * OCTET         = <any 8-bit sequence of data>
 29 */
 30var paramRegExp = /; *([!#$%&'\*\+\-\.0-9A-Z\^_`a-z\|~]+) *= *("(?:[ !\u0023-\u005b\u005d-\u007e\u0080-\u00ff]|\\[\u0020-\u007e])*"|[!#$%&'\*\+\-\.0-9A-Z\^_`a-z\|~]+) */g;
 31var textRegExp = /^[\u0020-\u007e\u0080-\u00ff]+$/
 32var tokenRegExp = /^[!#$%&'\*\+\-\.0-9A-Z\^_`a-z\|~]+$/
 33
 34/**
 35 * RegExp to match quoted-pair in RFC 2616
 36 *
 37 * quoted-pair = "\" CHAR
 38 * CHAR        = <any US-ASCII character (octets 0 - 127)>
 39 */
 40var qescRegExp = /\\([\u0000-\u007f])/g;
 41
 42/**
 43 * RegExp to match chars that must be quoted-pair in RFC 2616
 44 */
 45var quoteRegExp = /([\\"])/g;
 46
 47/**
 48 * RegExp to match type in RFC 6838
 49 *
 50 * type-name = restricted-name
 51 * subtype-name = restricted-name
 52 * restricted-name = restricted-name-first *126restricted-name-chars
 53 * restricted-name-first  = ALPHA / DIGIT
 54 * restricted-name-chars  = ALPHA / DIGIT / "!" / "#" /
 55 *                          "$" / "&" / "-" / "^" / "_"
 56 * restricted-name-chars =/ "." ; Characters before first dot always
 57 *                              ; specify a facet name
 58 * restricted-name-chars =/ "+" ; Characters after last plus always
 59 *                              ; specify a structured syntax suffix
 60 * ALPHA =  %x41-5A / %x61-7A   ; A-Z / a-z
 61 * DIGIT =  %x30-39             ; 0-9
 62 */
 63var subtypeNameRegExp = /^[A-Za-z0-9][A-Za-z0-9!#$&^_.-]{0,126}$/
 64var typeNameRegExp = /^[A-Za-z0-9][A-Za-z0-9!#$&^_-]{0,126}$/
 65var typeRegExp = /^ *([A-Za-z0-9][A-Za-z0-9!#$&^_-]{0,126})\/([A-Za-z0-9][A-Za-z0-9!#$&^_.+-]{0,126}) *$/;
 66
 67/**
 68 * Module exports.
 69 */
 70
 71exports.format = format
 72exports.parse = parse
 73
 74/**
 75 * Format object to media type.
 76 *
 77 * @param {object} obj
 78 * @return {string}
 79 * @api public
 80 */
 81
 82function format(obj) {
 83  if (!obj || typeof obj !== 'object') {
 84    throw new TypeError('argument obj is required')
 85  }
 86
 87  var parameters = obj.parameters
 88  var subtype = obj.subtype
 89  var suffix = obj.suffix
 90  var type = obj.type
 91
 92  if (!type || !typeNameRegExp.test(type)) {
 93    throw new TypeError('invalid type')
 94  }
 95
 96  if (!subtype || !subtypeNameRegExp.test(subtype)) {
 97    throw new TypeError('invalid subtype')
 98  }
 99
100  // format as type/subtype
101  var string = type + '/' + subtype
102
103  // append +suffix
104  if (suffix) {
105    if (!typeNameRegExp.test(suffix)) {
106      throw new TypeError('invalid suffix')
107    }
108
109    string += '+' + suffix
110  }
111
112  // append parameters
113  if (parameters && typeof parameters === 'object') {
114    var param
115    var params = Object.keys(parameters).sort()
116
117    for (var i = 0; i < params.length; i++) {
118      param = params[i]
119
120      if (!tokenRegExp.test(param)) {
121        throw new TypeError('invalid parameter name')
122      }
123
124      string += '; ' + param + '=' + qstring(parameters[param])
125    }
126  }
127
128  return string
129}
130
131/**
132 * Parse media type to object.
133 *
134 * @param {string|object} string
135 * @return {Object}
136 * @api public
137 */
138
139function parse(string) {
140  if (!string) {
141    throw new TypeError('argument string is required')
142  }
143
144  // support req/res-like objects as argument
145  if (typeof string === 'object') {
146    string = getcontenttype(string)
147  }
148
149  if (typeof string !== 'string') {
150    throw new TypeError('argument string is required to be a string')
151  }
152
153  var index = string.indexOf(';')
154  var type = index !== -1
155    ? string.substr(0, index)
156    : string
157
158  var key
159  var match
160  var obj = splitType(type)
161  var params = {}
162  var value
163
164  paramRegExp.lastIndex = index
165
166  while (match = paramRegExp.exec(string)) {
167    if (match.index !== index) {
168      throw new TypeError('invalid parameter format')
169    }
170
171    index += match[0].length
172    key = match[1].toLowerCase()
173    value = match[2]
174
175    if (value[0] === '"') {
176      // remove quotes and escapes
177      value = value
178        .substr(1, value.length - 2)
179        .replace(qescRegExp, '$1')
180    }
181
182    params[key] = value
183  }
184
185  if (index !== -1 && index !== string.length) {
186    throw new TypeError('invalid parameter format')
187  }
188
189  obj.parameters = params
190
191  return obj
192}
193
194/**
195 * Get content-type from req/res objects.
196 *
197 * @param {object}
198 * @return {Object}
199 * @api private
200 */
201
202function getcontenttype(obj) {
203  if (typeof obj.getHeader === 'function') {
204    // res-like
205    return obj.getHeader('content-type')
206  }
207
208  if (typeof obj.headers === 'object') {
209    // req-like
210    return obj.headers && obj.headers['content-type']
211  }
212}
213
214/**
215 * Quote a string if necessary.
216 *
217 * @param {string} val
218 * @return {string}
219 * @api private
220 */
221
222function qstring(val) {
223  var str = String(val)
224
225  // no need to quote tokens
226  if (tokenRegExp.test(str)) {
227    return str
228  }
229
230  if (str.length > 0 && !textRegExp.test(str)) {
231    throw new TypeError('invalid parameter value')
232  }
233
234  return '"' + str.replace(quoteRegExp, '\\$1') + '"'
235}
236
237/**
238 * Simply "type/subtype+siffx" into parts.
239 *
240 * @param {string} string
241 * @return {Object}
242 * @api private
243 */
244
245function splitType(string) {
246  var match = typeRegExp.exec(string.toLowerCase())
247
248  if (!match) {
249    throw new TypeError('invalid media type')
250  }
251
252  var type = match[1]
253  var subtype = match[2]
254  var suffix
255
256  // suffix after last +
257  var index = subtype.lastIndexOf('+')
258  if (index !== -1) {
259    suffix = subtype.substr(index + 1)
260    subtype = subtype.substr(0, index)
261  }
262
263  var obj = {
264    type: type,
265    subtype: subtype,
266    suffix: suffix
267  }
268
269  return obj
270}