Merge github.com:richardgirges/express-fileupload into dev

dev
Thomas Lynch 4 years ago
commit db1d264303
  1. 6
      README.md
  2. 20
      lib/memHandler.js
  3. 40
      lib/processMultipart.js
  4. 56
      lib/tempFileHandler.js
  5. 26
      lib/uploadtimer.js
  6. 78
      lib/utilities.js
  7. 142
      package-lock.json
  8. 8
      package.json
  9. 28
      test/uploadtimer.spec.js
  10. 6
      test/utilities.spec.js

@ -2,7 +2,7 @@
Simple express middleware for uploading files.
[![npm](https://img.shields.io/npm/v/express-fileupload.svg)](https://www.npmjs.org/package/express-fileupload)
[![Build Status](https://travis-ci.org/richardgirges/express-fileupload.svg?branch=master)](https://travis-ci.org/richardgirges/express-fileupload)
[![Build Status](https://travis-ci.com/richardgirges/express-fileupload.svg?branch=master)](https://travis-ci.com/richardgirges/express-fileupload)
[![downloads per month](http://img.shields.io/npm/dm/express-fileupload.svg)](https://www.npmjs.org/package/express-fileupload)
[![Coverage Status](https://img.shields.io/coveralls/richardgirges/express-fileupload.svg)](https://coveralls.io/r/richardgirges/express-fileupload)
@ -79,7 +79,7 @@ You can set `debug` option to `true` to see some logging about upload process.
In this case middleware uses `console.log` and adds `Express-file-upload` prefix for outputs.
It will show you whether the request is invalid and also common events triggered during upload.
That can be really usfull for troubleshhoting and ***we recommend to attach debug output to each issue on Github***.
That can be really useful for troubleshooting and ***we recommend attaching debug output to each issue on Github***.
***Output example:***
@ -115,7 +115,7 @@ limitHandler | <ul><li><code>false</code>&nbsp;**(default)**</li><li><code>funct
useTempFiles | <ul><li><code>false</code>&nbsp;**(default)**</li><li><code>true</code></ul> | By default this module uploads files into RAM. Setting this option to True turns on using temporary files instead of utilising RAM. This avoids memory overflow issues when uploading large files or in case of uploading lots of files at same time.
tempFileDir | <ul><li><code>String</code>&nbsp;**(path)**</li></ul> | Path to store temporary files.<br />Used along with the <code>useTempFiles</code> option. By default this module uses 'tmp' folder in the current working directory.<br />You can use trailing slash, but it is not necessary.
parseNested | <ul><li><code>false</code>&nbsp;**(default)**</li><li><code>true</code></li></ul> | By default, req.body and req.files are flattened like this: <code>{'name': 'John', 'hobbies[0]': 'Cinema', 'hobbies[1]': 'Bike'}</code><br /><br/>When this option is enabled they are parsed in order to be nested like this: <code>{'name': 'John', 'hobbies': ['Cinema', 'Bike']}</code>
debug | <ul><li><code>false</code>&nbsp;**(default)**</li><li><code>true</code></ul> | Turn on/off upload process logging. Can be usefull for troubleshooting.
debug | <ul><li><code>false</code>&nbsp;**(default)**</li><li><code>true</code></ul> | Turn on/off upload process logging. Can be useful for troubleshooting.
# Help Wanted
Looking for additional maintainers. Please contact `richardgirges [ at ] gmail.com` if you're interested. Pull Requests are welcomed!

@ -1,5 +1,5 @@
const crypto = require('crypto');
const {debugLog} = require('./utilities');
const { debugLog } = require('./utilities');
/**
* memHandler - In memory upload handler
@ -12,23 +12,31 @@ module.exports = (options, fieldname, filename) => {
let buffers = [];
let fileSize = 0; // eslint-disable-line
let hash = crypto.createHash('sha256');
let completed = false;
const getBuffer = () => Buffer.concat(buffers, fileSize);
const emptyFunc = () => '';
return {
dataHandler: (data) => {
if (completed === true) {
debugLog(options, `Error: got ${fieldname}->${filename} data chunk for completed upload!`);
return;
}
buffers.push(data);
hash.update(data);
fileSize += data.length;
debugLog(options, `Uploading ${fieldname} -> ${filename}, bytes: ${fileSize}`);
debugLog(options, `Uploading ${fieldname}->${filename}, bytes:${fileSize}...`);
},
getBuffer: getBuffer,
getFilePath: emptyFunc,
getFilePath: () => '',
getFileSize: () => fileSize,
getHash: () => hash.digest('hex'),
complete: getBuffer,
cleanup: emptyFunc,
complete: () => {
debugLog(options, `Upload ${fieldname}->${filename} completed, bytes:${fileSize}.`);
completed = true;
return getBuffer();
},
cleanup: () => { completed = true; },
getWritePromise: () => Promise.resolve()
};
};

@ -1,4 +1,5 @@
const Busboy = require('busboy');
const UploadTimer = require('./uploadtimer');
const fileFactory = require('./fileFactory');
const memHandler = require('./memHandler');
const tempFileHandler = require('./tempFileHandler');
@ -104,12 +105,14 @@ module.exports = (options, req, res, next) => {
// Debug logging for a new file upload.
debugLog(options, `Upload finished ${field}->${filename}, bytes:${getFileSize()}`);
// Add file instance to the req.files
// Empty name and zero size indicates empty file field in the posted form.
if (!name && size === 0) return;
req.files = buildFields(req.files, field, fileFactory({
buffer: complete(),
name: filename,
tempFilePath: getFilePath(),
size: getFileSize(),
hash: getHash(),
size,
encoding,
truncated: file.truncated,
mimetype: mime
@ -138,28 +141,21 @@ module.exports = (options, req, res, next) => {
});
busboy.on('finish', () => {
const handler = (err) => {
if (options.parseNested) {
req.body = processNested(req.body);
req.files = processNested(req.files);
}
next(err);
};
if (req[waitFlushProperty]) {
Promise.all(req[waitFlushProperty])
.then(() => {
delete req[waitFlushProperty];
handler();
})
.catch(err => {
delete req[waitFlushProperty];
debugLog(options, `Error wait flush error:${err}`);
handler(err);
});
} else {
handler();
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();
}).catch(err => {
delete req[waitFlushProperty];
debugLog(options, `Error while waiting files flush: ${err}`);
next(err);
});
});
busboy.on('error', next);

@ -11,25 +11,39 @@ const {
module.exports = (options, fieldname, filename) => {
const dir = path.normalize(options.tempFileDir);
const tempFilePath = path.join(dir, getTempFilename());
checkAndMakeDir({createParentPath: true}, tempFilePath);
checkAndMakeDir({ createParentPath: true }, tempFilePath);
let hash = crypto.createHash('sha256');
let writeStream = fs.createWriteStream(tempFilePath);
debugLog(options, `Temporary file path is ${tempFilePath}`);
let fileSize = 0; // eslint-disable-line
const promise = new Promise((resolve, reject) => {
writeStream.on('finish', () => {
resolve();
});
writeStream.on('error', (err) => {
debugLog(options, `Error write temp file error:${err}`);
reject(err);
const hash = crypto.createHash('sha256');
let fileSize = 0;
let completed = false;
let writeStream = false;
let writePromise = Promise.resolve();
const createWriteStream = () => {
debugLog(options, `Opening write stream for ${fieldname}->${filename}...`);
writeStream = fs.createWriteStream(tempFilePath);
writePromise = new Promise((resolve, reject) => {
writeStream.on('finish', () => {
resolve();
});
writeStream.on('error', (err) => {
debugLog(options, `Error write temp file: ${err}`);
reject(err);
});
});
});
};
return {
dataHandler: (data) => {
if (completed === true) {
debugLog(options, `Error: got ${fieldname}->${filename} data chunk for completed upload!`);
return;
}
if (writeStream === false) createWriteStream();
writeStream.write(data);
hash.update(data);
fileSize += data.length;
@ -39,17 +53,23 @@ module.exports = (options, fieldname, filename) => {
getFileSize: () => fileSize,
getHash: () => hash.digest('hex'),
complete: () => {
writeStream.end();
completed = true;
debugLog(options, `Upload ${fieldname}->${filename} completed, bytes:${fileSize}.`);
if (writeStream !== false) writeStream.end();
// Return empty buff since data was uploaded into a temp file.
return Buffer.concat([]);
},
cleanup: () => {
debugLog(options, `Cleaning up temporary file ${tempFilePath}...`);
writeStream.end();
deleteFile(tempFilePath, (err) => { if (err) throw err; });
completed = true;
if (writeStream !== false) {
debugLog(options, `Cleaning up temporary file ${tempFilePath}...`);
writeStream.end();
deleteFile(tempFilePath, err => (err
? debugLog(options, `Cleaning up temporary file ${tempFilePath} failed: ${err}`)
: debugLog(options, `Cleaning up temporary file ${tempFilePath} done.`)
));
}
},
getWritePromise: () => {
return promise;
}
getWritePromise: () => writePromise
};
};

@ -0,0 +1,26 @@
class UploadTimer {
/**
* @constructor
* @param {number} timeout - timer timeout in msecs.
* @param {Function} callback - callback to run when timeout reached.
*/
constructor(timeout = 0, callback = () => {}) {
this.timeout = timeout;
this.callback = callback;
this.timer = null;
}
clear() {
clearTimeout(this.timer);
}
set() {
// Do not start a timer if zero timeout or it hasn't been set.
if (!this.timeout) return false;
this.clear();
this.timer = setTimeout(this.callback, this.timeout);
return true;
}
}
module.exports = UploadTimer;

@ -2,14 +2,13 @@
const fs = require('fs');
const path = require('path');
const mkdirp = require('mkdirp');
const Readable = require('stream').Readable;
// Parameters for safe file name parsing.
const SAFE_FILE_NAME_REGEX = /[^\w-]/g;
const MAX_EXTENSION_LENGTH = 3;
// Parameters which used to generate unique temporary file names:
// Parameters to generate unique temporary file names:
const TEMP_COUNTER_MAX = 65536;
const TEMP_PREFIX = 'tmp';
let tempCounter = 0;
@ -17,30 +16,29 @@ let tempCounter = 0;
/**
* Logs message to console if debug option set to true.
* @param {Object} options - options object.
* @param {String} msg - message to log.
* @returns {Boolean}
* @param {string} msg - message to log.
* @returns {boolean} - false if debug is off.
*/
const debugLog = (options, msg) => {
options = options || {};
if (!options.debug) return false;
console.log(msg); // eslint-disable-line
const opts = options || {};
if (!opts.debug) return false;
console.log(`Express-file-upload: ${msg}`); // eslint-disable-line
return true;
};
/**
* Generates unique temporary file name like: tmp-5000-156788789789.
* @param prefix {String} - a prefix for generated unique file name.
* @returns {String}
* @param {string} prefix - a prefix for generated unique file name.
* @returns {string}
*/
const getTempFilename = (prefix) => {
prefix = prefix || TEMP_PREFIX;
tempCounter = tempCounter >= TEMP_COUNTER_MAX ? 1 : tempCounter + 1;
return `${prefix}-${tempCounter}-${Date.now()}`;
return `${prefix || TEMP_PREFIX}-${tempCounter}-${Date.now()}`;
};
/**
* Returns true if argument is a function.
* @returns {Boolean}
* isFunc- check if argument is a function.
* @returns {boolean} - Returns true if argument is a function.
*/
const isFunc = func => func && func.constructor && func.call && func.apply ? true: false;
@ -66,7 +64,7 @@ const buildOptions = function(){
const result = {};
[...arguments].forEach(options => {
if (!options || typeof options !== 'object') return;
Object.keys(options).forEach(key => result[key] = options[key]);
Object.keys(options).forEach(i => result[i] = options[i]);
});
return result;
};
@ -74,8 +72,8 @@ const buildOptions = function(){
/**
* Builds request fields (using to build req.body and req.files)
* @param {Object} instance - request object.
* @param {String} field - field name.
* @param value - field value.
* @param {string} field - field name.
* @param {any} value - field value.
* @returns {Object}
*/
const buildFields = (instance, field, value) => {
@ -85,13 +83,13 @@ const buildFields = (instance, field, value) => {
// Non-array fields
if (!instance[field]) {
instance[field] = value;
} else {
return instance;
}
// Array fields
if (instance[field] instanceof Array) {
instance[field].push(value);
} else {
instance[field] = [instance[field], value];
}
if (instance[field] instanceof Array) {
instance[field].push(value);
} else {
instance[field] = [instance[field], value];
}
return instance;
};
@ -99,8 +97,8 @@ const buildFields = (instance, field, value) => {
/**
* Creates a folder for file specified in the path variable
* @param {Object} fileUploadOptions
* @param {String} filePath
* @returns {Boolean}
* @param {string} filePath
* @returns {boolean}
*/
const checkAndMakeDir = (fileUploadOptions, filePath) => {
// Check upload options were set.
@ -109,24 +107,22 @@ const checkAndMakeDir = (fileUploadOptions, filePath) => {
// Check whether folder for the file exists.
if (!filePath) return false;
const parentPath = path.dirname(filePath);
// Create folder if it does not exist.
if (!fs.existsSync(parentPath)) {
mkdirp.sync(parentPath);
}
// Check folder again and return the result.
// Create folder if it is not exists.
if (!fs.existsSync(parentPath)) fs.mkdirSync(parentPath, { recursive: true });
// Checks folder again and return a results.
return fs.existsSync(parentPath);
};
/**
* Delete file.
* @param {String} file - Path to the file to delete.
* @param {string} file - Path to the file to delete.
*/
const deleteFile = (file, callback) => fs.unlink(file, err => err ? callback(err) : callback());
/**
* Copy file via streams
* @param {String} src - Path to the source file
* @param {String} dst - Path to the destination file.
* @param {string} src - Path to the source file
* @param {string} dst - Path to the destination file.
*/
const copyFile = (src, dst, callback) => {
// cbCalled flag and runCb helps to run cb only once.
@ -153,8 +149,8 @@ const copyFile = (src, dst, callback) => {
/**
* moveFile - moves the file from src to dst.
* Firstly trying to rename the file if no luck copying it to dst and then deleteing src.
* @param {String} src - Path to the source file
* @param {String} dst - Path to the destination file.
* @param {string} src - Path to the source file
* @param {string} dst - Path to the destination file.
* @param {Function} callback - A callback function.
*/
const moveFile = (src, dst, callback) => fs.rename(src, dst, err => (!err
@ -165,7 +161,7 @@ const moveFile = (src, dst, callback) => fs.rename(src, dst, err => (!err
/**
* Save buffer data to a file.
* @param {Buffer} buffer - buffer to save to a file.
* @param {String} filePath - path to a file.
* @param {string} filePath - path to a file.
*/
const saveBufferToFile = (buffer, filePath, callback) => {
if (!Buffer.isBuffer(buffer)) {
@ -197,9 +193,9 @@ const uriDecodeFileName = (opts, fileName) => {
/**
* Parses filename and extension and returns object {name, extension}.
* @param preserveExtension {Boolean, Integer} - true/false or number of characters for extension.
* @param fileName {String} - file name to parse.
* @returns {Object} - {name, extension}.
* @param {boolean|integer} preserveExtension - true/false or number of characters for extension.
* @param {string} fileName - file name to parse.
* @returns {Object} - { name, extension }.
*/
const parseFileNameExtension = (preserveExtension, fileName) => {
const preserveExtensionLengh = parseInt(preserveExtension);
@ -231,9 +227,9 @@ const parseFileNameExtension = (preserveExtension, fileName) => {
/**
* Parse file name and extension.
* @param opts {Object} - middleware options.
* @param fileName {String} - Uploaded file name.
* @returns {String}
* @param {Object} opts - middleware options.
* @param {string} fileName - Uploaded file name.
* @returns {string}
*/
const parseFileName = (opts, fileName) => {
// Cut off file name if it's lenght more then 255.

142
package-lock.json generated

@ -1,6 +1,6 @@
{
"name": "express-fileupload",
"version": "1.1.6",
"version": "1.1.7-alpha.3",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -58,9 +58,9 @@
}
},
"acorn": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.0.tgz",
"integrity": "sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==",
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz",
"integrity": "sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==",
"dev": true
},
"acorn-jsx": {
@ -509,15 +509,15 @@
"dev": true
},
"coveralls": {
"version": "3.0.9",
"resolved": "https://registry.npmjs.org/coveralls/-/coveralls-3.0.9.tgz",
"integrity": "sha512-nNBg3B1+4iDox5A5zqHKzUTiwl2ey4k2o0NEcVZYvl+GOSJdKBj4AJGKLv6h3SvWch7tABHePAQOSZWM9E2hMg==",
"version": "3.0.11",
"resolved": "https://registry.npmjs.org/coveralls/-/coveralls-3.0.11.tgz",
"integrity": "sha512-LZPWPR2NyGKyaABnc49dR0fpeP6UqhvGq4B5nUrTQ1UBy55z96+ga7r+/ChMdMJUwBgyJDXBi88UBgz2rs9IiQ==",
"dev": true,
"requires": {
"js-yaml": "^3.13.1",
"lcov-parse": "^1.0.0",
"log-driver": "^1.2.7",
"minimist": "^1.2.0",
"minimist": "^1.2.5",
"request": "^2.88.0"
},
"dependencies": {
@ -669,9 +669,9 @@
"dev": true
},
"es-abstract": {
"version": "1.17.4",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz",
"integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==",
"version": "1.17.5",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz",
"integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==",
"dev": true,
"requires": {
"es-to-primitive": "^1.2.1",
@ -1655,8 +1655,12 @@
"lodash": {
"version": "4.17.15",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
<<<<<<< HEAD
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
"dev": true
=======
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
>>>>>>> d55fa83832351eb3e44e7d2d14c9840ffc5d1b0e
},
"log-driver": {
"version": "1.2.7",
@ -1665,12 +1669,12 @@
"dev": true
},
"log-symbols": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz",
"integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==",
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz",
"integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==",
"dev": true,
"requires": {
"chalk": "^2.0.1"
"chalk": "^2.4.2"
}
},
"md5": {
@ -1739,12 +1743,13 @@
}
},
"minimist": {
"version": "1.2.0",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
"dev": true
},
"mkdirp": {
<<<<<<< HEAD
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
@ -1759,12 +1764,20 @@
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
"dev": true
}
=======
"version": "0.5.5",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
"dev": true,
"requires": {
"minimist": "^1.2.5"
>>>>>>> d55fa83832351eb3e44e7d2d14c9840ffc5d1b0e
}
},
"mocha": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/mocha/-/mocha-7.0.1.tgz",
"integrity": "sha512-9eWmWTdHLXh72rGrdZjNbG3aa1/3NRPpul1z0D979QpEnFdCG0Q5tv834N+94QEN2cysfV72YocQ3fn87s70fg==",
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/mocha/-/mocha-7.1.1.tgz",
"integrity": "sha512-3qQsu3ijNS3GkWcccT5Zw0hf/rWvu1fTN9sPvEd81hlwsr30GX2GcDSSoBxo24IR8FelmrAydGC6/1J5QQP4WA==",
"dev": true,
"requires": {
"ansi-colors": "3.2.3",
@ -1778,9 +1791,9 @@
"growl": "1.10.5",
"he": "1.2.0",
"js-yaml": "3.13.1",
"log-symbols": "2.2.0",
"log-symbols": "3.0.0",
"minimatch": "3.0.4",
"mkdirp": "0.5.1",
"mkdirp": "0.5.3",
"ms": "2.1.1",
"node-environment-flags": "1.0.6",
"object.assign": "4.1.0",
@ -1788,8 +1801,8 @@
"supports-color": "6.0.0",
"which": "1.3.1",
"wide-align": "1.1.3",
"yargs": "13.3.0",
"yargs-parser": "13.1.1",
"yargs": "13.3.2",
"yargs-parser": "13.1.2",
"yargs-unparser": "1.6.0"
},
"dependencies": {
@ -1812,6 +1825,15 @@
"esprima": "^4.0.0"
}
},
"mkdirp": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.3.tgz",
"integrity": "sha512-P+2gwrFqx8lhew375MQHHeTlY8AuOJSrGf0R5ddkEndUkmwpgUob/vQuBD1V22/Cw1/lJr4x+EjllSezBThzBg==",
"dev": true,
"requires": {
"minimist": "^1.2.5"
}
},
"ms": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
@ -2010,9 +2032,9 @@
"dev": true
},
"p-limit": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz",
"integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==",
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
"dev": true,
"requires": {
"p-try": "^2.0.0"
@ -2079,9 +2101,9 @@
"dev": true
},
"picomatch": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.1.tgz",
"integrity": "sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA==",
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
"integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
"dev": true
},
"prelude-ls": {
@ -2113,9 +2135,9 @@
}
},
"psl": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.7.0.tgz",
"integrity": "sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ==",
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
"integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==",
"dev": true
},
"punycode": {
@ -2477,24 +2499,46 @@
}
}
},
"string.prototype.trimend": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.0.tgz",
"integrity": "sha512-EEJnGqa/xNfIg05SxiPSqRS7S9qwDhYts1TSLR1BQfYUfPe1stofgGKvwERK9+9yf+PpfBMlpBaCHucXGPQfUA==",
"dev": true,
"requires": {
"define-properties": "^1.1.3",
"es-abstract": "^1.17.5"
}
},
"string.prototype.trimleft": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz",
"integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==",
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz",
"integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==",
"dev": true,
"requires": {
"define-properties": "^1.1.3",
"function-bind": "^1.1.1"
"es-abstract": "^1.17.5",
"string.prototype.trimstart": "^1.0.0"
}
},
"string.prototype.trimright": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz",
"integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==",
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz",
"integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==",
"dev": true,
"requires": {
"define-properties": "^1.1.3",
"function-bind": "^1.1.1"
"es-abstract": "^1.17.5",
"string.prototype.trimend": "^1.0.0"
}
},
"string.prototype.trimstart": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.0.tgz",
"integrity": "sha512-iCP8g01NFYiiBOnwG1Xc3WZLyoo+RuBymwIlWncShXDDJYWN6DbnM3odslBJdgCdRlq94B5s63NWAZlcn2CS4w==",
"dev": true,
"requires": {
"define-properties": "^1.1.3",
"es-abstract": "^1.17.5"
}
},
"string.prototype.trimright": {
@ -2956,9 +3000,9 @@
"dev": true
},
"yargs": {
"version": "13.3.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz",
"integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==",
"version": "13.3.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz",
"integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==",
"dev": true,
"requires": {
"cliui": "^5.0.0",
@ -2970,7 +3014,7 @@
"string-width": "^3.0.0",
"which-module": "^2.0.0",
"y18n": "^4.0.0",
"yargs-parser": "^13.1.1"
"yargs-parser": "^13.1.2"
},
"dependencies": {
"emoji-regex": {
@ -2999,9 +3043,9 @@
}
},
"yargs-parser": {
"version": "13.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz",
"integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==",
"version": "13.1.2",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
"integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
"dev": true,
"requires": {
"camelcase": "^5.0.0",

@ -1,6 +1,6 @@
{
"name": "express-fileupload",
"version": "1.1.6",
"version": "1.1.7-alpha.3",
"author": "Richard Girges <richardgirges@gmail.com>",
"description": "Simple express file upload middleware that wraps around Busboy",
"main": "./lib/index",
@ -13,7 +13,7 @@
"busboy": "^0.3.1"
},
"engines": {
"node": ">=6.0.0"
"node": ">=8.0.0"
},
"keywords": [
"express",
@ -29,12 +29,12 @@
"repository": "richardgirges/express-fileupload",
"devDependencies": {
"body-parser": "^1.19.0",
"coveralls": "^3.0.9",
"coveralls": "^3.0.11",
"eslint": "^6.8.0",
"express": "^4.17.1",
"istanbul": "^0.4.5",
"md5": "^2.2.1",
"mocha": "^7.0.1",
"mocha": "^7.1.1",
"rimraf": "^3.0.2",
"supertest": "^4.0.2"
}

@ -0,0 +1,28 @@
'use strict';
const assert = require('assert');
const UploadTimer = require('../lib/uploadtimer');
describe('Test UploadTimer class', () => {
it('It runs a callback function after specified timeout.', (done) => {
const uploadTimer = new UploadTimer(1000, done);
uploadTimer.set();
});
it('set method returns true if timeout specified.', () => {
const uploadTimer = new UploadTimer(1000);
assert.equal(uploadTimer.set(), true);
});
it('set method returns false if timeout has not specified.', () => {
const uploadTimer = new UploadTimer();
assert.equal(uploadTimer.set(), false);
});
it('set method returns false if zero timeout has specified.', () => {
const uploadTimer = new UploadTimer(0);
assert.equal(uploadTimer.set(), false);
});
});

@ -174,6 +174,12 @@ describe('Test of the utilities functions', function() {
assert.equal(result, expected);
});
it('Returns a temporary file name if name argument is empty.', () => {
const opts = {safeFileNames: false};
const result = parseFileName(opts);
assert.equal(typeof result, 'string');
});
});
//buildOptions tests
describe('Test buildOptions function', () => {

Loading…
Cancel
Save