| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 | 
							- /*!
 
-  * media-typer
 
-  * Copyright(c) 2014 Douglas Christopher Wilson
 
-  * MIT Licensed
 
-  */
 
- /**
 
-  * RegExp to match *( ";" parameter ) in RFC 2616 sec 3.7
 
-  *
 
-  * parameter     = token "=" ( token | quoted-string )
 
-  * token         = 1*<any CHAR except CTLs or separators>
 
-  * separators    = "(" | ")" | "<" | ">" | "@"
 
-  *               | "," | ";" | ":" | "\" | <">
 
-  *               | "/" | "[" | "]" | "?" | "="
 
-  *               | "{" | "}" | SP | HT
 
-  * quoted-string = ( <"> *(qdtext | quoted-pair ) <"> )
 
-  * qdtext        = <any TEXT except <">>
 
-  * quoted-pair   = "\" CHAR
 
-  * CHAR          = <any US-ASCII character (octets 0 - 127)>
 
-  * TEXT          = <any OCTET except CTLs, but including LWS>
 
-  * LWS           = [CRLF] 1*( SP | HT )
 
-  * CRLF          = CR LF
 
-  * CR            = <US-ASCII CR, carriage return (13)>
 
-  * LF            = <US-ASCII LF, linefeed (10)>
 
-  * SP            = <US-ASCII SP, space (32)>
 
-  * SHT           = <US-ASCII HT, horizontal-tab (9)>
 
-  * CTL           = <any US-ASCII control character (octets 0 - 31) and DEL (127)>
 
-  * OCTET         = <any 8-bit sequence of data>
 
-  */
 
- var paramRegExp = /; *([!#$%&'\*\+\-\.0-9A-Z\^_`a-z\|~]+) *= *("(?:[ !\u0023-\u005b\u005d-\u007e\u0080-\u00ff]|\\[\u0020-\u007e])*"|[!#$%&'\*\+\-\.0-9A-Z\^_`a-z\|~]+) */g;
 
- var textRegExp = /^[\u0020-\u007e\u0080-\u00ff]+$/
 
- var tokenRegExp = /^[!#$%&'\*\+\-\.0-9A-Z\^_`a-z\|~]+$/
 
- /**
 
-  * RegExp to match quoted-pair in RFC 2616
 
-  *
 
-  * quoted-pair = "\" CHAR
 
-  * CHAR        = <any US-ASCII character (octets 0 - 127)>
 
-  */
 
- var qescRegExp = /\\([\u0000-\u007f])/g;
 
- /**
 
-  * RegExp to match chars that must be quoted-pair in RFC 2616
 
-  */
 
- var quoteRegExp = /([\\"])/g;
 
- /**
 
-  * RegExp to match type in RFC 6838
 
-  *
 
-  * type-name = restricted-name
 
-  * subtype-name = restricted-name
 
-  * restricted-name = restricted-name-first *126restricted-name-chars
 
-  * restricted-name-first  = ALPHA / DIGIT
 
-  * restricted-name-chars  = ALPHA / DIGIT / "!" / "#" /
 
-  *                          "$" / "&" / "-" / "^" / "_"
 
-  * restricted-name-chars =/ "." ; Characters before first dot always
 
-  *                              ; specify a facet name
 
-  * restricted-name-chars =/ "+" ; Characters after last plus always
 
-  *                              ; specify a structured syntax suffix
 
-  * ALPHA =  %x41-5A / %x61-7A   ; A-Z / a-z
 
-  * DIGIT =  %x30-39             ; 0-9
 
-  */
 
- var subtypeNameRegExp = /^[A-Za-z0-9][A-Za-z0-9!#$&^_.-]{0,126}$/
 
- var typeNameRegExp = /^[A-Za-z0-9][A-Za-z0-9!#$&^_-]{0,126}$/
 
- var typeRegExp = /^ *([A-Za-z0-9][A-Za-z0-9!#$&^_-]{0,126})\/([A-Za-z0-9][A-Za-z0-9!#$&^_.+-]{0,126}) *$/;
 
- /**
 
-  * Module exports.
 
-  */
 
- exports.format = format
 
- exports.parse = parse
 
- /**
 
-  * Format object to media type.
 
-  *
 
-  * @param {object} obj
 
-  * @return {string}
 
-  * @api public
 
-  */
 
- function format(obj) {
 
-   if (!obj || typeof obj !== 'object') {
 
-     throw new TypeError('argument obj is required')
 
-   }
 
-   var parameters = obj.parameters
 
-   var subtype = obj.subtype
 
-   var suffix = obj.suffix
 
-   var type = obj.type
 
-   if (!type || !typeNameRegExp.test(type)) {
 
-     throw new TypeError('invalid type')
 
-   }
 
-   if (!subtype || !subtypeNameRegExp.test(subtype)) {
 
-     throw new TypeError('invalid subtype')
 
-   }
 
-   // format as type/subtype
 
-   var string = type + '/' + subtype
 
-   // append +suffix
 
-   if (suffix) {
 
-     if (!typeNameRegExp.test(suffix)) {
 
-       throw new TypeError('invalid suffix')
 
-     }
 
-     string += '+' + suffix
 
-   }
 
-   // append parameters
 
-   if (parameters && typeof parameters === 'object') {
 
-     var param
 
-     var params = Object.keys(parameters).sort()
 
-     for (var i = 0; i < params.length; i++) {
 
-       param = params[i]
 
-       if (!tokenRegExp.test(param)) {
 
-         throw new TypeError('invalid parameter name')
 
-       }
 
-       string += '; ' + param + '=' + qstring(parameters[param])
 
-     }
 
-   }
 
-   return string
 
- }
 
- /**
 
-  * Parse media type to object.
 
-  *
 
-  * @param {string|object} string
 
-  * @return {Object}
 
-  * @api public
 
-  */
 
- function parse(string) {
 
-   if (!string) {
 
-     throw new TypeError('argument string is required')
 
-   }
 
-   // support req/res-like objects as argument
 
-   if (typeof string === 'object') {
 
-     string = getcontenttype(string)
 
-   }
 
-   if (typeof string !== 'string') {
 
-     throw new TypeError('argument string is required to be a string')
 
-   }
 
-   var index = string.indexOf(';')
 
-   var type = index !== -1
 
-     ? string.substr(0, index)
 
-     : string
 
-   var key
 
-   var match
 
-   var obj = splitType(type)
 
-   var params = {}
 
-   var value
 
-   paramRegExp.lastIndex = index
 
-   while (match = paramRegExp.exec(string)) {
 
-     if (match.index !== index) {
 
-       throw new TypeError('invalid parameter format')
 
-     }
 
-     index += match[0].length
 
-     key = match[1].toLowerCase()
 
-     value = match[2]
 
-     if (value[0] === '"') {
 
-       // remove quotes and escapes
 
-       value = value
 
-         .substr(1, value.length - 2)
 
-         .replace(qescRegExp, '$1')
 
-     }
 
-     params[key] = value
 
-   }
 
-   if (index !== -1 && index !== string.length) {
 
-     throw new TypeError('invalid parameter format')
 
-   }
 
-   obj.parameters = params
 
-   return obj
 
- }
 
- /**
 
-  * Get content-type from req/res objects.
 
-  *
 
-  * @param {object}
 
-  * @return {Object}
 
-  * @api private
 
-  */
 
- function getcontenttype(obj) {
 
-   if (typeof obj.getHeader === 'function') {
 
-     // res-like
 
-     return obj.getHeader('content-type')
 
-   }
 
-   if (typeof obj.headers === 'object') {
 
-     // req-like
 
-     return obj.headers && obj.headers['content-type']
 
-   }
 
- }
 
- /**
 
-  * Quote a string if necessary.
 
-  *
 
-  * @param {string} val
 
-  * @return {string}
 
-  * @api private
 
-  */
 
- function qstring(val) {
 
-   var str = String(val)
 
-   // no need to quote tokens
 
-   if (tokenRegExp.test(str)) {
 
-     return str
 
-   }
 
-   if (str.length > 0 && !textRegExp.test(str)) {
 
-     throw new TypeError('invalid parameter value')
 
-   }
 
-   return '"' + str.replace(quoteRegExp, '\\$1') + '"'
 
- }
 
- /**
 
-  * Simply "type/subtype+siffx" into parts.
 
-  *
 
-  * @param {string} string
 
-  * @return {Object}
 
-  * @api private
 
-  */
 
- function splitType(string) {
 
-   var match = typeRegExp.exec(string.toLowerCase())
 
-   if (!match) {
 
-     throw new TypeError('invalid media type')
 
-   }
 
-   var type = match[1]
 
-   var subtype = match[2]
 
-   var suffix
 
-   // suffix after last +
 
-   var index = subtype.lastIndexOf('+')
 
-   if (index !== -1) {
 
-     suffix = subtype.substr(index + 1)
 
-     subtype = subtype.substr(0, index)
 
-   }
 
-   var obj = {
 
-     type: type,
 
-     subtype: subtype,
 
-     suffix: suffix
 
-   }
 
-   return obj
 
- }
 
 
  |