UNPKG

uploadio

Version:

Simple middleware for uploading files.

139 lines (128 loc) 3.67 kB
const fs = require('fs'); const path = require('path'); const { Readable } = require('stream'); // Parameters for safe file name parsing. const SAFE_FILE_NAME_REGEX = /[^\w-]/g; const MAX_EXTENSION_LENGTH = 3; // Parameters to generate unique temporary file names: const TEMP_COUNTER_MAX = 65536; const TEMP_PREFIX = 'tmp'; let tempCounter = 0; /** * Builds instance options from arguments objects(can't be arrow function). * @returns {Object} - result options. */ const buildOptions = function () { const result = {}; [...arguments].forEach((options) => { if (!options || typeof options !== 'object') { return true; } Object.keys(options).forEach((i) => (result[i] = options[i])); }); return result; }; /** * Logs message to console if debug option set to true. * @param {Object} options - options object. * @param {string} msg - message to log. * @returns {boolean} - false if debug is off. */ const debugLog = (options, msg) => { const opts = options || {}; if (!opts.debug) { return false; } console.log(`File upload: ${msg}`); // eslint-disable-line return true; }; /** * Decodes uriEncoded file names. * @param fileName {String} - file name to decode. * @returns {String} */ const uriDecodeFileName = (opts, fileName) => { return opts.uriDecodeFileNames ? decodeURIComponent(fileName) : fileName; }; /** * Generates unique temporary file name. e.g. tmp-5000-156788789789. * @param {string} prefix - a prefix for generated unique file name. * @returns {string} */ const getTempFilename = (prefix = TEMP_PREFIX) => { tempCounter = tempCounter >= TEMP_COUNTER_MAX ? 1 : tempCounter + 1; return `${prefix}-${tempCounter}-${Date.now()}`; }; const parseFileName = (opts, fileName) => { // Check fileName argument if (!fileName || typeof fileName !== 'string') { return getTempFilename(); } // Cut off file name if it's lenght more then 255. const fileLength = 255; const parsedName = fileName.length <= fileLength ? fileName : fileName.substr(0, fileLength); // Decode file name if uriDecodeFileNames option set true. return uriDecodeFileName(opts, parsedName); }; /** * Creates a folder for file specified in the path variable * @param {Object} fileUploadOptions * @param {string} filePath * @returns {boolean} */ const checkAndMakeDir = (fileUploadOptions, filePath) => { // Check upload options were set. if (!fileUploadOptions) { return false; } if (!fileUploadOptions.createParentPath) { return false; } // Check whether folder for the file exists. if (!filePath) { return false; } const parentPath = path.dirname(filePath); // Create folder if it doesn't exist. if (!fs.existsSync(parentPath)) { fs.mkdirSync(parentPath, { recursive: true, }); } // Checks folder again and return a results. return fs.existsSync(parentPath); }; /** * Builds request fields (using to build req.body and req.files) * @param {Object} instance - request object. * @param {string} field - field name. * @param {any} value - field value. * @returns {Object} */ const buildFields = (instance, field, value) => { // Do nothing if value is not set. if (value === null || value === undefined) { return instance; } instance = instance || {}; // Non-array fields if (!instance[field]) { instance[field] = value; return instance; } // Array fields if (instance[field] instanceof Array) { instance[field].push(value); } else { instance[field] = [instance[field], value]; } return instance; }; module.exports = { buildOptions, checkAndMakeDir, debugLog, parseFileName, buildFields, };