Socket
Socket
Sign inDemoInstall

formidable

Package Overview
Dependencies
Maintainers
5
Versions
78
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

formidable - npm Package Compare versions

Comparing version 2.0.0-canary.20200504.1 to 2.0.0-canary.20210330

src/FormidableError.js

37

CHANGELOG.md

@@ -0,19 +1,24 @@

# Changelog
### Unreleased (`canary` & `dev` dist-tags)
* Test only on Node.js >= v10. Support only Node LTS and latest ([#515](https://github.com/node-formidable/node-formidable/pull/515))
* stop using deprecated features ([#516](https://github.com/node-formidable/node-formidable/pull/516), [#472](https://github.com/node-formidable/node-formidable/issues/472), [#406](https://github.com/node-formidable/node-formidable/issues/406))
* throw error during data parsing ([#513](https://github.com/node-formidable/node-formidable/pull/513))
* Array support for fields and files ([#380](https://github.com/node-formidable/node-formidable/pull/380), [#340](https://github.com/node-formidable/node-formidable/pull/340), [#367](https://github.com/node-formidable/node-formidable/pull/367), [#33](https://github.com/node-formidable/node-formidable/issues/33), [#498](https://github.com/node-formidable/node-formidable/issues/498), [#280](https://github.com/node-formidable/node-formidable/issues/280), [#483](https://github.com/node-formidable/node-formidable/issues/483))
* feat: add options.filter ([#716](https://github.com/node-formidable/formidable/pull/716))
* feat: add code and httpCode to most errors ([#686](https://github.com/node-formidable/formidable/pull/686))
* rename: option.hash into option.hashAlgorithm ([#689](https://github.com/node-formidable/formidable/pull/689))
* rename: file.path into file.filepath ([#689](https://github.com/node-formidable/formidable/pull/689))
* rename: file.type into file.mimetype ([#689](https://github.com/node-formidable/formidable/pull/689))
* refactor: split file.name into file.newFilename and file.originalFilename ([#689](https://github.com/node-formidable/formidable/pull/689))
* feat: prevent directory traversal attacks by default ([#689](https://github.com/node-formidable/formidable/pull/689))
* meta: stop including test files in npm ([7003c](https://github.com/node-formidable/formidable/commit/7003cd6133f90c384081accb51743688d5e1f4be))
* fix: handle invalid filenames ([d0a34](https://github.com/node-formidable/formidable/commit/d0a3484b048b8c177e62d66aecb03f5928f7a857))
* feat: add fileWriteStreamHandler option
* feat: add allowEmptyFiles and minFileSize options
* feat: Array support for fields and files ([#380](https://github.com/node-formidable/node-formidable/pull/380), [#340](https://github.com/node-formidable/node-formidable/pull/340), [#367](https://github.com/node-formidable/node-formidable/pull/367), [#33](https://github.com/node-formidable/node-formidable/issues/33), [#498](https://github.com/node-formidable/node-formidable/issues/498), [#280](https://github.com/node-formidable/node-formidable/issues/280), [#483](https://github.com/node-formidable/node-formidable/issues/483))
* possible partial fix of [#386](https://github.com/node-formidable/node-formidable/pull/386) with #380 (need tests and better implementation)
* use hasOwnProperty in check against files/fields ([#522](https://github.com/node-formidable/node-formidable/pull/522))
* do not promote `IncomingForm` and add `exports.default` ([#529](https://github.com/node-formidable/node-formidable/pull/529))
* Improve examples and tests ([#523](https://github.com/node-formidable/node-formidable/pull/523))
* First step of Code quality improvements ([#525](https://github.com/node-formidable/node-formidable/pull/525))
* refactor: use hasOwnProperty in check against files/fields ([#522](https://github.com/node-formidable/node-formidable/pull/522))
* meta: do not promote `IncomingForm` and add `exports.default` ([#529](https://github.com/node-formidable/node-formidable/pull/529))
* meta: Improve examples and tests ([#523](https://github.com/node-formidable/node-formidable/pull/523))
* refactor: First step of Code quality improvements ([#525](https://github.com/node-formidable/node-formidable/pull/525))
* chore(funding): remove patreon & add npm funding field ([#525](https://github.com/node-formidable/node-formidable/pull/532)
* feat: use Modern Streams API ([#531](https://github.com/node-formidable/node-formidable/pull/531))
* fix: remove gently hijack and tests ([#539](https://github.com/node-formidable/node-formidable/pull/539))
* docs: Clarify supported hash algorithms ([#537](https://github.com/node-formidable/node-formidable/pull/537))
* feat: better tests, add Airbnb + Prettier ([#542](https://github.com/node-formidable/node-formidable/pull/542))
* fix(incomingForm): better detection of fields vs files
* fix: resolves [#128](https://github.com/node-formidable/node-formidable/pull/128)
* fix: urlencoded parsing to emit end [#543](https://github.com/node-formidable/node-formidable/pull/543), introduced in [#531](https://github.com/node-formidable/node-formidable/pull/531)

@@ -24,8 +29,6 @@ * fix(tests): include multipart and qs parser unit tests, part of [#415](https://github.com/node-formidable/node-formidable/issues/415)

* feat: introduce Plugins API, fix silent failing tests ([#545](https://github.com/node-formidable/node-formidable/pull/545), [#391](https://github.com/node-formidable/node-formidable/pull/391), [#407](https://github.com/node-formidable/node-formidable/pull/407), [#386](https://github.com/node-formidable/node-formidable/pull/386), [#374](https://github.com/node-formidable/node-formidable/pull/374), [#521](https://github.com/node-formidable/node-formidable/pull/521), [#267](https://github.com/node-formidable/node-formidable/pull/267))
* respect form hash option on incoming octect/stream requests ([#407](https://github.com/node-formidable/node-formidable/pull/407))
* fix: exposing file writable stream errors ([#520](https://github.com/node-formidable/node-formidable/pull/520), [#316](https://github.com/node-formidable/node-formidable/pull/316), [#469](https://github.com/node-formidable/node-formidable/pull/469), [#470](https://github.com/node-formidable/node-formidable/pull/470))
* feat: custom file (re)naming, thru options.filename ([#591](https://github.com/node-formidable/node-formidable/pull/591), [#84](https://github.com/node-formidable/node-formidable/issues/84), [#86](https://github.com/node-formidable/node-formidable/issues/86), [#94](https://github.com/node-formidable/node-formidable/issues/94), [#154](https://github.com/node-formidable/node-formidable/issues/154), [#158](https://github.com/node-formidable/node-formidable/issues/158), [#488](https://github.com/node-formidable/node-formidable/issues/488), [#595](https://github.com/node-formidable/node-formidable/issues/595))
* fix: make opts.filename from #591 work with opts.keepExtensions ([#597](https://github.com/node-formidable/node-formidable/pull/597))
* fix: better handling of nested arrays when options.multiples ([#621](https://github.com/node-formidable/node-formidable/pull/621))
* fix: a regression causing cyrillic to fail ([#624](https://github.com/node-formidable/node-formidable/pull/624), [#623](https://github.com/node-formidable/node-formidable/issues/623))

@@ -32,0 +35,0 @@ ### v1.2.1 (2018-03-20)

{
"name": "formidable",
"version": "2.0.0-canary.20200504.1",
"version": "2.0.0-canary.20210330",
"license": "MIT",

@@ -12,3 +12,5 @@ "description": "A node.js module for parsing form data, especially file uploads.",

"src",
"test"
"CHANGELOG.md",
"LICENSE",
"README.md"
],

@@ -29,5 +31,5 @@ "publishConfig": {

"pretest": "del-cli ./test/tmp && make-dir ./test/tmp",
"test": "node test/run.js",
"test": "jest --coverage",
"pretest:ci": "yarn run pretest",
"test:ci": "nyc node test/run.js",
"test:ci": "nyc jest --coverage",
"test:jest": "jest --coverage"

@@ -39,3 +41,3 @@ },

"once": "1.4.0",
"qs": "^6.9.3"
"qs": "6.9.3"
},

@@ -56,3 +58,3 @@ "devDependencies": {

"koa": "2.11.0",
"lint-staged": "10.1.7",
"lint-staged": "10.2.7",
"make-dir-cli": "2.0.0",

@@ -63,6 +65,7 @@ "nyc": "15.0.1",

"request": "2.88.2",
"supertest": "4.0.2",
"urun": "0.0.8",
"utest": "0.0.8"
"supertest": "4.0.2"
},
"jest": {
"verbose": true
},
"husky": {

@@ -92,3 +95,13 @@ "hooks": {

]
}
},
"keywords": [
"multipart",
"form",
"data",
"querystring",
"www",
"json",
"ulpoad",
"file"
]
}

@@ -67,3 +67,4 @@ <p align="center">

- [Fast (~900-2500 mb/sec)](#benchmarks) & streaming multipart parser
- Automatically writing file uploads to disk (soon optionally)
- Automatically writing file uploads to disk (optional, see
[`options.fileWriteStreamHandler`](#options))
- [Plugins API](#useplugin-plugin) - allowing custom parsers and plugins

@@ -116,3 +117,8 @@ - Low memory footprint

form.parse(req, (err, fields, files) => {
res.writeHead(200, { 'content-type': 'application/json' });
if (err) {
res.writeHead(err.httpCode || 400, { 'Content-Type': 'text/plain' });
res.end(String(err));
return;
}
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ fields, files }, null, 2));

@@ -125,3 +131,3 @@ });

// show a file upload form
res.writeHead(200, { 'content-type': 'text/html' });
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end(`

@@ -211,3 +217,3 @@ <h2>With Node.js <code>"http"</code> module</h2>

// not very elegant, but that's for now if you don't want touse `koa-better-body`
// not very elegant, but that's for now if you don't want to use `koa-better-body`
// or other middlewares.

@@ -317,4 +323,4 @@ await new Promise((resolve, reject) => {

See it's defaults in [src/Formidable.js](./src/Formidable.js#L14-L22) (the
`DEFAULT_OPTIONS` constant).
See it's defaults in [src/Formidable.js DEFAULT_OPTIONS](./src/Formidable.js)
(the `DEFAULT_OPTIONS` constant).

@@ -324,16 +330,29 @@ - `options.encoding` **{string}** - default `'utf-8'`; sets encoding for

- `options.uploadDir` **{string}** - default `os.tmpdir()`; the directory for
placing file uploads in. You can move them later by using `fs.rename()`
placing file uploads in. You can move them later by using `fs.rename()`.
- `options.keepExtensions` **{boolean}** - default `false`; to include the
extensions of the original files or not
- `options.allowEmptyFiles` **{boolean}** - default `true`; allow upload empty
files
- `options.minFileSize` **{number}** - default `1` (1byte); the minium size of
uploaded file.
- `options.maxFileSize` **{number}** - default `200 * 1024 * 1024` (200mb);
limit the size of uploaded file.
- `options.maxFields` **{number}** - default `1000`; limit the number of fields
that the Querystring parser will decode, set 0 for unlimited
- `options.maxFields` **{number}** - default `1000`; limit the number of fields, set 0 for unlimited
- `options.maxFieldsSize` **{number}** - default `20 * 1024 * 1024` (20mb);
limit the amount of memory all fields together (except files) can allocate in
bytes.
- `options.hash` **{boolean}** - default `false`; include checksums calculated
- `options.hashAlgorithm` **{string | false}** - default `false`; include checksums calculated
for incoming files, set this to some hash algorithm, see
[crypto.createHash](https://nodejs.org/api/crypto.html#crypto_crypto_createhash_algorithm_options)
for available algorithms
- `options.fileWriteStreamHandler` **{function}** - default `null`, which by
default writes to host machine file system every file parsed; The function
should return an instance of a
[Writable stream](https://nodejs.org/api/stream.html#stream_class_stream_writable)
that will receive the uploaded file data. With this option, you can have any
custom behavior regarding where the uploaded file data will be streamed for.
If you are looking to write the file uploaded in other types of cloud storages
(AWS S3, Azure blob storage, Google cloud storage) or private file storage,
this is the option you're looking for. When this option is defined the default
behavior of writing the file in the host machine file system is lost.
- `options.multiples` **{boolean}** - default `false`; when you call the

@@ -344,3 +363,11 @@ `.parse` method, the `files` argument (of the callback) will contain arrays of

fields that have names ending with '[]'.
- `options.filename` **{function}** - default `undefined` Use it to control
newFilename. Must return a string. Will be joined with options.uploadDir.
- `options.filter` **{function}** - default function that always returns true.
Use it to filter files before they are uploaded. Must return a boolean.
#### `options.filename` **{function}** function (name, ext, part, form) -> string
_**Note:** If this size of combined fields, or size of some file is exceeded, an

@@ -359,2 +386,16 @@ `'error'` event is fired._

#### `options.filter` **{function}** function ({name, originalFilename, mimetype}) -> boolean
**Note:** use an outside variable to cancel all uploads upon the first error
```js
const options = {
filter: function ({name, originalFilename, mimetype}) {
// keep only images
return mimetype && mimetype.includes("image");
}
};
```
### .parse(request, callback)

@@ -381,2 +422,37 @@

About `uploadDir`, given the following directory structure
```
project-name
├── src
│ └── server.js
└── uploads
└── image.jpg
```
`__dirname` would be the same directory as the source file itself (src)
```js
`${__dirname}/../uploads`
```
to put files in uploads.
Omitting `__dirname` would make the path relative to the current working directory. This would be the same if server.js is launched from src but not project-name.
`null` will use default which is `os.tmpdir()`
Note: If the directory does not exist, the uploaded files are __silently discarded__. To make sure it exists:
```js
import {createNecessaryDirectoriesSync} from "filesac";
const uploadPath = `${__dirname}/../uploads`;
createNecessaryDirectoriesSync(`${uploadPath}/x`);
```
In the example below, we listen on couple of events and direct them to the

@@ -393,8 +469,8 @@ `data` listener, so you can do whatever you choose there, based on whether its

form.on('fileBegin', (filename, file) => {
form.emit('data', { name: 'fileBegin', filename, value: file });
form.on('fileBegin', (formname, file) => {
form.emit('data', { name: 'fileBegin', formname, value: file });
});
form.on('file', (filename, file) => {
form.emit('data', { name: 'file', key: filename, value: file });
form.on('file', (formname, file) => {
form.emit('data', { name: 'file', formname, value: file });
});

@@ -411,3 +487,3 @@

// If you want to customize whatever you want...
form.on('data', ({ name, key, value, buffer, start, end, ...more }) => {
form.on('data', ({ name, key, value, buffer, start, end, formname, ...more }) => {
if (name === 'partBegin') {

@@ -430,6 +506,6 @@ }

if (name === 'file') {
console.log('file:', key, value);
console.log('file:', formname, value);
}
if (name === 'fileBegin') {
console.log('fileBegin:', key, value);
console.log('fileBegin:', formname, value);
}

@@ -489,3 +565,3 @@ });

const form = new Formidable({
hash: 'sha1',
hashAlgorithm: 'sha1',
enabledPlugins: ['octetstream', 'querystring', 'json'],

@@ -527,5 +603,5 @@ });

// let formidable handle only non-file parts
if (part.filename === '' || !part.mime) {
if (part.originalFilename === '' || !part.mimetype) {
// used internally, please do not override!
form.handlePart(part);
form._handlePart(part);
}

@@ -546,16 +622,20 @@ };

// case you are unhappy with the way formidable generates a temporary path for your files.
file.path: string;
file.filepath: string;
// The name this file had according to the uploading client.
file.name: string | null;
file.originalFilename: string | null;
// calculated based on options provided
file.newFilename: string | null;
// The mime type of this file, according to the uploading client.
file.type: string | null;
file.mimetype: string | null;
// A Date object (or `null`) containing the time this file was last written to.
// Mostly here for compatibility with the [W3C File API Draft](http://dev.w3.org/2006/webapi/FileAPI/).
file.lastModifiedDate: Date | null;
file.mtime: Date | null;
// If `options.hash` calculation was set, you can read the hex digest out of this var.
file.hash: string | 'sha1' | 'md5' | 'sha256' | null;
file.hashAlgorithm: false | |'sha1' | 'md5' | 'sha256'
// If `options.hashAlgorithm` calculation was set, you can read the hex digest out of this var (at the end it will be a string)
file.hash: string | object | null;
}

@@ -596,3 +676,10 @@ ```

```js
form.on('fileBegin', (name, file) => {});
form.on('fileBegin', (formName, file) => {
// accessible here
// formName the name in the form (<input name="thisname" type="file">) or http filename for octetstream
// file.originalFilename http filename or null if there was a parsing error
// file.newFilename generated hexoid or what options.filename returned
// file.filepath default pathnme as per options.uploadDir and options.filename
// file.filepath = CUSTOM_PATH // to change the final path
});
```

@@ -606,3 +693,7 @@

```js
form.on('file', (name, file) => {});
form.on('file', (formname, file) => {
// same as fileBegin, except
// it is too late to change file.filepath
// file.hash is available if options.hash was used
});
```

@@ -616,2 +707,4 @@

May have `error.httpCode` and `error.code` attached.
```js

@@ -653,4 +746,4 @@ form.on('error', (err) => {});

button (pencil icon) and suggest a correction. If you would like to help us fix
a bug or add a new feature, please check our
[Contributing Guide](./CONTRIBUTING.md). Pull requests are welcome!
a bug or add a new feature, please check our [Contributing
Guide][contributing-url]. Pull requests are welcome!

@@ -694,2 +787,9 @@ Thanks goes to these wonderful people

From a [Felix blog post](https://felixge.de/2013/03/11/the-pull-request-hack/):
- [Sven Lito](https://github.com/svnlto) for fixing bugs and merging patches
- [egirshov](https://github.com/egirshov) for contributing many improvements to the node-formidable multipart parser
- [Andrew Kelley](https://github.com/superjoe30) for also helping with fixing bugs and making improvements
- [Mike Frey](https://github.com/mikefrey) for contributing JSON support
## License

@@ -733,4 +833,4 @@

[contributing-url]: https://github.com/node-formidable/formidable/blob/master/CONTRIBUTING.md
[code_of_conduct-url]: https://github.com/node-formidable/formidable/blob/master/CODE_OF_CONDUCT.md
[contributing-url]: https://github.com/node-formidable/.github/blob/master/CONTRIBUTING.md
[code_of_conduct-url]: https://github.com/node-formidable/.github/blob/master/CODE_OF_CONDUCT.md

@@ -737,0 +837,0 @@ [open-issue-url]: https://github.com/node-formidable/formidable/issues/new

@@ -7,3 +7,2 @@ /* eslint-disable class-methods-use-this */

const os = require('os');
const fs = require('fs');
const path = require('path');

@@ -22,14 +21,25 @@ const hexoid = require('hexoid');

maxFileSize: 200 * 1024 * 1024,
minFileSize: 1,
allowEmptyFiles: true,
keepExtensions: false,
encoding: 'utf-8',
hash: false,
hashAlgorithm: false,
uploadDir: os.tmpdir(),
multiples: false,
enabledPlugins: ['octetstream', 'querystring', 'multipart', 'json'],
fileWriteStreamHandler: null,
defaultInvalidName: 'invalid-name',
filter: function () {
return true;
},
};
const File = require('./File');
const PersistentFile = require('./PersistentFile');
const VolatileFile = require('./VolatileFile');
const DummyParser = require('./parsers/Dummy');
const MultipartParser = require('./parsers/Multipart');
const errors = require('./FormidableError.js');
const { FormidableError } = errors;
function hasOwnProp(obj, key) {

@@ -45,3 +55,5 @@ return Object.prototype.hasOwnProperty.call(obj, key);

const dir = this.options.uploadDir || this.options.uploaddir || os.tmpdir();
const dir = path.resolve(
this.options.uploadDir || this.options.uploaddir || os.tmpdir(),
);

@@ -63,14 +75,4 @@ this.uploaddir = dir;

const hasRename = typeof this.options.filename === 'function';
this._setUpRename();
if (this.options.keepExtensions === true && hasRename) {
this._rename = (part) => {
const resultFilepath = this.options.filename.call(this, part, this);
return this._uploadPath(part, resultFilepath);
};
} else {
this._rename = (part) => this._uploadPath(part);
}
this._flushing = 0;

@@ -82,9 +84,10 @@ this._fieldsSize = 0;

const enabledPlugins = []
this.options.enabledPlugins = []
.concat(this.options.enabledPlugins)
.filter(Boolean);
if (enabledPlugins.length === 0) {
throw new Error(
if (this.options.enabledPlugins.length === 0) {
throw new FormidableError(
'expect at least 1 enabled builtin plugin, see options.enabledPlugins',
errors.missingPlugin,
);

@@ -98,2 +101,4 @@ }

});
this._setUpMaxFields();
}

@@ -103,3 +108,6 @@

if (typeof plugin !== 'function') {
throw new Error('.use: expect `plugin` to be a function');
throw new FormidableError(
'.use: expect `plugin` to be a function',
errors.pluginFunction,
);
}

@@ -146,7 +154,12 @@ this._plugins.push(plugin.bind(this));

const files = {};
this.on('field', (name, value) => {
if (this.options.multiples) {
let mObj = { [name] : value };
mockFields = mockFields + '&' + qs.stringify(mObj);
if (
this.options.multiples &&
(this.type === 'multipart' || this.type === 'urlencoded')
) {
const mObj = { [name]: value };
mockFields = mockFields
? `${mockFields}&${qs.stringify(mObj)}`
: `${qs.stringify(mObj)}`;
} else {

@@ -192,3 +205,3 @@ fields[name] = value;

this.emit('aborted');
this._error(new Error('Request aborted'));
this._error(new FormidableError('Request aborted', errors.aborted));
})

@@ -221,3 +234,9 @@ .on('data', (buffer) => {

if (!this._parser) {
this._error(new Error('not parser found'));
this._error(
new FormidableError(
'no parser found',
errors.noParser,
415, // Unsupported Media Type
),
);
return;

@@ -236,3 +255,5 @@ }

if (!this._parser) {
this._error(new Error('uninitialized parser'));
this._error(
new FormidableError('uninitialized parser', errors.uninitializedParser),
);
return null;

@@ -265,8 +286,13 @@ }

_handlePart(part) {
if (part.filename && typeof part.filename !== 'string') {
this._error(new Error(`the part.filename should be string when exists`));
if (part.originalFilename && typeof part.originalFilename !== 'string') {
this._error(
new FormidableError(
`the part.originalFilename should be string when it exists`,
errors.filenameNotString,
),
);
return;
}
// This MUST check exactly for undefined. You can not change it to !part.filename.
// This MUST check exactly for undefined. You can not change it to !part.originalFilename.

@@ -279,7 +305,9 @@ // todo: uncomment when switch tests to Jest

// and such thing because code style
// ? NOTE(@tunnckocore): or even better, if there is no mime, then it's for sure a field
// ? NOTE(@tunnckocore): filename is an empty string when a field?
if (!part.mime) {
// ? NOTE(@tunnckocore): or even better, if there is no mimetype, then it's for sure a field
// ? NOTE(@tunnckocore): originalFilename is an empty string when a field?
if (!part.mimetype) {
let value = '';
const decoder = new StringDecoder(this.options.encoding);
const decoder = new StringDecoder(
part.transferEncoding || this.options.encoding,
);

@@ -290,4 +318,6 @@ part.on('data', (buffer) => {

this._error(
new Error(
new FormidableError(
`options.maxFieldsSize (${this.options.maxFieldsSize} bytes) exceeded, received ${this._fieldsSize} bytes of field data`,
errors.maxFieldsSizeExceeded,
413, // Payload Too Large
),

@@ -306,9 +336,15 @@ );

if (!this.options.filter(part)) {
return;
}
this._flushing += 1;
const file = new File({
path: this._rename(part),
name: part.filename,
type: part.mime,
hash: this.options.hash,
const newFilename = this._getNewName(part);
const filepath = this._joinDirectoryName(newFilename);
const file = this._newFile({
newFilename,
filepath,
originalFilename: part.originalFilename,
mimetype: part.mimetype,
});

@@ -325,6 +361,18 @@ file.on('error', (err) => {

this._fileSize += buffer.length;
if (this._fileSize < this.options.minFileSize) {
this._error(
new FormidableError(
`options.minFileSize (${this.options.minFileSize} bytes) inferior, received ${this._fileSize} bytes of file data`,
errors.smallerThanMinFileSize,
400,
),
);
return;
}
if (this._fileSize > this.options.maxFileSize) {
this._error(
new Error(
new FormidableError(
`options.maxFileSize (${this.options.maxFileSize} bytes) exceeded, received ${this._fileSize} bytes of file data`,
errors.biggerThanMaxFileSize,
413,
),

@@ -344,2 +392,13 @@ );

part.on('end', () => {
if (!this.options.allowEmptyFiles && this._fileSize === 0) {
this._error(
new FormidableError(
`options.allowEmptyFiles is false, file size should be greather than 0`,
errors.noEmptyFiles,
400,
),
);
return;
}
file.end(() => {

@@ -361,3 +420,9 @@ this._flushing -= 1;

if (!this.headers['content-type']) {
this._error(new Error('bad content-type header, no content-type'));
this._error(
new FormidableError(
'bad content-type header, no content-type',
errors.missingContentType,
400,
),
);
return;

@@ -380,4 +445,6 @@ }

// there is no other better way, except a handle through options
const error = new Error(
const error = new FormidableError(
`plugin on index ${idx} failed with: ${err.message}`,
errors.pluginFailed,
500,
);

@@ -421,4 +488,3 @@ error.idx = idx;

this.openedFiles.forEach((file) => {
file._writeStream.destroy();
setTimeout(fs.unlink, 0, file.path, () => {});
file.destroy();
});

@@ -445,2 +511,21 @@ }

_newFile({ filepath, originalFilename, mimetype, newFilename }) {
return this.options.fileWriteStreamHandler
? new VolatileFile({
newFilename,
filepath,
originalFilename,
mimetype,
createFileWriteStream: this.options.fileWriteStreamHandler,
hashAlgorithm: this.options.hashAlgorithm,
})
: new PersistentFile({
newFilename,
filepath,
originalFilename,
mimetype,
hashAlgorithm: this.options.hashAlgorithm,
});
}
_getFileName(headerValue) {

@@ -454,12 +539,16 @@ // matches either a quoted-string or a token (RFC 2616 section 19.5.1)

const match = m[2] || m[3] || '';
let filename = match.substr(match.lastIndexOf('\\') + 1);
filename = filename.replace(/%22/g, '"');
filename = filename.replace(/&#([\d]{4});/g, (_, code) =>
let originalFilename = match.substr(match.lastIndexOf('\\') + 1);
originalFilename = originalFilename.replace(/%22/g, '"');
originalFilename = originalFilename.replace(/&#([\d]{4});/g, (_, code) =>
String.fromCharCode(code),
);
return filename;
return originalFilename;
}
_getExtension(str) {
if (!str) {
return '';
}
const basename = path.basename(str);

@@ -477,13 +566,62 @@ const firstDot = basename.indexOf('.');

_uploadPath(part, fp) {
const name = fp || `${this.uploadDir}${path.sep}${toHexoId()}`;
if (part && this.options.keepExtensions) {
const filename = typeof part === 'string' ? part : part.filename;
return `${name}${this._getExtension(filename)}`;
_joinDirectoryName(name) {
const newPath = path.join(this.uploadDir, name);
// prevent directory traversal attacks
if (!newPath.startsWith(this.uploadDir)) {
return path.join(this.uploadDir, this.options.defaultInvalidName);
}
return name;
return newPath;
}
_setUpRename() {
const hasRename = typeof this.options.filename === 'function';
if (hasRename) {
this._getNewName = (part) => {
let ext = '';
let name = this.options.defaultInvalidName;
if (part.originalFilename) {
// can be null
({ ext, name } = path.parse(part.originalFilename));
if (this.options.keepExtensions !== true) {
ext = '';
}
}
return this.options.filename.call(this, name, ext, part, this);
};
} else {
this._getNewName = (part) => {
const name = toHexoId();
if (part && this.options.keepExtensions) {
const originalFilename = typeof part === 'string' ? part : part.originalFilename;
return `${name}${this._getExtension(originalFilename)}`;
}
return name;
}
}
}
_setUpMaxFields() {
if (this.options.maxFields !== 0) {
let fieldsCount = 0;
this.on('field', () => {
fieldsCount += 1;
if (fieldsCount > this.options.maxFields) {
this._error(
new FormidableError(
`options.maxFields (${this.options.maxFields}) exceeded`,
errors.maxFieldsExceeded,
413,
),
);
}
});
}
}
_maybeEnd() {

@@ -490,0 +628,0 @@ // console.log('ended', this.ended);

'use strict';
const File = require('./File');
const PersistentFile = require('./PersistentFile');
const VolatileFile = require('./VolatileFile');
const Formidable = require('./Formidable');
const FormidableError = require('./FormidableError');

@@ -14,3 +16,6 @@ const plugins = require('./plugins/index');

module.exports = Object.assign(formidable, {
File,
errors: FormidableError,
File: PersistentFile,
PersistentFile,
VolatileFile,
Formidable,

@@ -17,0 +22,0 @@ formidable,

@@ -0,0 +0,0 @@ /* eslint-disable no-underscore-dangle */

@@ -0,0 +0,0 @@ 'use strict';

@@ -0,0 +0,0 @@ /* eslint-disable no-underscore-dangle */

@@ -9,3 +9,6 @@ /* eslint-disable no-fallthrough */

const { Transform } = require('stream');
const errors = require('../FormidableError.js');
const { FormidableError } = errors;
let s = 0;

@@ -63,3 +66,3 @@ const STATE = {

_final(done) {
_flush(done) {
if (

@@ -74,4 +77,6 @@ (this.state === STATE.HEADER_FIELD_START && this.index === 0) ||

done(
new Error(
new FormidableError(
`MultipartParser.end(): stream ended unexpectedly: ${this.explain()}`,
errors.malformedMultipart,
400,
),

@@ -78,0 +83,0 @@ );

@@ -0,0 +0,0 @@ 'use strict';

@@ -14,3 +14,2 @@ /* eslint-disable no-underscore-dangle */

this.globalOptions = { ...options };
this.maxKeys = this.globalOptions.maxFields;
this.buffer = '';

@@ -27,5 +26,3 @@ this.bufferLength = 0;

_flush(callback) {
const fields = querystring.parse(this.buffer, '&', '=', {
maxKeys: this.maxKeys,
});
const fields = querystring.parse(this.buffer, '&', '=');
// eslint-disable-next-line no-restricted-syntax, guard-for-in

@@ -32,0 +29,0 @@ for (const key in fields) {

@@ -0,0 +0,0 @@ 'use strict';

@@ -0,0 +0,0 @@ /* eslint-disable no-underscore-dangle */

@@ -7,3 +7,6 @@ /* eslint-disable no-underscore-dangle */

const MultipartParser = require('../parsers/Multipart');
const errors = require('../FormidableError.js');
const { FormidableError } = errors;
// the `options` is also available through the `options` / `formidable.options`

@@ -28,3 +31,7 @@ module.exports = function plugin(formidable, options) {

} else {
const err = new Error('bad content-type header, no multipart boundary');
const err = new FormidableError(
'bad content-type header, no multipart boundary',
errors.missingMultipartBoundary,
400,
);
self._error(err);

@@ -56,6 +63,6 @@ }

part.name = null;
part.filename = null;
part.mime = null;
part.originalFilename = null;
part.mimetype = null;
part.transferEncoding = 'binary';
part.transferEncoding = this.options.encoding;
part.transferBuffer = '';

@@ -83,5 +90,5 @@

part.filename = this._getFileName(headerValue);
part.originalFilename = this._getFileName(headerValue);
} else if (headerField === 'content-type') {
part.mime = headerValue;
part.mimetype = headerValue;
} else if (headerField === 'content-transfer-encoding') {

@@ -97,3 +104,4 @@ part.transferEncoding = headerValue.toLowerCase();

case '7bit':
case '8bit': {
case '8bit':
case 'utf-8': {
const dataPropagation = (ctx) => {

@@ -152,3 +160,9 @@ if (ctx.name === 'partData') {

default:
return this._error(new Error('unknown transfer-encoding'));
return this._error(
new FormidableError(
'unknown transfer-encoding',
errors.unknownTransferEncoding,
501,
),
);
}

@@ -155,0 +169,0 @@

@@ -5,3 +5,2 @@ /* eslint-disable no-underscore-dangle */

const File = require('../File');
const OctetStreamParser = require('../parsers/OctetStream');

@@ -29,13 +28,19 @@

this.type = 'octet-stream';
const filename = this.headers['x-file-name'];
const mime = this.headers['content-type'];
const originalFilename = this.headers['x-file-name'];
const mimetype = this.headers['content-type'];
const file = new File({
path: this._uploadPath(filename),
name: filename,
type: mime,
hash: this.options.hash,
const thisPart = {
originalFilename,
mimetype,
};
const newFilename = this._getNewName(thisPart);
const filepath = this._joinDirectoryName(newFilename);
const file = this._newFile({
newFilename,
filepath,
originalFilename,
mimetype,
});
this.emit('fileBegin', filename, file);
this.emit('fileBegin', originalFilename, file);
file.open();

@@ -42,0 +47,0 @@ this.openedFiles.push(file);

@@ -0,0 +0,0 @@ /* eslint-disable no-underscore-dangle */

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