Socket
Socket
Sign inDemoInstall

multer

Package Overview
Dependencies
Maintainers
3
Versions
46
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

multer - npm Package Compare versions

Comparing version 2.0.0-alpha.7 to 2.0.0-beta.1

4

CHANGELOG.md

@@ -6,2 +6,6 @@ # Change log

## 2.0.0-beta.1 - 2019-11-23
- Breaking: drop support for Node.js < 8.3.x
## 2.0.0-alpha.7 - 2019-05-03

@@ -8,0 +12,0 @@

63

index.js

@@ -5,49 +5,44 @@ const createFileFilter = require('./lib/file-filter')

function _middleware (limits, fields, fileStrategy) {
return createMiddleware(function setup () {
return {
fields: fields,
limits: limits,
fileFilter: createFileFilter(fields),
fileStrategy: fileStrategy
}
})
return createMiddleware(() => ({
fields: fields,
limits: limits,
fileFilter: createFileFilter(fields),
fileStrategy: fileStrategy
}))
}
function Multer (options) {
this.limits = options.limits
}
class Multer {
constructor (options) {
this.limits = options.limits
}
Multer.prototype.single = function (name) {
return _middleware(this.limits, [{ name: name, maxCount: 1 }], 'VALUE')
}
single (name) {
return _middleware(this.limits, [{ name: name, maxCount: 1 }], 'VALUE')
}
Multer.prototype.array = function (name, maxCount) {
return _middleware(this.limits, [{ name: name, maxCount: maxCount }], 'ARRAY')
}
array (name, maxCount) {
return _middleware(this.limits, [{ name: name, maxCount: maxCount }], 'ARRAY')
}
Multer.prototype.fields = function (fields) {
return _middleware(this.limits, fields, 'OBJECT')
}
fields (fields) {
return _middleware(this.limits, fields, 'OBJECT')
}
Multer.prototype.none = function () {
return _middleware(this.limits, [], 'NONE')
}
none () {
return _middleware(this.limits, [], 'NONE')
}
Multer.prototype.any = function () {
function setup () {
return {
any () {
return createMiddleware(() => ({
fields: [],
limits: this.limits,
fileFilter: function () {},
fileFilter: () => {},
fileStrategy: 'ARRAY'
}
}))
}
return createMiddleware(setup.bind(this))
}
function multer (options) {
if (options === undefined) options = {}
if (options === null) throw new TypeError('Expected object for arugment "options", got null')
if (typeof options !== 'object') throw new TypeError('Expected object for arugment "options", got ' + (typeof options))
function multer (options = {}) {
if (options === null) throw new TypeError('Expected object for argument "options", got null')
if (typeof options !== 'object') throw new TypeError(`Expected object for argument "options", got ${typeof options}`)

@@ -54,0 +49,0 @@ if (options.dest || options.storage || options.fileFilter) {

@@ -1,3 +0,1 @@

const util = require('util')
const errorMessages = new Map([

@@ -14,15 +12,14 @@ ['CLIENT_ABORTED', 'Client aborted'],

function MulterError (code, optionalField) {
Error.captureStackTrace(this, this.constructor)
this.name = this.constructor.name
this.message = errorMessages.get(code)
this.code = code
class MulterError extends Error {
constructor (code, optionalField) {
super(errorMessages.get(code))
if (optionalField) {
this.field = optionalField
this.code = code
this.name = this.constructor.name
if (optionalField) this.field = optionalField
Error.captureStackTrace(this, this.constructor)
}
}
util.inherits(MulterError, Error)
module.exports = MulterError

@@ -7,9 +7,9 @@ function createFileAppender (strategy, req, fields) {

case 'OBJECT': req.files = Object.create(null); break
default: throw new Error('Unknown file strategy: ' + strategy)
default: throw new Error(`Unknown file strategy: ${strategy}`)
}
if (strategy === 'OBJECT') {
fields.forEach(function (field) {
for (const field of fields) {
req.files[field.name] = []
})
}
}

@@ -16,0 +16,0 @@

const MulterError = require('./error')
module.exports = function createFileFilter (fields) {
function createFileFilter (fields) {
const filesLeft = new Map()
fields.forEach(function (field) {
for (const field of fields) {
if (typeof field.maxCount === 'number') {

@@ -12,3 +12,3 @@ filesLeft.set(field.name, field.maxCount)

}
})
}

@@ -29,1 +29,3 @@ return function fileFilter (file) {

}
module.exports = createFileFilter

@@ -8,32 +8,29 @@ const is = require('type-is')

module.exports = function createMiddleware (setup) {
return function multerMiddleware (req, res, next) {
if (!is(req, ['multipart'])) return next()
async function handleRequest (setup, req) {
const options = setup()
const result = await readBody(req, options.limits, options.fileFilter)
const options = setup()
req.body = Object.create(null)
readBody(req, options.limits, options.fileFilter)
.then(function (result) {
req.body = Object.create(null)
for (const field of result.fields) {
appendField(req.body, field.key, field.value)
}
result.fields.forEach(function (field) {
appendField(req.body, field.key, field.value)
})
const appendFile = createFileAppender(options.fileStrategy, req, options.fields)
const appendFile = createFileAppender(options.fileStrategy, req, options.fields)
for (const file of result.files) {
file.stream = fs.createReadStream(file.path)
file.stream.on('open', () => fs.unlink(file.path, () => {}))
result.files.forEach(function (file) {
file.stream = fs.createReadStream(file.path)
appendFile(file)
}
}
file.stream.on('open', function () {
fs.unlink(file.path, function () {})
})
appendFile(file)
})
next()
})
.catch(next)
function createMiddleware (setup) {
return function multerMiddleware (req, res, next) {
if (!is(req, ['multipart'])) return next()
handleRequest(setup, req).then(next, next)
}
}
module.exports = createMiddleware

@@ -17,6 +17,6 @@ const path = require('path')

function collectFields (busboy, limits) {
return new Promise(function (resolve, reject) {
return new Promise((resolve, reject) => {
const result = []
busboy.on('field', function (fieldname, value, fieldnameTruncated, valueTruncated) {
busboy.on('field', (fieldname, value, fieldnameTruncated, valueTruncated) => {
if (fieldnameTruncated) return reject(new MulterError('LIMIT_FIELD_KEY'))

@@ -33,5 +33,3 @@ if (valueTruncated) return reject(new MulterError('LIMIT_FIELD_VALUE', fieldname))

busboy.on('finish', function () {
resolve(result)
})
busboy.on('finish', () => resolve(result))
})

@@ -41,9 +39,14 @@ }

function collectFiles (busboy, limits, fileFilter) {
return new Promise(function (resolve, reject) {
return new Promise((resolve, reject) => {
const result = []
busboy.on('file', function (fieldname, fileStream, filename, encoding, mimetype) {
busboy.on('file', async (fieldname, fileStream, filename, encoding, mimetype) => {
// Catch all errors on file stream
fileStream.on('error', reject)
// Catch limit exceeded on file stream
fileStream.on('limit', () => {
reject(new MulterError('LIMIT_FILE_SIZE', fieldname))
})
// Work around bug in Busboy (https://github.com/mscdex/busboy/issues/6)

@@ -61,68 +64,46 @@ if (limits && limits.hasOwnProperty('fieldNameSize')) {

const limitHit = new Promise(function (resolve) {
fileStream.on('limit', resolve)
})
try {
fileFilter(file)
} catch (err) {
return reject(err)
}
Promise.resolve()
.then(function () {
return fileFilter(file)
})
.then(function () {
limitHit.then(function () {
reject(new MulterError('LIMIT_FILE_SIZE', fieldname))
})
const target = temp.createWriteStream()
const detector = new FileType()
const fileClosed = new Promise((resolve) => target.on('close', resolve))
const target = temp.createWriteStream()
const detector = new FileType()
const promise = pump(fileStream, detector, target)
.then(async () => {
await fileClosed
file.path = target.path
file.size = target.bytesWritten
const fileClosed = new Promise(function (resolve) {
target.on('close', resolve)
})
const fileType = await detector.fileTypePromise()
file.detectedMimeType = (fileType ? fileType.mime : null)
file.detectedFileExtension = (fileType ? `.${fileType.ext}` : '')
const promise = pump(fileStream, detector, target)
.then(function () {
return fileClosed
})
.then(function () {
return detector.fileTypePromise()
})
.then(function (fileType) {
file.path = target.path
file.size = target.bytesWritten
file.detectedMimeType = (fileType ? fileType.mime : null)
file.detectedFileExtension = (fileType ? '.' + fileType.ext : '')
return file
})
.catch(reject)
result.push(promise)
return file
})
.catch(reject)
result.push(promise)
})
busboy.on('finish', function () {
resolve(Promise.all(result))
})
busboy.on('finish', () => resolve(Promise.all(result)))
})
}
function readBody (req, limits, fileFilter) {
let busboy
async function readBody (req, limits, fileFilter) {
const busboy = new Busboy({ headers: req.headers, limits: limits })
try {
busboy = new Busboy({ headers: req.headers, limits: limits })
} catch (err) {
return Promise.reject(err)
}
const fields = collectFields(busboy, limits)
const files = collectFiles(busboy, limits, fileFilter)
const guard = new Promise(function (resolve, reject) {
req.on('error', function (err) { reject(err) })
busboy.on('error', function (err) { reject(err) })
const guard = new Promise((resolve, reject) => {
req.on('error', (err) => reject(err))
busboy.on('error', (err) => reject(err))
req.on('aborted', function () { reject(new MulterError('CLIENT_ABORTED')) })
busboy.on('partsLimit', function () { reject(new MulterError('LIMIT_PART_COUNT')) })
busboy.on('filesLimit', function () { reject(new MulterError('LIMIT_FILE_COUNT')) })
busboy.on('fieldsLimit', function () { reject(new MulterError('LIMIT_FIELD_COUNT')) })
req.on('aborted', () => reject(new MulterError('CLIENT_ABORTED')))
busboy.on('partsLimit', () => reject(new MulterError('LIMIT_PART_COUNT')))
busboy.on('filesLimit', () => reject(new MulterError('LIMIT_FILE_COUNT')))
busboy.on('fieldsLimit', () => reject(new MulterError('LIMIT_FIELD_COUNT')))

@@ -134,18 +115,17 @@ busboy.on('finish', resolve)

return Promise.all([fields, files, guard])
.then(function (result) {
return { fields: result[0], files: result[1] }
})
.catch(function (err) {
req.unpipe(busboy)
drainStream(req)
busboy.removeAllListeners()
try {
const result = await Promise.all([fields, files, guard])
return { fields: result[0], files: result[1] }
} catch (err) {
req.unpipe(busboy)
drainStream(req)
busboy.removeAllListeners()
return onFinished(req).then(
function () { throw err },
function () { throw err }
)
})
// Wait for request to close, finish, or error
await onFinished(req).catch(() => {})
throw err
}
}
module.exports = readBody
{
"name": "multer",
"description": "Middleware for handling `multipart/form-data`.",
"version": "2.0.0-alpha.7",
"version": "2.0.0-beta.1",
"contributors": [

@@ -28,3 +28,3 @@ "Hage Yaapa <captain@hacksparrow.com> (http://www.hacksparrow.com)",

"pump": "^3.0.0",
"stream-file-type": "^0.3.2",
"stream-file-type": "^0.4.0",
"type-is": "^1.6.18"

@@ -35,5 +35,5 @@ },

"express": "^4.16.4",
"form-data": "^2.1.0",
"get-stream": "^4.1.0",
"hasha": "^4.0.1",
"form-data": "^3.0.0",
"get-stream": "^5.1.0",
"hasha": "^5.1.0",
"mocha": "^6.1.4",

@@ -45,3 +45,3 @@ "recursive-nullify": "^1.0.0",

"engines": {
"node": ">= 6.0.0"
"node": ">=8.3"
},

@@ -48,0 +48,0 @@ "files": [

@@ -27,3 +27,3 @@ # Multer [![Build Status](https://travis-ci.org/expressjs/multer.svg?branch=master)](https://travis-ci.org/expressjs/multer) [![NPM version](https://badge.fury.io/js/multer.svg)](https://badge.fury.io/js/multer) [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat)](https://github.com/feross/standard)

app.post('/profile', upload.single('avatar'), function (req, res, next) {
app.post('/profile', upload.single('avatar'), (req, res, next) => {
// req.file is the `avatar` file

@@ -33,3 +33,3 @@ // req.body will hold the text fields, if there were any

app.post('/photos/upload', upload.array('photos', 12), function (req, res, next) {
app.post('/photos/upload', upload.array('photos', 12), (req, res, next) => {
// req.files is array of `photos` files

@@ -40,3 +40,3 @@ // req.body will contain the text fields, if there were any

const cpUpload = upload.fields([{ name: 'avatar', maxCount: 1 }, { name: 'gallery', maxCount: 8 }])
app.post('/cool-profile', cpUpload, function (req, res, next) {
app.post('/cool-profile', cpUpload, (req, res, next) => {
// req.files is an object (String -> Array) where fieldname is the key, and the value is array of files

@@ -61,3 +61,3 @@ //

app.post('/profile', upload.none(), function (req, res, next) {
app.post('/profile', upload.none(), (req, res, next) => {
// req.body contains the text fields

@@ -165,4 +165,4 @@ })

app.post('/profile', function (req, res) {
upload(req, res, function (err) {
app.post('/profile', (req, res) => {
upload(req, res, (err) => {
if (err) {

@@ -169,0 +169,0 @@ // An error occurred when uploading

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc