Initial commit - Event Planner application
This commit is contained in:
250
node_modules/multer/lib/make-middleware.js
generated
vendored
Normal file
250
node_modules/multer/lib/make-middleware.js
generated
vendored
Normal file
@@ -0,0 +1,250 @@
|
||||
var is = require('type-is')
|
||||
var Busboy = require('busboy')
|
||||
var appendField = require('append-field')
|
||||
|
||||
var Counter = require('./counter')
|
||||
var MulterError = require('./multer-error')
|
||||
var FileAppender = require('./file-appender')
|
||||
var removeUploadedFiles = require('./remove-uploaded-files')
|
||||
|
||||
function drainStream (stream) {
|
||||
stream.on('readable', () => {
|
||||
while (stream.read() !== null) {}
|
||||
})
|
||||
}
|
||||
|
||||
function makeMiddleware (setup) {
|
||||
return function multerMiddleware (req, res, next) {
|
||||
if (!is(req, ['multipart'])) return next()
|
||||
|
||||
var options = setup()
|
||||
|
||||
var limits = options.limits
|
||||
var storage = options.storage
|
||||
var fileFilter = options.fileFilter
|
||||
var fileStrategy = options.fileStrategy
|
||||
var preservePath = options.preservePath
|
||||
var defParamCharset = options.defParamCharset
|
||||
|
||||
req.body = Object.create(null)
|
||||
|
||||
var busboy
|
||||
var appender = null
|
||||
var isDone = false
|
||||
var readFinished = false
|
||||
var errorOccured = false
|
||||
var pendingWrites = new Counter()
|
||||
var uploadedFiles = []
|
||||
|
||||
function done (err) {
|
||||
var called = false
|
||||
function onFinished () {
|
||||
if (called) return
|
||||
called = true
|
||||
next(err)
|
||||
}
|
||||
|
||||
if (isDone) return
|
||||
isDone = true
|
||||
if (busboy) {
|
||||
req.unpipe(busboy)
|
||||
setImmediate(() => {
|
||||
busboy.removeAllListeners()
|
||||
})
|
||||
}
|
||||
drainStream(req)
|
||||
req.resume()
|
||||
|
||||
// - if responding with an error, drain request body before calling
|
||||
// next(err) -- avoids EPIPE on the client (server closing connection
|
||||
// while the client is still sending the request body)
|
||||
// - also listen for 'close' so we don't hang when the client aborts (stream may never 'end')
|
||||
// - skip waiting if the stream is already destroyed (e.g. client aborted)
|
||||
if (err && req.readable && !req.destroyed) {
|
||||
req.once('end', onFinished)
|
||||
req.once('error', onFinished)
|
||||
req.once('close', onFinished)
|
||||
return
|
||||
}
|
||||
next(err)
|
||||
}
|
||||
|
||||
function indicateDone () {
|
||||
if (readFinished && pendingWrites.isZero() && !errorOccured) done()
|
||||
}
|
||||
|
||||
function abortWithError (uploadError, skipPendingWait) {
|
||||
if (errorOccured) return
|
||||
errorOccured = true
|
||||
|
||||
function finishAbort () {
|
||||
function remove (file, cb) {
|
||||
storage._removeFile(req, file, cb)
|
||||
}
|
||||
|
||||
removeUploadedFiles(uploadedFiles, remove, function (err, storageErrors) {
|
||||
if (err) return done(err)
|
||||
|
||||
uploadError.storageErrors = storageErrors
|
||||
done(uploadError)
|
||||
})
|
||||
}
|
||||
|
||||
if (skipPendingWait) {
|
||||
finishAbort()
|
||||
} else {
|
||||
pendingWrites.onceZero(finishAbort)
|
||||
}
|
||||
}
|
||||
|
||||
function abortWithCode (code, optionalField) {
|
||||
abortWithError(new MulterError(code, optionalField))
|
||||
}
|
||||
|
||||
function handleRequestFailure (err) {
|
||||
if (isDone) return
|
||||
if (busboy) {
|
||||
req.unpipe(busboy)
|
||||
busboy.destroy(err)
|
||||
}
|
||||
abortWithError(err, true)
|
||||
}
|
||||
|
||||
req.on('error', function (err) {
|
||||
handleRequestFailure(err || new Error('Request error'))
|
||||
})
|
||||
|
||||
req.on('aborted', function () {
|
||||
handleRequestFailure(new Error('Request aborted'))
|
||||
})
|
||||
|
||||
req.on('close', function () {
|
||||
if (req.readableEnded) return
|
||||
handleRequestFailure(new Error('Request closed'))
|
||||
})
|
||||
|
||||
try {
|
||||
busboy = Busboy({
|
||||
headers: req.headers,
|
||||
limits: limits,
|
||||
preservePath: preservePath,
|
||||
defParamCharset: defParamCharset
|
||||
})
|
||||
} catch (err) {
|
||||
return next(err)
|
||||
}
|
||||
|
||||
appender = new FileAppender(fileStrategy, req)
|
||||
|
||||
// handle text field data
|
||||
busboy.on('field', function (fieldname, value, { nameTruncated, valueTruncated }) {
|
||||
if (fieldname == null) return abortWithCode('MISSING_FIELD_NAME')
|
||||
if (nameTruncated) return abortWithCode('LIMIT_FIELD_KEY')
|
||||
if (valueTruncated) return abortWithCode('LIMIT_FIELD_VALUE', fieldname)
|
||||
|
||||
// Work around bug in Busboy (https://github.com/mscdex/busboy/issues/6)
|
||||
if (limits && Object.prototype.hasOwnProperty.call(limits, 'fieldNameSize')) {
|
||||
if (fieldname.length > limits.fieldNameSize) return abortWithCode('LIMIT_FIELD_KEY')
|
||||
}
|
||||
|
||||
appendField(req.body, fieldname, value)
|
||||
})
|
||||
|
||||
// handle files
|
||||
busboy.on('file', function (fieldname, fileStream, { filename, encoding, mimeType }) {
|
||||
var pendingWritesIncremented = false
|
||||
|
||||
fileStream.on('error', function (err) {
|
||||
if (pendingWritesIncremented) {
|
||||
pendingWrites.decrement()
|
||||
}
|
||||
abortWithError(err)
|
||||
})
|
||||
|
||||
if (fieldname == null) return abortWithCode('MISSING_FIELD_NAME')
|
||||
|
||||
// don't attach to the files object, if there is no file
|
||||
if (!filename) return fileStream.resume()
|
||||
|
||||
// Work around bug in Busboy (https://github.com/mscdex/busboy/issues/6)
|
||||
if (limits && Object.prototype.hasOwnProperty.call(limits, 'fieldNameSize')) {
|
||||
if (fieldname.length > limits.fieldNameSize) return abortWithCode('LIMIT_FIELD_KEY')
|
||||
}
|
||||
|
||||
var file = {
|
||||
fieldname: fieldname,
|
||||
originalname: filename,
|
||||
encoding: encoding,
|
||||
mimetype: mimeType
|
||||
}
|
||||
|
||||
var placeholder = appender.insertPlaceholder(file)
|
||||
|
||||
fileFilter(req, file, function (err, includeFile) {
|
||||
if (errorOccured) {
|
||||
appender.removePlaceholder(placeholder)
|
||||
return fileStream.resume()
|
||||
}
|
||||
|
||||
if (err) {
|
||||
appender.removePlaceholder(placeholder)
|
||||
return abortWithError(err)
|
||||
}
|
||||
|
||||
if (!includeFile) {
|
||||
appender.removePlaceholder(placeholder)
|
||||
return fileStream.resume()
|
||||
}
|
||||
|
||||
var aborting = false
|
||||
pendingWritesIncremented = true
|
||||
pendingWrites.increment()
|
||||
|
||||
Object.defineProperty(file, 'stream', {
|
||||
configurable: true,
|
||||
enumerable: false,
|
||||
value: fileStream
|
||||
})
|
||||
|
||||
fileStream.on('limit', function () {
|
||||
aborting = true
|
||||
abortWithCode('LIMIT_FILE_SIZE', fieldname)
|
||||
})
|
||||
|
||||
storage._handleFile(req, file, function (err, info) {
|
||||
if (aborting) {
|
||||
appender.removePlaceholder(placeholder)
|
||||
uploadedFiles.push({ ...file, ...info })
|
||||
return pendingWrites.decrement()
|
||||
}
|
||||
|
||||
if (err) {
|
||||
appender.removePlaceholder(placeholder)
|
||||
pendingWrites.decrement()
|
||||
return abortWithError(err)
|
||||
}
|
||||
|
||||
var fileInfo = { ...file, ...info }
|
||||
|
||||
appender.replacePlaceholder(placeholder, fileInfo)
|
||||
uploadedFiles.push(fileInfo)
|
||||
pendingWrites.decrement()
|
||||
indicateDone()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
busboy.on('error', function (err) { abortWithError(err) })
|
||||
busboy.on('partsLimit', function () { abortWithCode('LIMIT_PART_COUNT') })
|
||||
busboy.on('filesLimit', function () { abortWithCode('LIMIT_FILE_COUNT') })
|
||||
busboy.on('fieldsLimit', function () { abortWithCode('LIMIT_FIELD_COUNT') })
|
||||
busboy.on('close', function () {
|
||||
readFinished = true
|
||||
indicateDone()
|
||||
})
|
||||
|
||||
req.pipe(busboy)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = makeMiddleware
|
||||
Reference in New Issue
Block a user