diff --git a/README.md b/README.md index 98cdb90..635f2dc 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ npm install content-type const contentType = require("content-type"); ``` -### contentType.parse(string) +### contentType.parse(string, options?) ```js const obj = contentType.parse("image/svg+xml; charset=utf-8"); @@ -33,6 +33,10 @@ Parse a `Content-Type` header. This will return an object with the following pro The parser is lenient, but will throw a `TypeError` when unable to parse a parameter due to ambiguity. E.g. `foo="` where the quote is unterminated. +#### Options + +- `parameters` (default: `true`): Set to `false` to skip parsing parameters, only returns `type`. + ### contentType.format(obj) ```js diff --git a/src/index.bench.ts b/src/index.bench.ts index 0636571..8065217 100644 --- a/src/index.bench.ts +++ b/src/index.bench.ts @@ -21,6 +21,10 @@ describe("parse", () => { parse(PARAMS_HEADER); }); + bench("simple parameters (options.parameters = false)", () => { + parse(PARAMS_HEADER, { parameters: false }); + }); + bench("quoted and escaped parameters", () => { parse(QUOTED_HEADER); }); diff --git a/src/index.ts b/src/index.ts index 5a536aa..ac3f443 100644 --- a/src/index.ts +++ b/src/index.ts @@ -55,10 +55,17 @@ export function format(obj: ContentType): string { return result; } +/** + * Options for parsing a `Content-Type` header. + */ +export interface ParseOptions { + parameters?: boolean; +} + /** * Parse a `Content-Type` header. */ -export function parse(header: string): ContentType { +export function parse(header: string, options?: ParseOptions): ContentType { const len = header.length; const semiIndex = header.indexOf(";"); const end = semiIndex !== -1 ? semiIndex : len; @@ -66,9 +73,9 @@ export function parse(header: string): ContentType { const valueEnd = trailingOWS(header, valueStart, end); const type = header.slice(valueStart, valueEnd).toLowerCase(); - if (semiIndex === -1) return { type }; + if (semiIndex === -1 || options?.parameters === false) return { type }; - const parameters = parseParameters(header, end, len); + const parameters = parseParameters(header, end + 1, len); return { type, parameters }; } @@ -80,13 +87,16 @@ function parseParameters( const parameters: Record = Object.create(null); parameter: while (index < len) { - index = skipOWS(header, index + 1, len); + index = skipOWS(header, index, len); const keyStart = index; while (index < len) { const char = header[index]; - if (char === ";") continue parameter; + if (char === ";") { + index++; + continue parameter; + } if (char === "=") { const keyEnd = trailingOWS(header, keyStart, index); @@ -94,7 +104,7 @@ function parseParameters( index = skipOWS(header, index + 1, len); - if (header[index] === '"') { + if (index < len && header[index] === '"') { index++; let value = ""; @@ -103,12 +113,11 @@ function parseParameters( if (char === '"') { index = skipOWS(header, index, len); if (index < len && header[index] !== ";") { - throw new TypeError( - `Unexpected characters after parameter at index ${index}`, - ); + throw new TypeError(`Unexpected character at index ${index}`); } parameters[key] = value; + index++; continue parameter; } @@ -131,6 +140,7 @@ function parseParameters( const valueEnd = trailingOWS(header, valueStart, index); parameters[key] = header.slice(valueStart, valueEnd); + index++; continue parameter; } diff --git a/src/parse.spec.ts b/src/parse.spec.ts index fd0bb16..8b20cfe 100644 --- a/src/parse.spec.ts +++ b/src/parse.spec.ts @@ -190,7 +190,7 @@ describe("parse(string)", function () { it("should error on non-OWS after closing quote", function () { assert.throws( parse.bind(null, 'text/plain; foo="bar"baz'), - /Unexpected characters after parameter at index 21/, + /Unexpected character at index 21/, ); }); @@ -213,4 +213,13 @@ describe("parse(string)", function () { }, }); }); + + it("should skip parsing parameters when options.parameters is false", function () { + const type = parse("text/html; charset=utf-8; foo=bar", { + parameters: false, + }); + assert.deepEqual(type, { + type: "text/html", + }); + }); });