Skip to content

Commit 0057e10

Browse files
authored
support parsing charset (#34)
* support parsing charset * remove unused lookaround
1 parent 4c55865 commit 0057e10

File tree

4 files changed

+67
-8
lines changed

4 files changed

+67
-8
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
**/node_modules
22
**/package-lock.json
3+
**/yarn.lock
34

45
coverage.*
56

API.md

+6-3
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,17 @@
55

66
### `type(header)`
77

8-
Generates an object containing the associated mime-type and the boundary (if specified).
8+
Generates an object containing the associated mime-type, charset and the boundary (if specified).
99

1010
```js
1111
Content.type('application/json; some=property; and="another"');
1212
// { mime: 'application/json' }
1313

14-
Content.type('application/json; boundary=asdf');
15-
// { mime: 'application/json', boundary: 'asdf' }
14+
Content.type('text/html; charset=utf-8')
15+
// { mime: 'text/html', charset: 'utf-8' }
16+
17+
Content.type('multipart/form-data; boundary=asdf');
18+
// { mime: 'multipart/form-data', boundary: 'asdf' }
1619
```
1720

1821
If the header is invalid (malformed) or missing required data, such as a `multipart/form-data` header missing its `boundary`, it returns an HTTP `Bad Request` error.

lib/index.js

+14-4
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,11 @@ const internals = {};
1818
// 1: type/subtype 2: params
1919
internals.contentTypeRegex = /^([^\/\s]+\/[^\s;]+)(.*)?$/;
2020

21-
// 1: "b" 2: b
22-
internals.paramsRegex = /;\s*boundary=(?:"([^"]+)"|([^;"\s]+))/i;
21+
// 1: "b" 2: b
22+
internals.charsetParamRegex = /;\s*charset=(?:"([^"]+)"|([^;"\s]+))/i;
23+
24+
// 1: "b" 2: b
25+
internals.boundaryParamRegex = /;\s*boundary=(?:"([^"]+)"|([^;"\s]+))/i;
2326

2427

2528
exports.type = function (header) {
@@ -37,10 +40,17 @@ exports.type = function (header) {
3740
mime: match[1].toLowerCase()
3841
};
3942

43+
const params = match[2];
44+
if (params) {
45+
const param = params.match(internals.charsetParamRegex);
46+
if (param) {
47+
result.charset = (param[1] || param[2]).toLowerCase();
48+
}
49+
}
50+
4051
if (result.mime.indexOf('multipart/') === 0) {
41-
const params = match[2];
4252
if (params) {
43-
const param = params.match(internals.paramsRegex);
53+
const param = params.match(internals.boundaryParamRegex);
4454
if (param) {
4555
result.boundary = param[1] || param[2];
4656
}

test/index.js

+46-1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,43 @@ describe('type()', () => {
4949
expect(type.boundary).to.equal('abcdefghijklm');
5050
});
5151

52+
it('parses header (charset)', () => {
53+
54+
const type = Content.type('application/json; charset=utf-8');
55+
expect(type.mime).to.equal('application/json');
56+
expect(type.charset).to.equal('utf-8');
57+
});
58+
59+
it('parses header (quoted charset)', () => {
60+
61+
const type = Content.type('application/json; charset="iso-8859-1"');
62+
expect(type.mime).to.equal('application/json');
63+
expect(type.charset).to.equal('iso-8859-1');
64+
});
65+
66+
it('parses header (charset and boundary)', () => {
67+
68+
const type = Content.type('multipart/form-data; charset=utf-8; boundary=abcdefghijklm');
69+
expect(type.mime).to.equal('multipart/form-data');
70+
expect(type.charset).to.equal('utf-8');
71+
expect(type.boundary).to.equal('abcdefghijklm');
72+
});
73+
74+
it('parses header (boundary and charset)', () => {
75+
76+
const type = Content.type('multipart/form-data; boundary=abcdefghijklm; charset=utf-8');
77+
expect(type.mime).to.equal('multipart/form-data');
78+
expect(type.charset).to.equal('utf-8');
79+
expect(type.boundary).to.equal('abcdefghijklm');
80+
});
81+
82+
it('parses header (uppercase)', () => {
83+
84+
const type = Content.type('TEXT/HTML; CHARSET=EUC-KR');
85+
expect(type.mime).to.equal('text/html');
86+
expect(type.charset).to.equal('euc-kr');
87+
});
88+
5289
it('handles large number of OWS', () => {
5390

5491
const now = Date.now();
@@ -78,7 +115,15 @@ describe('type()', () => {
78115

79116
it('handles multiple boundary params', () => {
80117

81-
const header = '0/\\x00;boundary=#;boundary=#;boundary=#;boundary=#;boundary=#;boundary=#;boundary=#;boundary=#;boundary=#;boundary=#;boundary=#;boundary=#;boundary=#;boundary=#;boundary=#;boundary=#;boundary=#;boundary=#;boundary=#;boundary=#;boundary=#;boundary=#;boundary=#;boundary=#;boundary=#;boundary=#"';
118+
const header = `multipart/form-data ${new Array(80000).join(';boundary=#')}`;
119+
const now = Date.now();
120+
Content.type(header);
121+
expect(Date.now() - now).to.be.below(100);
122+
});
123+
124+
it('handles multiple charset params', () => {
125+
126+
const header = `text/plain ${new Array(80000).join(';charset=utf-8')}`;
82127
const now = Date.now();
83128
Content.type(header);
84129
expect(Date.now() - now).to.be.below(100);

0 commit comments

Comments
 (0)