content-disposition
Advanced tools
+118
-40
@@ -18,8 +18,8 @@ /*! | ||
| /** | ||
| * Module dependencies. | ||
| * TextDecoder instance for UTF-8 decoding when decodeURIComponent fails due to invalid byte sequences. | ||
| * @type {TextDecoder} | ||
| * @private | ||
| */ | ||
| const utf8Decoder = new TextDecoder('utf-8') | ||
| var basename = require('path').basename | ||
| /** | ||
@@ -33,10 +33,2 @@ * RegExp to match non attr-char, *after* encodeURIComponent (i.e. not including "%") | ||
| /** | ||
| * RegExp to match percent encoding escape. | ||
| * @private | ||
| */ | ||
| var HEX_ESCAPE_REGEXP = /%[0-9A-Fa-f]{2}/ | ||
| var HEX_ESCAPE_REPLACE_REGEXP = /%([0-9A-Fa-f]{2})/g | ||
| /** | ||
| * RegExp to match non-latin1 characters. | ||
@@ -204,3 +196,3 @@ * @private | ||
| // set extended filename parameter | ||
| if (hasFallback || !isQuotedString || HEX_ESCAPE_REGEXP.test(name)) { | ||
| if (hasFallback || !isQuotedString || hasHexEscape(name)) { | ||
| params['filename*'] = name | ||
@@ -268,3 +260,3 @@ } | ||
| function decodefield (str) { | ||
| var match = EXT_VALUE_REGEXP.exec(str) | ||
| const match = EXT_VALUE_REGEXP.exec(str) | ||
@@ -275,22 +267,31 @@ if (!match) { | ||
| var charset = match[1].toLowerCase() | ||
| var encoded = match[2] | ||
| var value | ||
| const charset = match[1].toLowerCase() | ||
| const encoded = match[2] | ||
| // to binary string | ||
| var binary = encoded.replace(HEX_ESCAPE_REPLACE_REGEXP, pdecode) | ||
| switch (charset) { | ||
| case 'iso-8859-1': | ||
| value = getlatin1(binary) | ||
| break | ||
| { | ||
| const binary = decodeHexEscapes(encoded) | ||
| return getlatin1(binary) | ||
| } | ||
| case 'utf-8': | ||
| case 'utf8': | ||
| value = Buffer.from(binary, 'binary').toString('utf8') | ||
| break | ||
| default: | ||
| throw new TypeError('unsupported charset in extended field') | ||
| { | ||
| try { | ||
| return decodeURIComponent(encoded) | ||
| } catch { | ||
| // Failed to decode with decodeURIComponent, fallback to lenient decoding which replaces invalid UTF-8 byte sequences with the Unicode replacement character | ||
| // TODO: Consider removing in the next major version to be more strict about invalid percent-encodings | ||
| const binary = decodeHexEscapes(encoded) | ||
| const bytes = new Uint8Array(binary.length) | ||
| for (let idx = 0; idx < binary.length; idx++) { | ||
| bytes[idx] = binary.charCodeAt(idx) | ||
| } | ||
| return utf8Decoder.decode(bytes) | ||
| } | ||
| } | ||
| } | ||
| return value | ||
| throw new TypeError('unsupported charset in extended field') | ||
| } | ||
@@ -392,15 +393,2 @@ | ||
| /** | ||
| * Percent decode a single character. | ||
| * | ||
| * @param {string} str | ||
| * @param {string} hex | ||
| * @return {string} | ||
| * @private | ||
| */ | ||
| function pdecode (str, hex) { | ||
| return String.fromCharCode(parseInt(hex, 16)) | ||
| } | ||
| /** | ||
| * Percent encode a single character. | ||
@@ -465,1 +453,91 @@ * | ||
| } | ||
| /** | ||
| * Return the last portion of a path | ||
| * | ||
| * @param {string} path | ||
| * @returns {string} | ||
| */ | ||
| function basename (path) { | ||
| const normalized = path.replaceAll('\\', '/') | ||
| let end = normalized.length | ||
| while (end > 0 && normalized[end - 1] === '/') { | ||
| end-- | ||
| } | ||
| if (end === 0) { | ||
| return '' | ||
| } | ||
| let start = end - 1 | ||
| while (start >= 0 && normalized[start] !== '/') { | ||
| start-- | ||
| } | ||
| return normalized.slice(start + 1, end) | ||
| } | ||
| /** | ||
| * Check if a character is a hex digit [0-9A-Fa-f] | ||
| * | ||
| * @param {string} char | ||
| * @return {boolean} | ||
| * @private | ||
| */ | ||
| function isHexDigit (char) { | ||
| const code = char.charCodeAt(0) | ||
| return ( | ||
| (code >= 48 && code <= 57) || // 0-9 | ||
| (code >= 65 && code <= 70) || // A-F | ||
| (code >= 97 && code <= 102) // a-f | ||
| ) | ||
| } | ||
| /** | ||
| * Check if a string contains percent encoding escapes. | ||
| * | ||
| * @param {string} str | ||
| * @return {boolean} | ||
| * @private | ||
| */ | ||
| function hasHexEscape (str) { | ||
| const maxIndex = str.length - 3 | ||
| let lastIndex = -1 | ||
| while ((lastIndex = str.indexOf('%', lastIndex + 1)) !== -1 && lastIndex <= maxIndex) { | ||
| if (isHexDigit(str[lastIndex + 1]) && isHexDigit(str[lastIndex + 2])) { | ||
| return true | ||
| } | ||
| } | ||
| return false | ||
| } | ||
| /** | ||
| * Decode hex escapes in a string (e.g., %20 -> space) | ||
| * | ||
| * @param {string} str | ||
| * @return {string} | ||
| * @private | ||
| */ | ||
| function decodeHexEscapes (str) { | ||
| const firstEscape = str.indexOf('%') | ||
| if (firstEscape === -1) return str | ||
| let result = str.slice(0, firstEscape) | ||
| for (let idx = firstEscape; idx < str.length; idx++) { | ||
| if ( | ||
| str[idx] === '%' && | ||
| idx + 2 < str.length && | ||
| isHexDigit(str[idx + 1]) && | ||
| isHexDigit(str[idx + 2]) | ||
| ) { | ||
| result += String.fromCharCode(Number.parseInt(str[idx + 1] + str[idx + 2], 16)) | ||
| idx += 2 | ||
| } else { | ||
| result += str[idx] | ||
| } | ||
| } | ||
| return result | ||
| } |
+8
-11
| { | ||
| "name": "content-disposition", | ||
| "description": "Create and parse Content-Disposition header", | ||
| "version": "1.0.1", | ||
| "version": "1.1.0", | ||
| "author": "Douglas Christopher Wilson <doug@somethingdoug.com>", | ||
@@ -20,14 +20,11 @@ "license": "MIT", | ||
| "c8": "^10.1.2", | ||
| "eslint": "7.32.0", | ||
| "eslint-config-standard": "13.0.1", | ||
| "eslint-plugin-import": "2.25.3", | ||
| "eslint-plugin-markdown": "2.2.1", | ||
| "eslint-plugin-node": "11.1.0", | ||
| "eslint-plugin-promise": "5.2.0", | ||
| "eslint-plugin-standard": "4.1.0" | ||
| "eslint": "^8.57.1", | ||
| "eslint-config-standard": "^14.1.1", | ||
| "eslint-plugin-import": "^2.32.0", | ||
| "eslint-plugin-markdown": "^3.0.1", | ||
| "eslint-plugin-node": "^11.1.0", | ||
| "eslint-plugin-promise": "^6.6.0", | ||
| "eslint-plugin-standard": "^4.1.0" | ||
| }, | ||
| "files": [ | ||
| "LICENSE", | ||
| "HISTORY.md", | ||
| "README.md", | ||
| "index.js" | ||
@@ -34,0 +31,0 @@ ], |
+7
-8
@@ -90,3 +90,2 @@ # content-disposition | ||
| const contentDisposition = require('content-disposition') | ||
| const destroy = require('destroy') | ||
| const fs = require('fs') | ||
@@ -107,3 +106,3 @@ const http = require('http') | ||
| onFinished(res, function () { | ||
| destroy(stream) | ||
| stream.destroy() | ||
| }) | ||
@@ -126,5 +125,5 @@ }) | ||
| [rfc-2616]: https://tools.ietf.org/html/rfc2616 | ||
| [rfc-5987]: https://tools.ietf.org/html/rfc5987 | ||
| [rfc-6266]: https://tools.ietf.org/html/rfc6266 | ||
| [rfc-2616]: https://datatracker.ietf.org/doc/html/rfc2616 | ||
| [rfc-5987]: https://datatracker.ietf.org/doc/html/rfc5987 | ||
| [rfc-6266]: https://datatracker.ietf.org/doc/html/rfc6266 | ||
| [tc-2231]: http://greenbytes.de/tech/tc2231/ | ||
@@ -137,10 +136,10 @@ | ||
| [npm-image]: https://img.shields.io/npm/v/content-disposition | ||
| [npm-url]: https://npmjs.org/package/content-disposition | ||
| [npm-url]: https://www.npmjs.com/package/content-disposition | ||
| [node-version-image]: https://img.shields.io/node/v/content-disposition | ||
| [node-version-url]: https://nodejs.org/en/download | ||
| [coveralls-image]: https://img.shields.io/coverallsCoverage/github/jshttp/content-disposition | ||
| [coveralls-url]: https://coveralls.io/r/jshttp/content-disposition?branch=master | ||
| [coveralls-url]: https://coveralls.io/github/jshttp/content-disposition?branch=master | ||
| [downloads-image]: https://img.shields.io/npm/dm/content-disposition | ||
| [downloads-url]: https://npmjs.org/package/content-disposition | ||
| [downloads-url]: https://www.npmjs.com/package/content-disposition | ||
| [github-actions-ci-image]: https://img.shields.io/github/actions/workflow/status/jshttp/content-disposition/ci.yml | ||
| [github-actions-ci-url]: https://github.com/jshttp/content-disposition/actions/workflows/ci.yml |
-72
| 1.0.1 / 2025-11-18 | ||
| ================= | ||
| * Updated `engines` field to Node@18 or higher (fixed reference, see 1.0.0) | ||
| * Remove dependency `safe-buffer` | ||
| 1.0.0 / 2024-08-31 | ||
| ================== | ||
| * drop node <18 | ||
| * allow utf8 as alias for utf-8 | ||
| 0.5.4 / 2021-12-10 | ||
| ================== | ||
| * deps: safe-buffer@5.2.1 | ||
| 0.5.3 / 2018-12-17 | ||
| ================== | ||
| * Use `safe-buffer` for improved Buffer API | ||
| 0.5.2 / 2016-12-08 | ||
| ================== | ||
| * Fix `parse` to accept any linear whitespace character | ||
| 0.5.1 / 2016-01-17 | ||
| ================== | ||
| * perf: enable strict mode | ||
| 0.5.0 / 2014-10-11 | ||
| ================== | ||
| * Add `parse` function | ||
| 0.4.0 / 2014-09-21 | ||
| ================== | ||
| * Expand non-Unicode `filename` to the full ISO-8859-1 charset | ||
| 0.3.0 / 2014-09-20 | ||
| ================== | ||
| * Add `fallback` option | ||
| * Add `type` option | ||
| 0.2.0 / 2014-09-19 | ||
| ================== | ||
| * Reduce ambiguity of file names with hex escape in buggy browsers | ||
| 0.1.2 / 2014-09-19 | ||
| ================== | ||
| * Fix periodic invalid Unicode filename header | ||
| 0.1.1 / 2014-09-19 | ||
| ================== | ||
| * Fix invalid characters appearing in `filename*` parameter | ||
| 0.1.0 / 2014-09-18 | ||
| ================== | ||
| * Make the `filename` argument optional | ||
| 0.0.0 / 2014-09-18 | ||
| ================== | ||
| * Initial release |
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
19928
3.71%442
19.46%4
-20%142
-0.7%