Skip to content

Commit

Permalink
Remove parameter handling, which is outside RFC 6838 scope
Browse files Browse the repository at this point in the history
  • Loading branch information
dougwilson committed Mar 25, 2017
1 parent e5201db commit a861b0f
Show file tree
Hide file tree
Showing 4 changed files with 2 additions and 231 deletions.
1 change: 1 addition & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
127 changes: 0 additions & 127 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,46 +4,6 @@
* 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 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 = <any US-ASCII character (octets 0 - 127)>
*/
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
*
Expand Down Expand Up @@ -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
Expand All @@ -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
}

Expand All @@ -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) {
Expand Down
101 changes: 0 additions & 101 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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/)
})
Expand Down Expand Up @@ -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 () {
Expand All @@ -117,74 +71,19 @@ 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')
assert.equal(type.subtype, 'svg')
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/)
})
Expand Down

0 comments on commit a861b0f

Please sign in to comment.