Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@tinyhttp/content-disposition

Package Overview
Dependencies
Maintainers
1
Versions
41
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@tinyhttp/content-disposition - npm Package Compare versions

Comparing version 2.2.1 to 2.2.2

2

dist/index.d.ts
export declare class ContentDisposition {
type: string;
parameters: Record<string, unknown>;
constructor(type: string, parameters: Record<string, unknown>);
constructor(type: string, parameters: Record<string, string | undefined | boolean>);
}

@@ -6,0 +6,0 @@ /**

@@ -0,1 +1,2 @@

// biome-ignore lint/suspicious/noControlCharactersInRegex: <explanation>
const ENCODE_URL_ATTR_CHAR_REGEXP = /[\x00-\x20"'()*,/:;<=>?@[\\\]{}\x7f]/g;

@@ -5,132 +6,158 @@ const HEX_ESCAPE_REGEXP = /%[0-9A-Fa-f]{2}/;

const NON_LATIN1_REGEXP = /[^\x20-\x7e\xa0-\xff]/g;
// biome-ignore lint/suspicious/noControlCharactersInRegex: <explanation>
const QESC_REGEXP = /\\([\u0000-\u007f])/g;
const QUOTE_REGEXP = /([\\"])/g;
const PARAM_REGEXP = (
// biome-ignore lint/suspicious/noControlCharactersInRegex: <explanation>
/;[\x09\x20]*([!#$%&'*+.0-9A-Z^_`a-z|~-]+)[\x09\x20]*=[\x09\x20]*("(?:[\x20!\x23-\x5b\x5d-\x7e\x80-\xff]|\\[\x20-\x7e])*"|[!#$%&'*+.0-9A-Z^_`a-z|~-]+)[\x09\x20]*/g
);
const PARAM_REGEXP =
// biome-ignore lint/suspicious/noControlCharactersInRegex: <explanation>
/;[\x09\x20]*([!#$%&'*+.0-9A-Z^_`a-z|~-]+)[\x09\x20]*=[\x09\x20]*("(?:[\x20!\x23-\x5b\x5d-\x7e\x80-\xff]|\\[\x20-\x7e])*"|[!#$%&'*+.0-9A-Z^_`a-z|~-]+)[\x09\x20]*/g;
const TEXT_REGEXP = /^[\x20-\x7e\x80-\xff]+$/;
const TOKEN_REGEXP = /^[!#$%&'*+.0-9A-Z^_`a-z|~-]+$/;
const EXT_VALUE_REGEXP = /^([A-Za-z0-9!#$%&+\-^_`{}~]+)'(?:[A-Za-z]{2,3}(?:-[A-Za-z]{3}){0,3}|[A-Za-z]{4,8}|)'((?:%[0-9A-Fa-f]{2}|[A-Za-z0-9!#$&+.^_`|~-])+)$/;
// biome-ignore lint/suspicious/noControlCharactersInRegex: <explanation>
const DISPOSITION_TYPE_REGEXP = /^([!#$%&'*+.0-9A-Z^_`a-z|~-]+)[\x09\x20]*(?:$|;)/;
const getlatin1 = (val) => {
return String(val).replace(NON_LATIN1_REGEXP, "?");
// simple Unicode -> ISO-8859-1 transformation
return String(val).replace(NON_LATIN1_REGEXP, '?');
};
class ContentDisposition {
constructor(type, parameters) {
this.type = type;
this.parameters = parameters;
}
export class ContentDisposition {
constructor(type, parameters) {
this.type = type;
this.parameters = parameters;
}
}
const qstring = (val) => `"${String(val).replace(QUOTE_REGEXP, "\\$1")}"`;
const qstring = (val) => `"${String(val).replace(QUOTE_REGEXP, '\\$1')}"`;
const pencode = (char) => `%${String(char).charCodeAt(0).toString(16).toUpperCase()}`;
function ustring(val) {
const str = String(val);
const encoded = encodeURIComponent(str).replace(ENCODE_URL_ATTR_CHAR_REGEXP, pencode);
return `UTF-8''${encoded}`;
const str = String(val);
// percent encode as UTF-8
const encoded = encodeURIComponent(str).replace(ENCODE_URL_ATTR_CHAR_REGEXP, pencode);
return `UTF-8''${encoded}`;
}
const basename = (str) => str.slice(str.lastIndexOf("/") + 1);
function format({
parameters,
type
}) {
if (!type || typeof type !== "string" || !TOKEN_REGEXP.test(type)) {
throw new TypeError("invalid type");
}
let string = String(type).toLowerCase();
if (parameters && typeof parameters === "object") {
const params = Object.keys(parameters).sort();
for (const param of params) {
const val = param.slice(-1) === "*" ? ustring(parameters[param]) : qstring(parameters[param]);
string += `; ${param}=${val}`;
const basename = (str) => str.slice(str.lastIndexOf('/') + 1);
function format({ parameters, type }) {
if (!type || typeof type !== 'string' || !TOKEN_REGEXP.test(type)) {
throw new TypeError('invalid type');
}
}
return string;
// start with normalized type
let string = String(type).toLowerCase();
// append parameters
if (parameters && typeof parameters === 'object') {
const params = Object.keys(parameters).sort();
for (const param of params) {
const val = param.slice(-1) === '*' ? ustring(parameters[param]) : qstring(parameters[param]);
string += `; ${param}=${val}`;
}
}
return string;
}
function createParams(filename, fallback) {
if (filename === void 0) return;
const params = {};
if (!fallback) fallback = true;
if (typeof fallback === "string" && NON_LATIN1_REGEXP.test(fallback)) {
throw new TypeError("fallback must be ISO-8859-1 string");
}
const name = basename(filename);
const isQuotedString = TEXT_REGEXP.test(name);
const fallbackName = typeof fallback !== "string" ? fallback && getlatin1(name) : basename(fallback);
const hasFallback = typeof fallbackName === "string" && fallbackName !== name;
if (hasFallback || !isQuotedString || HEX_ESCAPE_REGEXP.test(name)) {
params["filename*"] = name;
}
if (isQuotedString || hasFallback) {
params.filename = hasFallback ? fallbackName : name;
}
return params;
if (filename === undefined)
return {};
const params = {};
// fallback defaults to true
if (!fallback)
fallback = true;
if (typeof fallback === 'string' && NON_LATIN1_REGEXP.test(fallback)) {
throw new TypeError('fallback must be ISO-8859-1 string');
}
// restrict to file base name
const name = basename(filename);
// determine if name is suitable for quoted string
const isQuotedString = TEXT_REGEXP.test(name);
// generate fallback name
const fallbackName = typeof fallback !== 'string' ? fallback && getlatin1(name) : basename(fallback);
const hasFallback = typeof fallbackName === 'string' && fallbackName !== name;
// set extended filename parameter
if (hasFallback || !isQuotedString || HEX_ESCAPE_REGEXP.test(name)) {
params['filename*'] = name;
}
// set filename parameter
if (isQuotedString || hasFallback) {
params.filename = hasFallback ? fallbackName : name;
}
return params;
}
const pdecode = (_str, hex) => String.fromCharCode(Number.parseInt(hex, 16));
function contentDisposition(filename, options = {}) {
return format(new ContentDisposition(options.type || "attachment", createParams(filename, options.fallback)));
/**
* Create an attachment Content-Disposition header.
*
* @param filename file name
* @param options
*/
export function contentDisposition(filename, options = {}) {
// format into string
return format(new ContentDisposition(options.type || 'attachment', createParams(filename, options.fallback)));
}
function decodefield(str) {
const match = EXT_VALUE_REGEXP.exec(str);
if (!match) throw new TypeError("invalid extended field value");
const charset = match[1].toLowerCase();
const encoded = match[2];
let value;
switch (charset) {
case "iso-8859-1":
value = getlatin1(encoded.replace(HEX_ESCAPE_REPLACE_REGEXP, pdecode));
break;
case "utf-8":
try {
value = decodeURIComponent(encoded);
} catch {
throw new TypeError("invalid encoded utf-8");
}
break;
default:
throw new TypeError("unsupported charset in extended field");
}
return value;
const match = EXT_VALUE_REGEXP.exec(str);
if (!match)
throw new TypeError('invalid extended field value');
const charset = match[1].toLowerCase();
const encoded = match[2];
let value;
switch (charset) {
case 'iso-8859-1':
value = getlatin1(encoded.replace(HEX_ESCAPE_REPLACE_REGEXP, pdecode));
break;
case 'utf-8':
try {
value = decodeURIComponent(encoded);
}
catch {
throw new TypeError('invalid encoded utf-8');
}
break;
default:
throw new TypeError('unsupported charset in extended field');
}
return value;
}
function parse(header) {
let match = DISPOSITION_TYPE_REGEXP.exec(header);
if (!match) throw new TypeError("invalid type format");
let index = match[0].length;
const type = match[1].toLowerCase();
let key;
const names = [];
const params = {};
let value;
index = PARAM_REGEXP.lastIndex = match[0].slice(-1) === ";" ? index - 1 : index;
while (match = PARAM_REGEXP.exec(header)) {
if (match.index !== index) throw new TypeError("invalid parameter format");
index += match[0].length;
key = match[1].toLowerCase();
value = match[2];
if (names.indexOf(key) !== -1) {
throw new TypeError("invalid duplicate parameter");
/**
* Parse Content-Disposition header string.
* @param header string
*/
export function parse(header) {
let match = DISPOSITION_TYPE_REGEXP.exec(header);
if (!match)
throw new TypeError('invalid type format');
// normalize type
let index = match[0].length;
const type = match[1].toLowerCase();
let key;
const names = [];
const params = {};
let value;
// calculate index to start at
index = PARAM_REGEXP.lastIndex = match[0].slice(-1) === ';' ? index - 1 : index;
// match parameters
while ((match = PARAM_REGEXP.exec(header))) {
if (match.index !== index)
throw new TypeError('invalid parameter format');
index += match[0].length;
key = match[1].toLowerCase();
value = match[2];
if (names.indexOf(key) !== -1) {
throw new TypeError('invalid duplicate parameter');
}
names.push(key);
if (key.indexOf('*') + 1 === key.length) {
// decode extended value
key = key.slice(0, -1);
value = decodefield(value);
// overwrite existing value
params[key] = value;
continue;
}
if (typeof params[key] === 'string')
continue;
if (value[0] === '"') {
value = value.slice(1, value.length - 1).replace(QESC_REGEXP, '$1');
}
params[key] = value;
}
names.push(key);
if (key.indexOf("*") + 1 === key.length) {
key = key.slice(0, -1);
value = decodefield(value);
params[key] = value;
continue;
if (index !== -1 && index !== header.length) {
throw new TypeError('invalid parameter format');
}
if (typeof params[key] === "string") continue;
if (value[0] === '"') {
value = value.slice(1, value.length - 1).replace(QESC_REGEXP, "$1");
}
params[key] = value;
}
if (index !== -1 && index !== header.length) {
throw new TypeError("invalid parameter format");
}
return new ContentDisposition(type, params);
return new ContentDisposition(type, params);
}
export {
ContentDisposition,
contentDisposition,
parse
};
//# sourceMappingURL=index.js.map
//# sourceMappingURL=index.js.map
{
"name": "@tinyhttp/content-disposition",
"description": "content-disposition rewrite in TypeScript",
"version": "2.2.1",
"version": "2.2.2",
"license": "MIT",

@@ -25,7 +25,5 @@ "homepage": "https://tinyhttp.v1rtl.site",

],
"dependencies": {},
"scripts": {
"dev": "vite",
"build": "vite build"
"build": "tsc"
}
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc