Skip to content

Commit e42098c

Browse files
committed
improve Multer limits validation and error reporting, update related tests
1 parent e259a7e commit e42098c

File tree

3 files changed

+80
-4
lines changed

3 files changed

+80
-4
lines changed

index.js

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,24 @@ var diskStorage = require('./storage/disk')
44
var memoryStorage = require('./storage/memory')
55
var MulterError = require('./lib/multer-error')
66

7+
function checkLimitValue (limitKey, value) {
8+
if (!Number.isInteger(value) || value < 0) {
9+
throw new MulterError('LIMIT_OPTION_ERROR', `option "${limitKey}" value: ${value}`)
10+
}
11+
return value
12+
}
13+
14+
function getLimits (limitObj) {
15+
if (!limitObj || typeof limitObj !== 'object' || Array.isArray(limitObj)) {
16+
throw new TypeError('Expected limits to be a plain object')
17+
}
18+
var limits = {}
19+
Object.keys(limitObj).forEach(key => {
20+
limits[key] = checkLimitValue(key, limitObj[key])
21+
})
22+
return limits
23+
}
24+
725
function allowAll (req, file, cb) {
826
cb(null, true)
927
}
@@ -17,7 +35,7 @@ function Multer (options) {
1735
this.storage = memoryStorage()
1836
}
1937

20-
this.limits = options.limits
38+
this.limits = options.limits ? getLimits(options.limits) : options.limits
2139
this.preservePath = options.preservePath
2240
this.fileFilter = options.fileFilter || allowAll
2341
}
@@ -91,7 +109,7 @@ function multer (options) {
91109
return new Multer({})
92110
}
93111

94-
if (typeof options === 'object' && options !== null) {
112+
if (typeof options === 'object' && options !== null && !Array.isArray(options)) {
95113
return new Multer(options)
96114
}
97115

lib/multer-error.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,19 @@ var errorMessages = {
88
LIMIT_FIELD_VALUE: 'Field value too long',
99
LIMIT_FIELD_COUNT: 'Too many fields',
1010
LIMIT_UNEXPECTED_FILE: 'Unexpected field',
11-
MISSING_FIELD_NAME: 'Field name missing'
11+
MISSING_FIELD_NAME: 'Field name missing',
12+
LIMIT_OPTION_ERROR: 'Limit option must be an integer'
1213
}
1314

1415
function MulterError (code, field) {
1516
Error.captureStackTrace(this, this.constructor)
1617
this.name = this.constructor.name
1718
this.message = errorMessages[code]
1819
this.code = code
19-
if (field) this.field = field
20+
if (field) {
21+
this.field = field
22+
if (code === 'LIMIT_OPTION_ERROR') this.message += `: ${field}`
23+
}
2024
}
2125

2226
util.inherits(MulterError, Error)

test/error-handling.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,60 @@ function withLimits (limits, fields) {
1414
}
1515

1616
describe('Error Handling', function () {
17+
const invalidPlainObj = ['not an plain object', ['storage', 'limits']]
18+
19+
const invalidLimitOptions = [
20+
{ option: 'fieldNameSize', value: -100 },
21+
{ option: 'fieldSize', value: 0.5 },
22+
{ option: 'fields', value: '10' },
23+
{ option: 'files', value: 'foo' },
24+
{ option: 'fileSize', value: 1048.15 },
25+
{ option: 'parts', value: '0' },
26+
{ option: 'headersPairs', value: -10.55 }
27+
]
28+
29+
invalidLimitOptions.forEach(({ option, value }) => {
30+
it(`should throw an invalid limit option error for ${option} with value ${value}`, () => {
31+
assert.throws(
32+
() => multer({ limits: { [option]: value } }),
33+
(err) => {
34+
return (
35+
err instanceof multer.MulterError &&
36+
err.name === 'MulterError' &&
37+
err.code === 'LIMIT_OPTION_ERROR' &&
38+
err.field === `option "${option}" value: ${value}` &&
39+
err.message === `Limit option must be an integer: option "${option}" value: ${value}`
40+
)
41+
},
42+
`Expected multer to reject ${option} value for ${value}`
43+
)
44+
})
45+
})
46+
47+
it('should throw argument type error if limits is not a plain object', function () {
48+
invalidPlainObj.forEach(option=>{
49+
assert.throws(
50+
() => multer({ limits: option }),
51+
(err) => {
52+
return err instanceof TypeError && err.message === 'Expected limits to be a plain object'
53+
},
54+
'Expected multer to throw TypeError for non-object limits'
55+
)
56+
})
57+
})
58+
59+
it('should throw type error if options is not a plain object', function () {
60+
invalidPlainObj.forEach(option=>{
61+
assert.throws(
62+
() => multer(option),
63+
(err) => {
64+
return err instanceof TypeError && err.message === 'Expected object for argument options'
65+
},
66+
'Expected multer to throw TypeError for non plain object options'
67+
)
68+
})
69+
})
70+
1771
it('should be an instance of both `Error` and `MulterError` classes in case of the Multer\'s error', function (done) {
1872
var form = new FormData()
1973
var storage = multer.diskStorage({ destination: os.tmpdir() })

0 commit comments

Comments
 (0)