123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- const Busboy = require('busboy');
- const UploadTimer = require('./uploadtimer');
- const fileFactory = require('./fileFactory');
- const memHandler = require('./memHandler');
- const tempFileHandler = require('./tempFileHandler');
- const processNested = require('./processNested');
- const {
- isFunc,
- debugLog,
- buildFields,
- buildOptions,
- parseFileName
- } = require('./utilities');
- const waitFlushProperty = Symbol('wait flush property symbol');
- module.exports = (options, req, res, next) => {
- req.files = null;
-
- const busboyOptions = buildOptions(options, { headers: req.headers });
- const busboy = Busboy(busboyOptions);
-
- const closeConnection = (code, reason) => {
- req.unpipe(busboy);
- res.writeHead(code || 400, { Connection: 'close' });
- res.end(reason || 'Bad Request');
- };
-
- if (req.body instanceof Buffer) {
- req.body = Object.create(null);
- }
-
- busboy.on('field', (field, val) => req.body = buildFields(req.body, field, val));
-
- busboy.on('file', (field, file, info) => {
-
- const {filename:name, encoding, mimeType: mime} = info;
- const filename = parseFileName(options, name);
-
- const {
- dataHandler,
- getFilePath,
- getFileSize,
- getHash,
- complete,
- cleanup,
- getWritePromise
- } = options.useTempFiles
- ? tempFileHandler(options, field, filename)
- : memHandler(options, field, filename);
- const writePromise = options.useTempFiles
- ? getWritePromise().catch(err => {
- req.unpipe(busboy);
- req.resume();
- cleanup();
- next(err);
- }) : getWritePromise();
-
- const uploadTimer = new UploadTimer(options.uploadTimeout, () => {
- file.removeAllListeners('data');
- file.resume();
-
- file.destroy(new Error(`Upload timeout ${field}->${filename}, bytes:${getFileSize()}`));
- });
- file.on('limit', () => {
- debugLog(options, `Size limit reached for ${field}->${filename}, bytes:${getFileSize()}`);
-
- uploadTimer.clear();
-
- if (isFunc(options.limitHandler)) return options.limitHandler(req, res, next);
-
- if (options.abortOnLimit) {
- debugLog(options, `Aborting upload because of size limit ${field}->${filename}.`);
- !isFunc(options.limitHandler) ? closeConnection(413, options.responseOnLimit) : '';
- cleanup();
- }
- });
- file.on('data', (data) => {
- uploadTimer.set();
- dataHandler(data);
- });
- file.on('end', () => {
- const size = getFileSize();
-
- debugLog(options, `Upload finished ${field}->${filename}, bytes:${size}`);
-
- uploadTimer.clear();
-
-
-
- if (!name && size === 0) {
- if (options.useTempFiles) {
- cleanup();
- debugLog(options, `Removing the empty file ${field}->${filename}`);
- }
- return debugLog(options, `Don't add file instance if original name and size are empty`);
- }
- req.files = buildFields(req.files, field, fileFactory({
- buffer: complete(),
- name: filename,
- tempFilePath: getFilePath(),
- hash: getHash(),
- size,
- encoding,
- truncated: file.truncated,
- mimetype: mime
- }, options));
- if (!req[waitFlushProperty]) {
- req[waitFlushProperty] = [];
- }
- req[waitFlushProperty].push(writePromise);
- });
- file.on('error', (err) => {
- uploadTimer.clear();
- debugLog(options, err);
- cleanup();
- next();
- });
-
- debugLog(options, `New upload started ${field}->${filename}, bytes:${getFileSize()}`);
-
- uploadTimer.set();
- });
- busboy.on('finish', () => {
- debugLog(options, `Busboy finished parsing request.`);
- if (options.parseNested) {
- req.body = processNested(req.body);
- req.files = processNested(req.files);
- }
- if (!req[waitFlushProperty]) return next();
- Promise.all(req[waitFlushProperty])
- .then(() => {
- delete req[waitFlushProperty];
- next();
- });
- });
- busboy.on('error', (err) => {
- debugLog(options, `Busboy error`);
- next(err);
- });
- req.pipe(busboy);
- };
|