diff --git a/HISTORY.md b/HISTORY.md index 843d661..933bf9e 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,6 +1,7 @@ unreleased ========== + * Remove parameter handling, which is outside RFC 6838 scope * Remove `parse(req)` and `parse(res)` signatures - Use the `content-type` module for content type parsing * perf: use a class for object creation diff --git a/README.md b/README.md index b0c0e05..70291f5 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ var typer = require('media-typer') ### typer.parse(string) ```js -var obj = typer.parse('image/svg+xml; charset=utf-8') +var obj = typer.parse('image/svg+xml') ``` Parse a media type string. This will return an object with the following @@ -39,8 +39,6 @@ properties (examples are shown for the string `'image/svg+xml; charset=utf-8'`): - `suffix`: The suffix of the media type (always lower case). Example: `'xml'` - - `parameters`: An object of the parameters in the media type (name of parameter always lower case). Example: `{charset: 'utf-8'}` - ### typer.format(obj) ```js diff --git a/index.js b/index.js index 8f45e5f..fcab013 100644 --- a/index.js +++ b/index.js @@ -4,46 +4,6 @@ * MIT Licensed */ -/** - * RegExp to match *( ";" parameter ) in RFC 2616 sec 3.7 - * - * parameter = token "=" ( token | quoted-string ) - * token = 1* - * separators = "(" | ")" | "<" | ">" | "@" - * | "," | ";" | ":" | "\" | <"> - * | "/" | "[" | "]" | "?" | "=" - * | "{" | "}" | SP | HT - * quoted-string = ( <"> *(qdtext | quoted-pair ) <"> ) - * qdtext = > - * quoted-pair = "\" CHAR - * CHAR = - * TEXT = - * LWS = [CRLF] 1*( SP | HT ) - * CRLF = CR LF - * CR = - * LF = - * SP = - * SHT = - * CTL = - * OCTET = - */ -var PARAM_REGEXP = /; *([!#$%&'*+.0-9A-Z^_`a-z|~-]+) *= *("(?:[ !\u0023-\u005b\u005d-\u007e\u0080-\u00ff]|\\[\u0020-\u007e])*"|[!#$%&'*+.0-9A-Z^_`a-z|~-]+) */g -var TEXT_REGEXP = /^[\u0020-\u007e\u0080-\u00ff]+$/ -var TOKEN_REGEXP = /^[!#$%&'*+.0-9A-Z^_`a-z|~-]+$/ - -/** - * RegExp to match quoted-pair in RFC 2616 - * - * quoted-pair = "\" CHAR - * CHAR = - */ -var QESC_REGEXP = /\\([\u0000-\u007f])/g - -/** - * RegExp to match chars that must be quoted-pair in RFC 2616 - */ -var QUOTE_REGEXP = /([\\"])/g - /** * RegExp to match type in RFC 6838 * @@ -84,7 +44,6 @@ function format (obj) { throw new TypeError('argument obj is required') } - var parameters = obj.parameters var subtype = obj.subtype var suffix = obj.suffix var type = obj.type @@ -109,22 +68,6 @@ function format (obj) { 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 (!TOKEN_REGEXP.test(param)) { - throw new TypeError('invalid parameter name') - } - - string += '; ' + param + '=' + qstring(parameters[param]) - } - } - return string } @@ -145,76 +88,6 @@ function parse (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 value - - PARAM_REGEXP.lastIndex = index - - while ((match = PARAM_REGEXP.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(QESC_REGEXP, '$1') - } - - obj.parameters[key] = value - } - - if (index !== -1 && index !== string.length) { - throw new TypeError('invalid parameter format') - } - - return obj -} - -/** - * 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') + '"' -} - -/** - * Split "type/subtype+siffx" into parts. - * - * @param {string} string - * @return {Object} - * @private - */ - -function splitType (string) { var match = TYPE_REGEXP.exec(string.toLowerCase()) if (!match) { diff --git a/test/test.js b/test/test.js index 8bfa7dd..d80ecf6 100644 --- a/test/test.js +++ b/test/test.js @@ -26,42 +26,6 @@ describe('typer.format(obj)', function () { assert.equal(str, 'image/svg+xml') }) - it('should format type with parameter', function () { - var str = typer.format({ - type: 'text', - subtype: 'html', - parameters: {charset: 'utf-8'} - }) - assert.equal(str, 'text/html; charset=utf-8') - }) - - it('should format type with parameter that needs quotes', function () { - var str = typer.format({ - type: 'text', - subtype: 'html', - parameters: {foo: 'bar or "baz"'} - }) - assert.equal(str, 'text/html; foo="bar or \\"baz\\""') - }) - - it('should format type with parameter with empty value', function () { - var str = typer.format({ - type: 'text', - subtype: 'html', - parameters: {foo: ''} - }) - assert.equal(str, 'text/html; foo=""') - }) - - it('should format type with multiple parameters', function () { - var str = typer.format({ - type: 'text', - subtype: 'html', - parameters: {charset: 'utf-8', foo: 'bar', bar: 'baz'} - }) - assert.equal(str, 'text/html; bar=baz; charset=utf-8; foo=bar') - }) - it('should require argument', function () { assert.throws(typer.format.bind(null), /obj.*required/) }) @@ -91,16 +55,6 @@ describe('typer.format(obj)', function () { var obj = {type: 'image', subtype: 'svg', suffix: 'xml\\'} assert.throws(typer.format.bind(null, obj), /invalid suffix/) }) - - it('should reject invalid parameter name', function () { - var obj = {type: 'image', subtype: 'svg', parameters: {'foo/': 'bar'}} - assert.throws(typer.format.bind(null, obj), /invalid parameter name/) - }) - - it('should reject invalid parameter value', function () { - var obj = {type: 'image', subtype: 'svg', parameters: {'foo': 'bar\u0000'}} - assert.throws(typer.format.bind(null, obj), /invalid parameter value/) - }) }) describe('typer.parse(string)', function () { @@ -117,26 +71,6 @@ describe('typer.parse(string)', function () { assert.equal(type.suffix, 'xml') }) - it('should parse parameters', function () { - var type = typer.parse('text/html; charset=utf-8; foo=bar') - assert.equal(type.type, 'text') - assert.equal(type.subtype, 'html') - assert.deepEqual(type.parameters, { - charset: 'utf-8', - foo: 'bar' - }) - }) - - it('should parse parameters with extra LWS', function () { - var type = typer.parse('text/html ; charset=utf-8 ; foo=bar') - assert.equal(type.type, 'text') - assert.equal(type.subtype, 'html') - assert.deepEqual(type.parameters, { - charset: 'utf-8', - foo: 'bar' - }) - }) - it('should lower-case type', function () { var type = typer.parse('IMAGE/SVG+XML') assert.equal(type.type, 'image') @@ -144,47 +78,12 @@ describe('typer.parse(string)', function () { assert.equal(type.suffix, 'xml') }) - it('should lower-case parameter names', function () { - var type = typer.parse('text/html; Charset=UTF-8') - assert.deepEqual(type.parameters, { - charset: 'UTF-8' - }) - }) - - it('should unquote parameter values', function () { - var type = typer.parse('text/html; charset="UTF-8"') - assert.deepEqual(type.parameters, { - charset: 'UTF-8' - }) - }) - - it('should unquote parameter values with escapes', function () { - var type = typer.parse('text/html; charset = "UT\\F-\\\\\\"8\\""') - assert.deepEqual(type.parameters, { - charset: 'UTF-\\"8"' - }) - }) - - it('should handle balanced quotes', function () { - var type = typer.parse('text/html; param="charset=\\"utf-8\\"; foo=bar"; bar=foo') - assert.deepEqual(type.parameters, { - param: 'charset="utf-8"; foo=bar', - bar: 'foo' - }) - }) - invalidTypes.forEach(function (type) { it('should throw on invalid media type ' + type, function () { assert.throws(typer.parse.bind(null, type), /invalid media type/) }) }) - it('should throw on invalid parameter format', function () { - assert.throws(typer.parse.bind(null, 'text/plain; foo="bar'), /invalid parameter format/) - assert.throws(typer.parse.bind(null, 'text/plain; profile=http://localhost; foo=bar'), /invalid parameter format/) - assert.throws(typer.parse.bind(null, 'text/plain; profile=http://localhost'), /invalid parameter format/) - }) - it('should require argument', function () { assert.throws(typer.parse.bind(null), /string.*required/) })