Skip to content

Commit

Permalink
Merge pull request node-formidable#45 from dougwilson/feature/max-fil…
Browse files Browse the repository at this point in the history
…e-size

Add option for max files size for autoFiles
  • Loading branch information
andrewrk committed Jan 18, 2014
2 parents 05d8e6e + 2489f46 commit ec028e5
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 4 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ Creates a new form. Options:
* `maxFields` - Limits the number of fields that will be parsed before
emitting an `error` event. A file counts as a field in this case.
Defaults to 1000.
* `maxFilesSize` - Only relevant when `autoFiles` is `true`. Limits the
total bytes accepted for all files combined. If this value is exceeded,
an `error` event is emitted. The default is `Infinity`.
* `autoFields` - Enables `field` events. This is automatically set to `true`
if you add a `field` listener.
* `autoFiles` - Enables `file` events. This is automatically set to `true`
Expand Down Expand Up @@ -159,6 +162,8 @@ event is emitted. This is typically when you would send your response.
listener, multiparty automatically sets `form.autoFiles` to `true` and will
stream uploads to disk for you.

**The max bytes accepted per request can be specified with `maxFilesSize`.**

* `name` - the field name for this file
* `file` - an object with these properties:
- `fieldName` - same as `name` - the field name for this file
Expand Down
29 changes: 25 additions & 4 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ function Form(options) {

self.maxFields = options.maxFields || 1000;
self.maxFieldsSize = options.maxFieldsSize || 2 * 1024 * 1024;
self.maxFilesSize = options.maxFilesSize || Infinity;
self.uploadDir = options.uploadDir || os.tmpDir();
self.encoding = options.encoding || 'utf8';
self.hash = options.hash || false;
Expand All @@ -59,6 +60,7 @@ function Form(options) {
self.openedFiles = [];
self.totalFieldSize = 0;
self.totalFieldCount = 0;
self.totalFileSize = 0;
self.flushing = 0;

self.backpressure = false;
Expand Down Expand Up @@ -143,10 +145,7 @@ Form.prototype.parse = function(req, cb) {
}

self.openedFiles.forEach(function(file) {
file.ws.destroy();
fs.unlink(file.path, function(err) {
// this is already an error condition, ignore 2nd error
});
destroyFile(self, file);
});
self.openedFiles = [];

Expand Down Expand Up @@ -493,6 +492,18 @@ function maybeClose(self) {
}
}

function destroyFile(self, file) {
if (!file.ws) return;
file.ws.destroy();
file.ws.removeAllListeners('close');
if (typeof file.ws.fd !== 'number') return;
file.ws.on('close', function() {
fs.unlink(file.path, function(err) {
if (!self.error) self.handleError(err);
});
});
}

function handleFile(self, fileStream) {
beginFlush(self);
var file = {
Expand All @@ -505,6 +516,7 @@ function handleFile(self, fileStream) {
self.openedFiles.push(file);
fileStream.pipe(file.ws);
var counter = new StreamCounter();
var seenBytes = 0;
fileStream.pipe(counter);
var hashWorkaroundStream
, hash = null;
Expand All @@ -518,6 +530,15 @@ function handleFile(self, fileStream) {
};
fileStream.pipe(hashWorkaroundStream);
}
counter.on('progress', function() {
var deltaBytes = counter.bytes - seenBytes;
self.totalFileSize += deltaBytes;
if (self.totalFileSize > self.maxFilesSize) {
if (hashWorkaroundStream) fileStream.unpipe(hashWorkaroundStream);
fileStream.unpipe(counter);
self.handleError(new Error("maxFilesSize " + self.maxFilesSize + " exceeded"));
}
});
file.ws.on('error', function(err) {
if (!self.error) self.handleError(err);
});
Expand Down
44 changes: 44 additions & 0 deletions test/standalone/test-max-files-size.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
var http = require('http')
, multiparty = require('../../')
, assert = require('assert')
, superagent = require('superagent')
, path = require('path')
, fs = require('fs')

var server = http.createServer(function(req, res) {
assert.strictEqual(req.url, '/upload');
assert.strictEqual(req.method, 'POST');

var form = new multiparty.Form({autoFiles:true,maxFilesSize:800*1024});

var first = true;
form.on('error', function (err) {
assert.ok(first);
first = false;
assert.ok(/maxFilesSize/.test(err.message));
server.close();
});

var fileCount = 0;
form.on('file', function(name, file) {
fileCount += 1;
fs.unlink(file.path, function() {});
});

form.parse(req, function(err, fields, files) {
assert.ok(fileCount <= 1);
res.end();
});
});
server.listen(function() {
var url = 'http://localhost:' + server.address().port + '/upload';
var req = superagent.post(url);
req.attach('file0', fixture('pf1y5.png'), 'SOG1.JPG');
req.attach('file1', fixture('pf1y5.png'), 'SOG2.JPG');
req.on('error', function(){});
req.end();
});

function fixture(name) {
return path.join(__dirname, '..', 'fixture', 'file', name)
}

0 comments on commit ec028e5

Please sign in to comment.