From aedadba0efd67ee42967f08c8927fc3c1bcd11df Mon Sep 17 00:00:00 2001 From: Bradley Farias Date: Tue, 18 Oct 2022 21:26:16 -0500 Subject: [PATCH] util: add MIME utilities (#21128) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Rich Trott Co-authored-by: Antoine du Hamel PR-URL: https://github.com/nodejs/node/pull/21128 Reviewed-By: Gus Caplan Reviewed-By: Matteo Collina Reviewed-By: Robert Nagy Reviewed-By: Jacob Smith Reviewed-By: Michaël Zasso Reviewed-By: Geoffrey Booth Reviewed-By: James M Snell --- doc/api/errors.md | 6 + doc/api/util.md | 353 ++ doc/contributing/primordials.md | 17 +- lib/internal/errors.js | 4 + lib/internal/mime.js | 367 ++ lib/internal/per_context/primordials.js | 147 + lib/util.js | 3 + test/fixtures/mime-whatwg-generated.js | 3533 +++++++++++++++++ test/fixtures/mime-whatwg.js | 392 ++ test/parallel/test-bootstrap-modules.js | 1 + .../test-eslint-avoid-prototype-pollution.js | 4 +- test/parallel/test-mime-api.js | 160 + test/parallel/test-mime-whatwg.js | 23 + test/parallel/test-primordials-regexp.js | 119 + tools/doc/type-parser.mjs | 2 + .../eslint-rules/avoid-prototype-pollution.js | 9 +- 16 files changed, 5123 insertions(+), 17 deletions(-) create mode 100644 lib/internal/mime.js create mode 100644 test/fixtures/mime-whatwg-generated.js create mode 100644 test/fixtures/mime-whatwg.js create mode 100644 test/parallel/test-mime-api.js create mode 100644 test/parallel/test-mime-whatwg.js create mode 100644 test/parallel/test-primordials-regexp.js diff --git a/doc/api/errors.md b/doc/api/errors.md index 9bb467af7fc78e..e1e1b92f654505 100644 --- a/doc/api/errors.md +++ b/doc/api/errors.md @@ -1967,6 +1967,12 @@ An invalid HTTP token was supplied. An IP address is not valid. + + +### `ERR_INVALID_MIME_SYNTAX` + +The syntax of a MIME is not valid. + ### `ERR_INVALID_MODULE` diff --git a/doc/api/util.md b/doc/api/util.md index 207e5abed617b7..e3e86899089310 100644 --- a/doc/api/util.md +++ b/doc/api/util.md @@ -1024,6 +1024,355 @@ Otherwise, returns `false`. See [`assert.deepStrictEqual()`][] for more information about deep strict equality. +## Class: `util.MIMEType` + + + +> Stability: 1 - Experimental + +An implementation of [the MIMEType class](https://bmeck.github.io/node-proposal-mime-api/). + +In accordance with browser conventions, all properties of `MIMEType` objects +are implemented as getters and setters on the class prototype, rather than as +data properties on the object itself. + +A MIME string is a structured string containing multiple meaningful +components. When parsed, a `MIMEType` object is returned containing +properties for each of these components. + +### Constructor: `new MIMEType(input)` + +* `input` {string} The input MIME to parse + +Creates a new `MIMEType` object by parsing the `input`. + +```mjs +import { MIMEType } from 'node:util'; + +const myMIME = new MIMEType('text/plain'); +``` + +```cjs +const { MIMEType } = require('node:util'); + +const myMIME = new MIMEType('text/plain'); +``` + +A `TypeError` will be thrown if the `input` is not a valid MIME. Note +that an effort will be made to coerce the given values into strings. For +instance: + +```mjs +import { MIMEType } from 'node:util'; +const myMIME = new MIMEType({ toString: () => 'text/plain' }); +console.log(String(myMIME)); +// Prints: text/plain +``` + +```cjs +const { MIMEType } = require('node:util'); +const myMIME = new MIMEType({ toString: () => 'text/plain' }); +console.log(String(myMIME)); +// Prints: text/plain +``` + +#### `mime.type` + +* {string} + +Gets and sets the type portion of the MIME. + +```mjs +import { MIMEType } from 'node:util'; + +const myMIME = new MIMEType('text/javascript'); +console.log(myMIME.type); +// Prints: text +myMIME.type = 'application'; +console.log(myMIME.type); +// Prints: application +console.log(String(myMIME)); +// Prints: application/javascript +``` + +```cjs +const { MIMEType } = require('node:util'); + +const myMIME = new MIMEType('text/javascript'); +console.log(myMIME.type); +// Prints: text +myMIME.type = 'application'; +console.log(myMIME.type); +// Prints: application +console.log(String(myMIME)); +// Prints: application/javascript/javascript +``` + +#### `mime.subtype` + +* {string} + +Gets and sets the subtype portion of the MIME. + +```mjs +import { MIMEType } from 'node:util'; + +const myMIME = new MIMEType('text/ecmascript'); +console.log(myMIME.subtype); +// Prints: ecmascript +myMIME.subtype = 'javascript'; +console.log(myMIME.subtype); +// Prints: javascript +console.log(String(myMIME)); +// Prints: text/javascript +``` + +```cjs +const { MIMEType } = require('node:util'); + +const myMIME = new MIMEType('text/ecmascript'); +console.log(myMIME.subtype); +// Prints: ecmascript +myMIME.subtype = 'javascript'; +console.log(myMIME.subtype); +// Prints: javascript +console.log(String(myMIME)); +// Prints: text/javascript +``` + +#### `mime.essence` + +* {string} + +Gets the essence of the MIME. This property is read only. +Use `mime.type` or `mime.subtype` to alter the MIME. + +```mjs +import { MIMEType } from 'node:util'; + +const myMIME = new MIMEType('text/javascript;key=value'); +console.log(myMIME.essence); +// Prints: text/javascript +myMIME.type = 'application'; +console.log(myMIME.essence); +// Prints: application/javascript +console.log(String(myMIME)); +// Prints: application/javascript;key=value +``` + +```cjs +const { MIMEType } = require('node:util'); + +const myMIME = new MIMEType('text/javascript;key=value'); +console.log(myMIME.essence); +// Prints: text/javascript +myMIME.type = 'application'; +console.log(myMIME.essence); +// Prints: application/javascript +console.log(String(myMIME)); +// Prints: application/javascript;key=value +``` + +#### `mime.params` + +* {MIMEParams} + +Gets the [`MIMEParams`][] object representing the +parameters of the MIME. This property is read-only. See +[`MIMEParams`][] documentation for details. + +#### `mime.toString()` + +* Returns: {string} + +The `toString()` method on the `MIMEType` object returns the serialized MIME. + +Because of the need for standard compliance, this method does not allow users +to customize the serialization process of the MIME. + +#### `mime.toJSON()` + +* Returns: {string} + +Alias for [`mime.toString()`][]. + +This method is automatically called when an `MIMEType` object is serialized +with [`JSON.stringify()`][]. + +```mjs +import { MIMEType } from 'node:util'; + +const myMIMES = [ + new MIMEType('image/png'), + new MIMEType('image/gif'), +]; +console.log(JSON.stringify(myMIMES)); +// Prints: ["image/png", "image/gif"] +``` + +```cjs +const { MIMEType } = require('node:util'); + +const myMIMES = [ + new MIMEType('image/png'), + new MIMEType('image/gif'), +]; +console.log(JSON.stringify(myMIMES)); +// Prints: ["image/png", "image/gif"] +``` + +### Class: `util.MIMEParams` + + + +The `MIMEParams` API provides read and write access to the parameters of a +`MIMEType`. + +#### Constructor: `new MIMEParams()` + +Creates a new `MIMEParams` object by with empty parameters + +```mjs +import { MIMEParams } from 'node:util'; + +const myParams = new MIMEParams(); +``` + +```cjs +const { MIMEParams } = require('node:util'); + +const myParams = new MIMEParams(); +``` + +#### `mimeParams.delete(name)` + +* `name` {string} + +Remove all name-value pairs whose name is `name`. + +#### `mimeParams.entries()` + +* Returns: {Iterator} + +Returns an iterator over each of the name-value pairs in the parameters. +Each item of the iterator is a JavaScript `Array`. The first item of the array +is the `name`, the second item of the array is the `value`. + +#### `mimeParams.get(name)` + +* `name` {string} +* Returns: {string} or `null` if there is no name-value pair with the given + `name`. + +Returns the value of the first name-value pair whose name is `name`. If there +are no such pairs, `null` is returned. + +#### `mimeParams.has(name)` + +* `name` {string} +* Returns: {boolean} + +Returns `true` if there is at least one name-value pair whose name is `name`. + +#### `mimeParams.keys()` + +* Returns: {Iterator} + +Returns an iterator over the names of each name-value pair. + +```mjs +import { MIMEType } from 'node:util'; + +const { params } = new MIMEType('text/plain;foo=0;bar=1'); +for (const name of params.keys()) { + console.log(name); +} +// Prints: +// foo +// bar +``` + +```cjs +const { MIMEType } = require('node:util'); + +const { params } = new MIMEType('text/plain;foo=0;bar=1'); +for (const name of params.keys()) { + console.log(name); +} +// Prints: +// foo +// bar +``` + +#### `mimeParams.set(name, value)` + +* `name` {string} +* `value` {string} + +Sets the value in the `MIMEParams` object associated with `name` to +`value`. If there are any pre-existing name-value pairs whose names are `name`, +set the first such pair's value to `value`. + +```mjs +import { MIMEType } from 'node:util'; + +const { params } = new MIMEType('text/plain;foo=0;bar=1'); +params.set('foo', 'def'); +params.set('baz', 'xyz'); +console.log(params.toString()); +// Prints: foo=def&bar=1&baz=xyz +``` + +```cjs +const { MIMEType } = require('node:util'); + +const { params } = new MIMEType('text/plain;foo=0;bar=1'); +params.set('foo', 'def'); +params.set('baz', 'xyz'); +console.log(params.toString()); +// Prints: foo=def&bar=1&baz=xyz +``` + +#### `mimeParams.values()` + +* Returns: {Iterator} + +Returns an iterator over the values of each name-value pair. + +#### `mimeParams[@@iterator]()` + +* Returns: {Iterator} + +Alias for [`mimeParams.entries()`][]. + +```mjs +import { MIMEType } from 'node:util'; + +const { params } = new MIMEType('text/plain;foo=bar;xyz=baz'); +for (const [name, value] of params) { + console.log(name, value); +} +// Prints: +// foo bar +// xyz baz +``` + +```cjs +const { MIMEType } = require('node:util'); + +const { params } = new MIMEType('text/plain;foo=bar;xyz=baz'); +for (const [name, value] of params) { + console.log(name, value); +} +// Prints: +// foo bar +// xyz baz +``` + ## `util.parseArgs([config])`