expressjs / multer

Node.js middleware for handling `multipart/form-data`.
MIT License
11.63k stars 1.06k forks source link

file.size undefined with multiple files #1246

Closed djcaesar9114 closed 8 months ago

djcaesar9114 commented 8 months ago

I'm using multer to handle a multi-file upload, and the middleware "filename", like this:

  filename: async (req, file, cb) => {
    console.log(Object.keys(file));
    ({ rows } = await db.query(`
    INSERT INTO public.files(
      uuid,
      nom,
      type,
      size
    )
    VALUES
    ($1, $2, $3, $4)
    RETURNING *`, [
      req.uuid,
      file.originalname,
      file.mimetype,
      file.size,
      // +req.headers["content-length"],
    ]));
    cb(null, uuid);
  },

The problem is that file.size remains undefined. I control that the size exists before sending the files to the API. When I check which properties are available (see the console.log), I only have 'fieldname', 'originalname', 'encoding', 'mimetype'.

If I use +req.headers["content-length"] it takes into account the size of all the request (all the files), and not only the current file.

Why can't I have the file size? Is it impossible or should I edit some setting I haven't found in the documentation?

I think it's because multer is base on busboy, and there could be a way from here:

https://github.com/expressjs/multer/blob/aa42bea6ac7d0cb8fcb279b15a7278cda805dc63/lib/make-middleware.js#L97

Either busboy gives the size (I opened an issue here: https://github.com/mscdex/busboy/issues/354), or multer can estimate the size with the filestream. That would be a good solution, in my opinion.

Doc999tor commented 8 months ago

Why the file.size is undefined:

  1. storage.filename callback arguments are based on request content disposition header: filename, content-type etc. In multer().single() middleware the file is already being uploaded and you can have more detailed file stats
  2. https://github.com/expressjs/multer/blob/master/lib/make-middleware.js#L106

      var file = { // initial content disposition header reading
        fieldname: fieldname,
        originalname: filename,
        encoding: encoding,
        mimetype: mimetype
      }

    https://github.com/expressjs/multer/blob/master/storage/disk.js#L47

      outStream.on('finish', function () {
        cb(null, {
          destination: destination,
          filename: filename,
          path: finalPath,
          size: outStream.bytesWritten // actual filesize stat from the finished stream
        })
      })

https://github.com/expressjs/multer/blob/master/lib/make-middleware.js#L158

     var fileInfo = extend(file, info) // extending the initial file object with actual file stats
  1. For your use case, you can move the db population to later middleware, when the files will already be uploaded and written to disk
djcaesar9114 commented 8 months ago

Thanks!