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.
|
|
/*! * content-type * Copyright(c) 2015 Douglas Christopher Wilson * MIT Licensed */
'use strict'
/** * RegExp to match *( ";" parameter ) in RFC 7231 sec 3.1.1.1 * * parameter = token "=" ( token / quoted-string ) * token = 1*tchar * tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" * / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" * / DIGIT / ALPHA * ; any VCHAR, except delimiters * quoted-string = DQUOTE *( qdtext / quoted-pair ) DQUOTE * qdtext = HTAB / SP / %x21 / %x23-5B / %x5D-7E / obs-text * obs-text = %x80-FF * quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text ) */ var PARAM_REGEXP = /; *([!#$%&'*+.^_`|~0-9A-Za-z-]+) *= *("(?:[\u000b\u0020\u0021\u0023-\u005b\u005d-\u007e\u0080-\u00ff]|\\[\u000b\u0020-\u00ff])*"|[!#$%&'*+.^_`|~0-9A-Za-z-]+) */g var TEXT_REGEXP = /^[\u000b\u0020-\u007e\u0080-\u00ff]+$/ var TOKEN_REGEXP = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/
/** * RegExp to match quoted-pair in RFC 7230 sec 3.2.6 * * quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text ) * obs-text = %x80-FF */ var QESC_REGEXP = /\\([\u000b\u0020-\u00ff])/g
/** * RegExp to match chars that must be quoted-pair in RFC 7230 sec 3.2.6 */ var QUOTE_REGEXP = /([\\"])/g
/** * RegExp to match type in RFC 7231 sec 3.1.1.1 * * media-type = type "/" subtype * type = token * subtype = token */ var TYPE_REGEXP = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+\/[!#$%&'*+.^_`|~0-9A-Za-z-]+$/
/** * Module exports. * @public */
exports.format = format exports.parse = parse
/** * Format object to media type. * * @param {object} obj * @return {string} * @public */
function format (obj) { if (!obj || typeof obj !== 'object') { throw new TypeError('argument obj is required') }
var parameters = obj.parameters var type = obj.type
if (!type || !TYPE_REGEXP.test(type)) { throw new TypeError('invalid type') }
var string = type
// 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 (!TOKEN_REGEXP.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} * @public */
function parse (string) { if (!string) { throw new TypeError('argument string is required') }
// support req/res-like objects as argument
var header = typeof string === 'object' ? getcontenttype(string) : string
if (typeof header !== 'string') { throw new TypeError('argument string is required to be a string') }
var index = header.indexOf(';') var type = index !== -1 ? header.substr(0, index).trim() : header.trim()
if (!TYPE_REGEXP.test(type)) { throw new TypeError('invalid media type') }
var obj = new ContentType(type.toLowerCase())
// parse parameters
if (index !== -1) { var key var match var value
PARAM_REGEXP.lastIndex = index
while ((match = PARAM_REGEXP.exec(header))) { 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(QESC_REGEXP, '$1') }
obj.parameters[key] = value }
if (index !== header.length) { throw new TypeError('invalid parameter format') } }
return obj }
/** * Get content-type from req/res objects. * * @param {object} * @return {Object} * @private */
function getcontenttype (obj) { var header
if (typeof obj.getHeader === 'function') { // res-like
header = obj.getHeader('content-type') } else if (typeof obj.headers === 'object') { // req-like
header = obj.headers && obj.headers['content-type'] }
if (typeof header !== 'string') { throw new TypeError('content-type header is missing from object') }
return header }
/** * Quote a string if necessary. * * @param {string} val * @return {string} * @private */
function qstring (val) { var str = String(val)
// no need to quote tokens
if (TOKEN_REGEXP.test(str)) { return str }
if (str.length > 0 && !TEXT_REGEXP.test(str)) { throw new TypeError('invalid parameter value') }
return '"' + str.replace(QUOTE_REGEXP, '\\$1') + '"' }
/** * Class to represent a content type. * @private */ function ContentType (type) { this.parameters = Object.create(null) this.type = type }
|