FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

util: add non-throwing MIMEType.parse · nodejs/node@4299cd5 · GitHub

/ node Public

Commit 4299cd5

Browse files
authored andcommitted
util: add non-throwing MIMEType.parse
Similar to `URL.parse(...)`, the `MIMEType.parse(...)` API will return `null` if the input cannot be parsed as opposed to throwing the way the constructor does. Signed-off-by: James M Snell <jasnell@gmail.com> PR-URL: #64965 Reviewed-By: Aviv Keller <me@aviv.sh> Reviewed-By: Filip Skokan <panva.ip@gmail.com> Reviewed-By: René <contact.9a5d6388@renegade334.me.uk>
1 parent 0cf7993 commit 4299cd5

5 files changed

Lines changed: 55 additions & 23 deletions

File tree

‎doc/api/util.md‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1896,6 +1896,18 @@ console.log(JSON.stringify(myMIMES));
18961896
// Prints: ["image/png", "image/gif"]
18971897
```
18981898

1899+
### `MIMEType.parse(string)`
1900+
1901+
<!--
1902+
added: REPLACEME
1903+
-->
1904+
1905+
* `string` {string} The input MIME to parse
1906+
* Returns: {MIMEType|null}
1907+
1908+
Attempts to parse the given `string` as a MIMEType. If the string cannot be
1909+
parsed, `null` is returned.
1910+
18991911
## Class: `util.MIMEParams`
19001912

19011913
<!-- YAML

‎lib/internal/data_url.js‎

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -117,13 +117,8 @@ function dataURLProcessor(dataURL) {
117117
// mimeType.
118118
// 14. If mimeTypeRecord is failure, then set
119119
// mimeTypeRecord to text/plain;charset=US-ASCII.
120-
let mimeTypeRecord;
121-
122-
try {
123-
mimeTypeRecord = new MIMEType(mimeType);
124-
} catch {
125-
mimeTypeRecord = new MIMEType('text/plain;charset=US-ASCII');
126-
}
120+
const mimeTypeRecord = MIMEType.parse(mimeType) ||
121+
new MIMEType('text/plain;charset=US-ASCII');
127122

128123
// 15. Return a new data: URL struct whose MIME
129124
// type is mimeTypeRecord and body is body.

‎lib/internal/inspector/network.js‎

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,16 +52,9 @@ function getNextRequestId() {
5252
};
5353

5454
function sniffMimeType(contentType) {
55-
let mimeType;
56-
let charset;
57-
try {
58-
const mimeTypeObj = new MIMEType(contentType);
59-
mimeType = StringPrototypeToLowerCase(mimeTypeObj.essence || '');
60-
charset = StringPrototypeToLowerCase(mimeTypeObj.params.get('charset') || '');
61-
} catch {
62-
mimeType = '';
63-
charset = '';
64-
}
55+
const mimeTypeObj = MIMEType.parse(contentType);
56+
const mimeType = StringPrototypeToLowerCase(mimeTypeObj?.essence || '');
57+
const charset = StringPrototypeToLowerCase(mimeTypeObj?.params.get('charset') || '');
6558

6659
return {
6760
__proto__: null,

‎lib/internal/mime.js‎

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@ const {
1010
StringPrototypeIndexOf,
1111
StringPrototypeSlice,
1212
StringPrototypeToLowerCase,
13+
Symbol,
1314
SymbolIterator,
1415
} = primordials;
1516
const {
17+
ERR_ILLEGAL_CONSTRUCTOR,
1618
ERR_INVALID_MIME_SYNTAX,
1719
} = require('internal/errors').codes;
1820

@@ -22,6 +24,8 @@ const NOT_HTTP_QUOTED_STRING_CODE_POINT = /[^\t\u0020-~\u0080-\u00FF]/g;
2224
const END_BEGINNING_WHITESPACE = /[^\r\n\t ]|$/;
2325
const START_ENDING_WHITESPACE = /[\r\n\t ]*$/;
2426

27+
const kNoThrow = Symbol('kNoThrow');
28+
2529
function toASCIILower(str) {
2630
// eslint-disable-next-line no-control-regex
2731
if (!/[^\x00-\x7f]/.test(str)) return StringPrototypeToLowerCase(str);
@@ -39,7 +43,7 @@ function toASCIILower(str) {
3943
const SOLIDUS = '/';
4044
const SEMICOLON = ';';
4145

42-
function parseTypeAndSubtype(str) {
46+
function parseTypeAndSubtype(str, noThrow = null) {
4347
// Skip only HTTP whitespace from start
4448
let position = SafeStringPrototypeSearch(str, END_BEGINNING_WHITESPACE);
4549
// read until '/'
@@ -50,6 +54,7 @@ function parseTypeAndSubtype(str) {
5054
const invalidTypeIndex = SafeStringPrototypeSearch(trimmedType,
5155
NOT_HTTP_TOKEN_CODE_POINT);
5256
if (trimmedType === '' || invalidTypeIndex !== -1 || typeEnd === -1) {
57+
if (noThrow === kNoThrow) return null;
5358
throw new ERR_INVALID_MIME_SYNTAX('type', str, invalidTypeIndex);
5459
}
5560
// skip type and '/'
@@ -72,6 +77,7 @@ function parseTypeAndSubtype(str) {
7277
const invalidSubtypeIndex = SafeStringPrototypeSearch(trimmedSubtype,
7378
NOT_HTTP_TOKEN_CODE_POINT);
7479
if (trimmedSubtype === '' || invalidSubtypeIndex !== -1) {
80+
if (noThrow === kNoThrow) return null;
7581
throw new ERR_INVALID_MIME_SYNTAX('subtype', str, invalidSubtypeIndex);
7682
}
7783
const subtype = toASCIILower(trimmedSubtype);
@@ -335,12 +341,24 @@ class MIMEType {
335341
#type;
336342
#subtype;
337343
#parameters;
338-
constructor(string) {
344+
constructor(string, noThrowSymbol = null) {
339345
string = `${string}`;
340-
const data = parseTypeAndSubtype(string);
341-
this.#type = data[0];
342-
this.#subtype = data[1];
343-
this.#parameters = instantiateMimeParams(StringPrototypeSlice(string, data[2]));
346+
// noThrowSymbol can be null or kNoThrow, but not any other value
347+
if (noThrowSymbol != null && noThrowSymbol !== kNoThrow) {
348+
throw new ERR_ILLEGAL_CONSTRUCTOR();
349+
}
350+
const data = parseTypeAndSubtype(string, noThrowSymbol);
351+
if (data != null) {
352+
this.#type = data[0];
353+
this.#subtype = data[1];
354+
this.#parameters = instantiateMimeParams(StringPrototypeSlice(string, data[2]));
355+
}
356+
}
357+
358+
// Like the constructor, but returns null instead of throwing on invalid input.
359+
static parse(string) {
360+
const mt = new MIMEType(string, kNoThrow);
361+
return mt.type ? mt : null;
344362
}
345363

346364
get type() {

‎test/parallel/test-mime-api.js‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,3 +185,17 @@ assert.throws(() => params.set('x', `x${NOT_HTTP_QUOTED_STRING_CODE_POINT}`), /p
185185
assert.strictEqual(params.has('foo'), false);
186186
assert.deepStrictEqual([...params], []);
187187
}
188+
189+
{
190+
// Non-throwing MimeType.parse, works for valid
191+
const mime = MIMEType.parse('text/plain;Charset=value');
192+
assert.strictEqual(mime.params.get('Charset'), 'value');
193+
assert.strictEqual(mime.params.get('charset'), 'value');
194+
assert.strictEqual(mime.params.get('CHARSET'), 'value');
195+
assert.strictEqual(mime.params.has('Charset'), true);
196+
assert.strictEqual(`${mime.params}`, 'charset=value');
197+
198+
// Returns null on Invalid
199+
const invalidMime = MIMEType.parse('text plain');
200+
assert.strictEqual(invalidMime, null);
201+
}

0 commit comments

Comments
 (0)

Back | FazBrowse Home | New Git URL