Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ Key | Description
`limits` | Limits of the uploaded data
`preservePath` | Keep the full client-supplied path in `file.originalname` instead of just the base name
`defParamCharset` | Default character set to use for values of part header parameters (e.g. filename) that are not extended parameters (that contain an explicit charset). Default: `'latin1'`
`defCharset` | Default character set to use for text field values that do not declare one. Default: `'utf8'`
`highWaterMark` | `highWaterMark` of the multipart parser stream. Default: busboy's default
`fileHwm` | `highWaterMark` of each file stream (`file.stream`). Default: busboy's default

In an average web app, only `dest` might be required, and configured as shown in
the following example.
Expand Down
9 changes: 9 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ function Multer (options) {
this.limits = options.limits
this.preservePath = options.preservePath
this.defParamCharset = options.defParamCharset || 'latin1'
this.defCharset = options.defCharset
this.highWaterMark = options.highWaterMark
this.fileHwm = options.fileHwm
this.fileFilter = options.fileFilter || allowAll
}

Expand Down Expand Up @@ -49,6 +52,9 @@ Multer.prototype._makeMiddleware = function (fields, fileStrategy) {
limits: this.limits,
preservePath: this.preservePath,
defParamCharset: this.defParamCharset,
defCharset: this.defCharset,
highWaterMark: this.highWaterMark,
fileHwm: this.fileHwm,
storage: this.storage,
fileFilter: wrappedFileFilter,
fileStrategy: fileStrategy
Expand Down Expand Up @@ -80,6 +86,9 @@ Multer.prototype.any = function () {
limits: this.limits,
preservePath: this.preservePath,
defParamCharset: this.defParamCharset,
defCharset: this.defCharset,
highWaterMark: this.highWaterMark,
fileHwm: this.fileHwm,
storage: this.storage,
fileFilter: this.fileFilter,
fileStrategy: 'ARRAY'
Expand Down
8 changes: 7 additions & 1 deletion lib/make-middleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ function makeMiddleware (setup) {
var fileStrategy = options.fileStrategy
var preservePath = options.preservePath
var defParamCharset = options.defParamCharset
var defCharset = options.defCharset
var highWaterMark = options.highWaterMark
var fileHwm = options.fileHwm

req.body = Object.create(null)

Expand Down Expand Up @@ -198,7 +201,10 @@ function makeMiddleware (setup) {
headers: req.headers,
limits: busboyLimits,
preservePath: preservePath,
defParamCharset: defParamCharset
defParamCharset: defParamCharset,
defCharset: defCharset,
highWaterMark: highWaterMark,
fileHwm: fileHwm
})
} catch (err) {
return next(err)
Expand Down
131 changes: 131 additions & 0 deletions test/busboy-options.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/* eslint-env mocha */

var assert = require('assert')
var stream = require('stream')

var multer = require('../')

// Multipart body with one text field whose value is "åäö" encoded as latin1
// (bytes e5 e4 f6) and no charset declared for the part.
function latin1FieldRequest () {
var boundary = 'AaB03x'
var body = Buffer.concat([
Buffer.from('--' + boundary + '\r\nContent-Disposition: form-data; name="name"\r\n\r\n'),
Buffer.from([0xe5, 0xe4, 0xf6]),
Buffer.from('\r\n--' + boundary + '--\r\n')
])
var req = new stream.PassThrough()

req.headers = {
'content-type': 'multipart/form-data; boundary=' + boundary,
'content-length': body.length
}
req.end(body)

return req
}

function fileRequest () {
var boundary = 'AaB03x'
var body = [
'--' + boundary,
'Content-Disposition: form-data; name="file"; filename="a.txt"',
'Content-Type: text/plain',
'',
'file content',
'--' + boundary + '--',
''
].join('\r\n')
var req = new stream.PassThrough()

req.headers = {
'content-type': 'multipart/form-data; boundary=' + boundary,
'content-length': body.length
}
req.end(body)

return req
}

// Storage engine that records the file stream's highWaterMark.
function recordingStorage (record) {
return {
_handleFile: function (req, file, cb) {
record.readableHighWaterMark = file.stream.readableHighWaterMark
file.stream.resume()
file.stream.on('end', function () { cb(null, {}) })
},
_removeFile: function (req, file, cb) { cb(null) }
}
}

describe('busboy options', function () {
it('should decode text fields as utf8 by default', function (done) {
var upload = multer()
var req = latin1FieldRequest()

upload.none()(req, null, function (err) {
assert.ifError(err)
// latin1 bytes are not valid utf8, so the value is decoded with replacement characters
assert.notStrictEqual(req.body.name, 'åäö')
assert.ok(req.body.name.indexOf('\ufffd') !== -1)
done()
})
})

it('should decode text fields with the given defCharset', function (done) {
var upload = multer({ defCharset: 'latin1' })
var req = latin1FieldRequest()

upload.none()(req, null, function (err) {
assert.ifError(err)
assert.strictEqual(req.body.name, 'åäö')
done()
})
})

it('should apply defCharset to .any() as well', function (done) {
var upload = multer({ defCharset: 'latin1' })
var req = latin1FieldRequest()

upload.any()(req, null, function (err) {
assert.ifError(err)
assert.strictEqual(req.body.name, 'åäö')
done()
})
})

it('should keep the default file stream highWaterMark when fileHwm is not set', function (done) {
var record = {}
var upload = multer({ storage: recordingStorage(record) })

upload.single('file')(fileRequest(), null, function (err) {
assert.ifError(err)
assert.strictEqual(record.readableHighWaterMark, new stream.Readable().readableHighWaterMark)
done()
})
})

it('should pass fileHwm to the file streams', function (done) {
var record = {}
var upload = multer({ storage: recordingStorage(record), fileHwm: 1024 })

upload.single('file')(fileRequest(), null, function (err) {
assert.ifError(err)
assert.strictEqual(record.readableHighWaterMark, 1024)
done()
})
})

it('should accept highWaterMark for the parser stream', function (done) {
var record = {}
var upload = multer({ storage: recordingStorage(record), highWaterMark: 1024 })
var req = fileRequest()

upload.single('file')(req, null, function (err) {
assert.ifError(err)
assert.strictEqual(req.file.originalname, 'a.txt')
done()
})
})
})