content-type 1.0.0 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/HISTORY.md +20 -0
- package/README.md +8 -0
- package/index.js +62 -50
- package/package.json +9 -2
package/HISTORY.md
CHANGED
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
1.0.4 / 2017-09-11
|
|
2
|
+
==================
|
|
3
|
+
|
|
4
|
+
* perf: skip parameter parsing when no parameters
|
|
5
|
+
|
|
6
|
+
1.0.3 / 2017-09-10
|
|
7
|
+
==================
|
|
8
|
+
|
|
9
|
+
* perf: remove argument reassignment
|
|
10
|
+
|
|
11
|
+
1.0.2 / 2016-05-09
|
|
12
|
+
==================
|
|
13
|
+
|
|
14
|
+
* perf: enable strict mode
|
|
15
|
+
|
|
16
|
+
1.0.1 / 2015-02-13
|
|
17
|
+
==================
|
|
18
|
+
|
|
19
|
+
* Improve missing `Content-Type` header error message
|
|
20
|
+
|
|
1
21
|
1.0.0 / 2015-02-01
|
|
2
22
|
==================
|
|
3
23
|
|
package/README.md
CHANGED
|
@@ -35,6 +35,8 @@ properties (examples are shown for the string `'image/svg+xml; charset=utf-8'`):
|
|
|
35
35
|
- `parameters`: An object of the parameters in the media type (name of parameter
|
|
36
36
|
always lower case). Example: `{charset: 'utf-8'}`
|
|
37
37
|
|
|
38
|
+
Throws a `TypeError` if the string is missing or invalid.
|
|
39
|
+
|
|
38
40
|
### contentType.parse(req)
|
|
39
41
|
|
|
40
42
|
```js
|
|
@@ -44,6 +46,8 @@ var obj = contentType.parse(req)
|
|
|
44
46
|
Parse the `content-type` header from the given `req`. Short-cut for
|
|
45
47
|
`contentType.parse(req.headers['content-type'])`.
|
|
46
48
|
|
|
49
|
+
Throws a `TypeError` if the `Content-Type` header is missing or invalid.
|
|
50
|
+
|
|
47
51
|
### contentType.parse(res)
|
|
48
52
|
|
|
49
53
|
```js
|
|
@@ -53,6 +57,8 @@ var obj = contentType.parse(res)
|
|
|
53
57
|
Parse the `content-type` header set on the given `res`. Short-cut for
|
|
54
58
|
`contentType.parse(res.getHeader('content-type'))`.
|
|
55
59
|
|
|
60
|
+
Throws a `TypeError` if the `Content-Type` header is missing or invalid.
|
|
61
|
+
|
|
56
62
|
### contentType.format(obj)
|
|
57
63
|
|
|
58
64
|
```js
|
|
@@ -68,6 +74,8 @@ shown that produce the string `'image/svg+xml; charset=utf-8'`):
|
|
|
68
74
|
- `parameters`: An object of the parameters in the media type (name of the
|
|
69
75
|
parameter will be lower-cased). Example: `{charset: 'utf-8'}`
|
|
70
76
|
|
|
77
|
+
Throws a `TypeError` if the object contains an invalid type or parameter names.
|
|
78
|
+
|
|
71
79
|
## License
|
|
72
80
|
|
|
73
81
|
[MIT](LICENSE)
|
package/index.js
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
* MIT Licensed
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
'use strict'
|
|
8
|
+
|
|
7
9
|
/**
|
|
8
10
|
* RegExp to match *( ";" parameter ) in RFC 7231 sec 3.1.1.1
|
|
9
11
|
*
|
|
@@ -18,9 +20,9 @@
|
|
|
18
20
|
* obs-text = %x80-FF
|
|
19
21
|
* quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text )
|
|
20
22
|
*/
|
|
21
|
-
var
|
|
22
|
-
var
|
|
23
|
-
var
|
|
23
|
+
var PARAM_REGEXP = /; *([!#$%&'*+.^_`|~0-9A-Za-z-]+) *= *("(?:[\u000b\u0020\u0021\u0023-\u005b\u005d-\u007e\u0080-\u00ff]|\\[\u000b\u0020-\u00ff])*"|[!#$%&'*+.^_`|~0-9A-Za-z-]+) */g
|
|
24
|
+
var TEXT_REGEXP = /^[\u000b\u0020-\u007e\u0080-\u00ff]+$/
|
|
25
|
+
var TOKEN_REGEXP = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/
|
|
24
26
|
|
|
25
27
|
/**
|
|
26
28
|
* RegExp to match quoted-pair in RFC 7230 sec 3.2.6
|
|
@@ -28,21 +30,21 @@ var tokenRegExp = /^[!#$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+$/
|
|
|
28
30
|
* quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text )
|
|
29
31
|
* obs-text = %x80-FF
|
|
30
32
|
*/
|
|
31
|
-
var
|
|
33
|
+
var QESC_REGEXP = /\\([\u000b\u0020-\u00ff])/g
|
|
32
34
|
|
|
33
35
|
/**
|
|
34
36
|
* RegExp to match chars that must be quoted-pair in RFC 7230 sec 3.2.6
|
|
35
37
|
*/
|
|
36
|
-
var
|
|
38
|
+
var QUOTE_REGEXP = /([\\"])/g
|
|
37
39
|
|
|
38
40
|
/**
|
|
39
|
-
* RegExp to match type in RFC
|
|
41
|
+
* RegExp to match type in RFC 7231 sec 3.1.1.1
|
|
40
42
|
*
|
|
41
43
|
* media-type = type "/" subtype
|
|
42
44
|
* type = token
|
|
43
45
|
* subtype = token
|
|
44
46
|
*/
|
|
45
|
-
var
|
|
47
|
+
var TYPE_REGEXP = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+\/[!#$%&'*+.^_`|~0-9A-Za-z-]+$/
|
|
46
48
|
|
|
47
49
|
/**
|
|
48
50
|
* Module exports.
|
|
@@ -60,7 +62,7 @@ exports.parse = parse
|
|
|
60
62
|
* @public
|
|
61
63
|
*/
|
|
62
64
|
|
|
63
|
-
function format(obj) {
|
|
65
|
+
function format (obj) {
|
|
64
66
|
if (!obj || typeof obj !== 'object') {
|
|
65
67
|
throw new TypeError('argument obj is required')
|
|
66
68
|
}
|
|
@@ -68,7 +70,7 @@ function format(obj) {
|
|
|
68
70
|
var parameters = obj.parameters
|
|
69
71
|
var type = obj.type
|
|
70
72
|
|
|
71
|
-
if (!type || !
|
|
73
|
+
if (!type || !TYPE_REGEXP.test(type)) {
|
|
72
74
|
throw new TypeError('invalid type')
|
|
73
75
|
}
|
|
74
76
|
|
|
@@ -82,7 +84,7 @@ function format(obj) {
|
|
|
82
84
|
for (var i = 0; i < params.length; i++) {
|
|
83
85
|
param = params[i]
|
|
84
86
|
|
|
85
|
-
if (!
|
|
87
|
+
if (!TOKEN_REGEXP.test(param)) {
|
|
86
88
|
throw new TypeError('invalid parameter name')
|
|
87
89
|
}
|
|
88
90
|
|
|
@@ -101,57 +103,61 @@ function format(obj) {
|
|
|
101
103
|
* @public
|
|
102
104
|
*/
|
|
103
105
|
|
|
104
|
-
function parse(string) {
|
|
106
|
+
function parse (string) {
|
|
105
107
|
if (!string) {
|
|
106
108
|
throw new TypeError('argument string is required')
|
|
107
109
|
}
|
|
108
110
|
|
|
109
111
|
// support req/res-like objects as argument
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
112
|
+
var header = typeof string === 'object'
|
|
113
|
+
? getcontenttype(string)
|
|
114
|
+
: string
|
|
113
115
|
|
|
114
|
-
if (typeof
|
|
116
|
+
if (typeof header !== 'string') {
|
|
115
117
|
throw new TypeError('argument string is required to be a string')
|
|
116
118
|
}
|
|
117
119
|
|
|
118
|
-
var index =
|
|
120
|
+
var index = header.indexOf(';')
|
|
119
121
|
var type = index !== -1
|
|
120
|
-
?
|
|
121
|
-
:
|
|
122
|
+
? header.substr(0, index).trim()
|
|
123
|
+
: header.trim()
|
|
122
124
|
|
|
123
|
-
if (!
|
|
125
|
+
if (!TYPE_REGEXP.test(type)) {
|
|
124
126
|
throw new TypeError('invalid media type')
|
|
125
127
|
}
|
|
126
128
|
|
|
127
|
-
var key
|
|
128
|
-
var match
|
|
129
129
|
var obj = new ContentType(type.toLowerCase())
|
|
130
|
-
var value
|
|
131
130
|
|
|
132
|
-
|
|
131
|
+
// parse parameters
|
|
132
|
+
if (index !== -1) {
|
|
133
|
+
var key
|
|
134
|
+
var match
|
|
135
|
+
var value
|
|
133
136
|
|
|
134
|
-
|
|
135
|
-
if (match.index !== index) {
|
|
136
|
-
throw new TypeError('invalid parameter format')
|
|
137
|
-
}
|
|
137
|
+
PARAM_REGEXP.lastIndex = index
|
|
138
138
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
139
|
+
while ((match = PARAM_REGEXP.exec(header))) {
|
|
140
|
+
if (match.index !== index) {
|
|
141
|
+
throw new TypeError('invalid parameter format')
|
|
142
|
+
}
|
|
142
143
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
value =
|
|
146
|
-
.substr(1, value.length - 2)
|
|
147
|
-
.replace(qescRegExp, '$1')
|
|
148
|
-
}
|
|
144
|
+
index += match[0].length
|
|
145
|
+
key = match[1].toLowerCase()
|
|
146
|
+
value = match[2]
|
|
149
147
|
|
|
150
|
-
|
|
151
|
-
|
|
148
|
+
if (value[0] === '"') {
|
|
149
|
+
// remove quotes and escapes
|
|
150
|
+
value = value
|
|
151
|
+
.substr(1, value.length - 2)
|
|
152
|
+
.replace(QESC_REGEXP, '$1')
|
|
153
|
+
}
|
|
152
154
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
+
obj.parameters[key] = value
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (index !== header.length) {
|
|
159
|
+
throw new TypeError('invalid parameter format')
|
|
160
|
+
}
|
|
155
161
|
}
|
|
156
162
|
|
|
157
163
|
return obj
|
|
@@ -165,16 +171,22 @@ function parse(string) {
|
|
|
165
171
|
* @private
|
|
166
172
|
*/
|
|
167
173
|
|
|
168
|
-
function getcontenttype(obj) {
|
|
174
|
+
function getcontenttype (obj) {
|
|
175
|
+
var header
|
|
176
|
+
|
|
169
177
|
if (typeof obj.getHeader === 'function') {
|
|
170
178
|
// res-like
|
|
171
|
-
|
|
179
|
+
header = obj.getHeader('content-type')
|
|
180
|
+
} else if (typeof obj.headers === 'object') {
|
|
181
|
+
// req-like
|
|
182
|
+
header = obj.headers && obj.headers['content-type']
|
|
172
183
|
}
|
|
173
184
|
|
|
174
|
-
if (typeof
|
|
175
|
-
|
|
176
|
-
return obj.headers && obj.headers['content-type']
|
|
185
|
+
if (typeof header !== 'string') {
|
|
186
|
+
throw new TypeError('content-type header is missing from object')
|
|
177
187
|
}
|
|
188
|
+
|
|
189
|
+
return header
|
|
178
190
|
}
|
|
179
191
|
|
|
180
192
|
/**
|
|
@@ -185,26 +197,26 @@ function getcontenttype(obj) {
|
|
|
185
197
|
* @private
|
|
186
198
|
*/
|
|
187
199
|
|
|
188
|
-
function qstring(val) {
|
|
200
|
+
function qstring (val) {
|
|
189
201
|
var str = String(val)
|
|
190
202
|
|
|
191
203
|
// no need to quote tokens
|
|
192
|
-
if (
|
|
204
|
+
if (TOKEN_REGEXP.test(str)) {
|
|
193
205
|
return str
|
|
194
206
|
}
|
|
195
207
|
|
|
196
|
-
if (str.length > 0 && !
|
|
208
|
+
if (str.length > 0 && !TEXT_REGEXP.test(str)) {
|
|
197
209
|
throw new TypeError('invalid parameter value')
|
|
198
210
|
}
|
|
199
211
|
|
|
200
|
-
return '"' + str.replace(
|
|
212
|
+
return '"' + str.replace(QUOTE_REGEXP, '\\$1') + '"'
|
|
201
213
|
}
|
|
202
214
|
|
|
203
215
|
/**
|
|
204
216
|
* Class to represent a content type.
|
|
205
217
|
* @private
|
|
206
218
|
*/
|
|
207
|
-
function ContentType(type) {
|
|
219
|
+
function ContentType (type) {
|
|
208
220
|
this.parameters = Object.create(null)
|
|
209
221
|
this.type = type
|
|
210
222
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "content-type",
|
|
3
3
|
"description": "Create and parse HTTP Content-Type header",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.4",
|
|
5
5
|
"author": "Douglas Christopher Wilson <doug@somethingdoug.com>",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"keywords": [
|
|
@@ -13,7 +13,13 @@
|
|
|
13
13
|
],
|
|
14
14
|
"repository": "jshttp/content-type",
|
|
15
15
|
"devDependencies": {
|
|
16
|
-
"
|
|
16
|
+
"eslint": "3.19.0",
|
|
17
|
+
"eslint-config-standard": "10.2.1",
|
|
18
|
+
"eslint-plugin-import": "2.7.0",
|
|
19
|
+
"eslint-plugin-node": "5.1.1",
|
|
20
|
+
"eslint-plugin-promise": "3.5.0",
|
|
21
|
+
"eslint-plugin-standard": "3.0.1",
|
|
22
|
+
"istanbul": "0.4.5",
|
|
17
23
|
"mocha": "~1.21.5"
|
|
18
24
|
},
|
|
19
25
|
"files": [
|
|
@@ -26,6 +32,7 @@
|
|
|
26
32
|
"node": ">= 0.6"
|
|
27
33
|
},
|
|
28
34
|
"scripts": {
|
|
35
|
+
"lint": "eslint .",
|
|
29
36
|
"test": "mocha --reporter spec --check-leaks --bail test/",
|
|
30
37
|
"test-ci": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/",
|
|
31
38
|
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/"
|