Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

File size fix #791

Merged
merged 12 commits into from
Dec 9, 2021
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# Changelog


### 3.2.0


* feat: maxFileSize option is now per file (as the name suggests)
* feat: add maxFiles option, default Infinity
* feat: add maxTotalFileSize, default is maxFileSize (for backwards compatibility)
* fix: minFileSize is per file
* fix: allowEmptyFiles fix in cases where one file is not empty
* fix: allowEmptyFiles false option by default
* fix: rename wrongly named error
* refactor: rename wrongly named maxFileSize into maxTotalFileSize

### 3.1.5

* fix: PersistentFile.toString ([#796](https://github.com/node-formidable/formidable/pull/796))
Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -310,8 +310,12 @@ See it's defaults in [src/Formidable.js DEFAULT_OPTIONS](./src/Formidable.js)
files
- `options.minFileSize` **{number}** - default `1` (1byte); the minium size of
uploaded file.
- `options.maxFiles` **{number}** - default `Infinity`;
limit the amount of uploaded files.
- `options.maxFileSize` **{number}** - default `200 * 1024 * 1024` (200mb);
limit the size of uploaded file.
limit the size of each uploaded file.
- `options.maxTotalFileSize` **{number}** - default `options.maxFileSize`;
limit the size of the batch of uploaded files.
- `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
Expand Down
12 changes: 7 additions & 5 deletions examples/with-http.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const server = http.createServer((req, res) => {
if (req.url === '/api/upload' && req.method.toLowerCase() === 'post') {
// parse a file upload
const form = formidable({
uploadDir: `uploads`,
// uploadDir: `uploads`,
keepExtensions: true,
// filename(/*name, ext, part, form*/) {
// /* name basename of the http originalFilename
Expand All @@ -24,10 +24,12 @@ const server = http.createServer((req, res) => {
// return 'yo.txt'; // or completly different name
// // return 'z/yo.txt'; // subdirectory
// },
filter: function ({name, originalFilename, mimetype}) {
// keep only images
return mimetype && mimetype.includes("image");
}
// filter: function ({name, originalFilename, mimetype}) {
// // keep only images
// return mimetype && mimetype.includes("image");
// }
// maxTotalFileSize: 4000,
// maxFileSize: 1000,

});

Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "formidable",
"version": "3.1.5",
"version": "3.2.0",
"license": "MIT",
"description": "A node.js module for parsing form data, especially file uploads.",
"homepage": "https://github.com/node-formidable/formidable",
Expand All @@ -13,7 +13,7 @@
],
"publishConfig": {
"access": "public",
"tag": "v3"
"tag": "v4"
},
"scripts": {
"bench": "node benchmark",
Expand Down
71 changes: 54 additions & 17 deletions src/Formidable.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@ const toHexoId = hexoid(25);
const DEFAULT_OPTIONS = {
maxFields: 1000,
maxFieldsSize: 20 * 1024 * 1024,
maxFiles: Infinity,
maxFileSize: 200 * 1024 * 1024,
maxTotalFileSize: undefined,
minFileSize: 1,
allowEmptyFiles: true,
allowEmptyFiles: false,
keepExtensions: false,
encoding: 'utf-8',
hashAlgorithm: false,
Expand All @@ -45,6 +47,9 @@ class IncomingForm extends EventEmitter {
super();

this.options = { ...DEFAULT_OPTIONS, ...options };
if (!this.options.maxTotalFileSize) {
this.options.maxTotalFileSize = this.options.maxFileSize
}

const dir = path.resolve(
this.options.uploadDir || this.options.uploaddir || os.tmpdir(),
Expand All @@ -69,7 +74,7 @@ class IncomingForm extends EventEmitter {

this._flushing = 0;
this._fieldsSize = 0;
this._fileSize = 0;
this._totalFileSize = 0;
this._plugins = [];
this.openedFiles = [];

Expand All @@ -89,6 +94,7 @@ class IncomingForm extends EventEmitter {
});

this._setUpMaxFields();
this._setUpMaxFiles();
this.ended = undefined;
this.type = undefined;
}
Expand Down Expand Up @@ -308,6 +314,7 @@ class IncomingForm extends EventEmitter {

this._flushing += 1;

let fileSize = 0;
const newFilename = this._getNewName(part);
const filepath = this._joinDirectoryName(newFilename);
const file = this._newFile({
Expand All @@ -325,22 +332,14 @@ class IncomingForm extends EventEmitter {
this.openedFiles.push(file);

part.on('data', (buffer) => {
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._totalFileSize += buffer.length;
fileSize += buffer.length;

if (this._totalFileSize > this.options.maxTotalFileSize) {
this._error(
new FormidableError(
`options.maxFileSize (${this.options.maxFileSize} bytes) exceeded, received ${this._fileSize} bytes of file data`,
errors.biggerThanMaxFileSize,
`options.maxTotalFileSize (${this.options.maxTotalFileSize} bytes) exceeded, received ${this._totalFileSize} bytes of file data`,
errors.biggerThanTotalMaxFileSize,
413,
),
);
Expand All @@ -356,7 +355,7 @@ class IncomingForm extends EventEmitter {
});

part.on('end', () => {
if (!this.options.allowEmptyFiles && this._fileSize === 0) {
if (!this.options.allowEmptyFiles && fileSize === 0) {
this._error(
new FormidableError(
`options.allowEmptyFiles is false, file size should be greather than 0`,
Expand All @@ -366,6 +365,26 @@ class IncomingForm extends EventEmitter {
);
return;
}
if (fileSize < this.options.minFileSize) {
this._error(
new FormidableError(
`options.minFileSize (${this.options.minFileSize} bytes) inferior, received ${fileSize} bytes of file data`,
errors.smallerThanMinFileSize,
400,
),
);
return;
}
if (fileSize > this.options.maxFileSize) {
this._error(
new FormidableError(
`options.maxFileSize (${this.options.maxFileSize} bytes), received ${fileSize} bytes of file data`,
errors.biggerThanMaxFileSize,
413,
),
);
return;
}

file.end(() => {
this._flushing -= 1;
Expand Down Expand Up @@ -583,6 +602,24 @@ class IncomingForm extends EventEmitter {
}
}

_setUpMaxFiles() {
if (this.options.maxFiles !== Infinity) {
let fileCount = 0;
this.on('file', () => {
fileCount += 1;
if (fileCount > this.options.maxFiles) {
this._error(
new FormidableError(
`options.maxFiles (${this.options.maxFiles}) exceeded`,
errors.maxFilesExceeded,
413,
),
);
}
});
}
}

_maybeEnd() {
// console.log('ended', this.ended);
// console.log('_flushing', this._flushing);
Expand Down
6 changes: 5 additions & 1 deletion src/FormidableError.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ const filenameNotString = 1005;
const maxFieldsSizeExceeded = 1006;
const maxFieldsExceeded = 1007;
const smallerThanMinFileSize = 1008;
const biggerThanMaxFileSize = 1009;
const biggerThanTotalMaxFileSize = 1009;
const noEmptyFiles = 1010;
const missingContentType = 1011;
const malformedMultipart = 1012;
const missingMultipartBoundary = 1013;
const unknownTransferEncoding = 1014;
const maxFilesExceeded = 1015;
const biggerThanMaxFileSize = 1016;
const pluginFailed = 1017;

const FormidableError = class extends Error {
Expand All @@ -32,13 +34,15 @@ export {
filenameNotString,
maxFieldsSizeExceeded,
maxFieldsExceeded,
maxFilesExceeded,
smallerThanMinFileSize,
biggerThanMaxFileSize,
noEmptyFiles,
missingContentType,
malformedMultipart,
missingMultipartBoundary,
unknownTransferEncoding,
biggerThanTotalMaxFileSize,
pluginFailed,
};

Expand Down