diff --git a/index.js b/index.js index 1dbfaacb..d34adeb2 100644 --- a/index.js +++ b/index.js @@ -41,8 +41,13 @@ Multer.prototype._makeMiddleware = function (fields, fileStrategy) { return cb(new MulterError('LIMIT_UNEXPECTED_FILE', file.fieldname)) } - filesLeft[file.fieldname] -= 1 - fileFilter(req, file, cb) + // Only count the file against the field's maxCount once the user's + // fileFilter has accepted it. A file skipped via cb(null, false) is + // never stored, so it must not consume a slot (see #1419). + fileFilter(req, file, function (err, includeFile) { + if (!err && includeFile) filesLeft[file.fieldname] -= 1 + cb(err, includeFile) + }) } return { diff --git a/test/file-filter.js b/test/file-filter.js index 1d857f44..cce59b69 100644 --- a/test/file-filter.js +++ b/test/file-filter.js @@ -18,6 +18,10 @@ function reportFakeError (req, file, cb) { cb(new Error('Fake error')) } +function skipByOriginalName (req, file, cb) { + cb(null, file.originalname !== 'tiny0.dat') +} + describe('File Filter', function () { it('should skip some files', function (done) { var form = new FormData() @@ -41,6 +45,24 @@ describe('File Filter', function () { }) }) + it('should not consume maxCount for files skipped by fileFilter (#1419)', function (done) { + var form = new FormData() + var upload = withFilter(skipByOriginalName) + var parser = upload.array('docs', 1) + + // Two files on the same field: the first is skipped by the filter, the + // second accepted. The skipped file must not consume the single slot. + form.append('docs', util.file('tiny0.dat')) + form.append('docs', util.file('tiny1.dat')) + + util.submitForm(parser, form, function (err, req) { + assert.ifError(err) + assert.strictEqual(req.files.length, 1) + assert.strictEqual(req.files[0].originalname, 'tiny1.dat') + done() + }) + }) + it('should report errors from fileFilter', function (done) { var form = new FormData() var upload = withFilter(reportFakeError)