UNPKG

multer

Version:

Middleware for handling `multipart/form-data`.

98 lines (76 loc) 2.87 kB
var fs = require('fs') var os = require('os') var path = require('path') var crypto = require('crypto') var pipeline = require('stream').pipeline var MulterError = require('../lib/multer-error') // Write streams still open for a file, so _removeFile can wait for the // descriptor to be closed before unlinking (Windows refuses to unlink open files). var openStreams = new WeakMap() function getFilename (req, file, cb) { crypto.randomBytes(16, function (err, raw) { cb(err, err ? undefined : raw.toString('hex')) }) } function getDestination (req, file, cb) { cb(null, os.tmpdir()) } function DiskStorage (opts) { this.getFilename = (opts.filename || getFilename) if (typeof opts.destination === 'string') { fs.mkdirSync(opts.destination, { recursive: true }) this.getDestination = function ($0, $1, cb) { cb(null, opts.destination) } } else { this.getDestination = (opts.destination || getDestination) } } DiskStorage.prototype._handleFile = function _handleFile (req, file, cb) { var that = this that.getDestination(req, file, function (err, destination) { if (err) return cb(err) that.getFilename(req, file, function (err, filename) { if (err) return cb(err) var finalPath = path.join(destination, filename) if (file.stream.destroyed) return cb(new MulterError('STREAM_DESTROYED')) var outStream = fs.createWriteStream(finalPath) file.path = finalPath openStreams.set(file, outStream) outStream.once('close', function () { openStreams.delete(file) }) pipeline(file.stream, outStream, function (err) { if (err) return cb(err) cb(null, { destination: destination, filename: filename, path: finalPath, size: outStream.bytesWritten }) }) }) }) } DiskStorage.prototype._removeFile = function _removeFile (req, file, cb) { var path = file.path delete file.destination delete file.filename delete file.path var outStream = openStreams.get(file) if (!outStream) return fs.unlink(path, cb) // Unlink only once the descriptor has been released. `closed` is set when // the descriptor is closed on every supported Node.js version, whereas // 'close' is not emitted after a write stream is destroyed with an error on // Node.js < 14 (emitClose defaults to false there), so wait for 'close' or // 'error', whichever comes first. destroy() is a no-op if the stream is // already being torn down. if (outStream.closed) return fs.unlink(path, cb) function onReleased () { outStream.removeListener('close', onReleased) outStream.removeListener('error', onReleased) fs.unlink(path, cb) } outStream.once('close', onReleased) outStream.once('error', onReleased) outStream.destroy() } module.exports = function (opts) { return new DiskStorage(opts) }