multer icon indicating copy to clipboard operation
multer copied to clipboard

Different file size limitation based on file type

Open olefrank opened this issue 8 years ago • 10 comments

I have an endpoint to upload files. I would like to have different file size limits depending on the file type. Images size limit =< .5 MB and PDF size limit =< 2MB.

The limits.fileSize options only allows for one value, and I can't do it in the fileFilter property either... So how could I do it?

olefrank avatar Mar 13 '18 12:03 olefrank

I think you should be able to do it with the fileFilter property?

function fileFilter (req, file, cb) {
  if (file.mimetype === 'application/pdf' && file. size > 2 * 1014 * 1024) {
    return cb(new Error('File too large'))
  }

  cb(null, true)
}

LinusU avatar Mar 14 '18 10:03 LinusU

@LinusU , I can't get 'size' from file inside fileFilter(), other fields are: { fieldname: 'xxxx', originalname: 'xxxx-xxxx.jpg', encoding: '7bit', mimetype: 'image/jpeg' }

version: "multer": "^1.3.0"

flight9 avatar Mar 20 '18 02:03 flight9

Ah, I see 🤔

Right, I remember now, yeah the length is not given prior to consuming the stream...

Hmm, this is currently unsupported, any suggestions on how an API might look?

Also, in the 2.0 alpha you should be able to do this fairly easy:

(req, res, next) => {
  switch (req.file.detectedMimeType) {
    case 'image/jpeg':
    case 'image/png':
    case 'image/gif':
      if (req.file.size > 512 * 1024) {
        return next(new Error('File too large'))
      }
      break
    case 'application/pdf':
      if (req.file.size > 2 * 1024 * 1024) {
        return next(new Error('File too large'))
      }
      break
    default:
      return next(new Error('Unspported file type'))
  }

  // Use `req.file` here
}

LinusU avatar Mar 20 '18 10:03 LinusU

Considering https://github.com/expressjs/multer/issues/568 this will not remove the temp file and file handle will not be closed.

ecmel avatar Mar 27 '18 07:03 ecmel

@ecmel They should be unlinked as soon as they are opened, which should happen regardless of whether you read the file or not:

https://github.com/expressjs/multer/blob/c4b223efc4730611f7c6bfe9608bfd4048e3754d/lib/middleware.js#L24-L32

That issue was originally opened about an EPERM error...

LinusU avatar Mar 28 '18 14:03 LinusU

But as far as I understand, if there is an error and next is called with an error the file will never be opened and never removed from temp

Am I wrong?

ecmel avatar Mar 28 '18 14:03 ecmel

The file will be opened shortly after the call to createReadStream so the temporary file will be removed. This should be easy to confirm as well.

However, I just realized that there is an FD leak going on when ReadStream is garbage collected... made some comments about it here: #570

LinusU avatar Mar 28 '18 15:03 LinusU

Hi @LinusU

I have the same problem on Multer 1.4.2. I need to limit the file size on base of the file type for my project. It would be really nice, if that would be possible inside the file filter function.

Or can you expect when there will be a stable release for Multer 2.0?

msteini82 avatar Aug 27 '19 23:08 msteini82

there is size of file in req.rawHeaders(it a array) in my request last item is size of file so I used (req.rawHeaders.slice(-1)[0]) ,after that I write a logic in fileFilter based on type file, It's work to me, multer should be .any

in this logic, size of .pdf < 1 Mb and .png,.jpeg,.jpg < 4 Mb

const multer = require('multer');
const { v4: uuid } = require("uuid");

const TYPE_IMAGE = {
  'image/png': 'png',
  'image/jpeg': 'jpeg',
  'image/jpg': 'jpg'
};
const TYPE_File = {
  'application/pdf': 'pdf',
};

const fileUpload = 
  multer({
    limits: 500000, 
    storage: multer.diskStorage({
      destination: (req, file, cb) => {
        cb(null, 'uploads/images');
      },
      filename: (req, file, cb) => {
        const ext = (TYPE_IMAGE[file.mimetype]) ? TYPE_IMAGE[file.mimetype] : TYPE_File[file.mimetype];
        cb(null, uuid() + '.' + ext);
      }
    }),
    fileFilter: (req, file, cb) => {
      let size = +req.rawHeaders.slice(-1)[0]
      let isValid =false;
      if(!!TYPE_IMAGE[file.mimetype] && size < 4 * 1024 * 1024  ){
        isValid = true
      }
      if(!!TYPE_File[file.mimetype] && size < 1 * 1024 * 1024  ){
        isValid = true
      }
      let error = isValid ? null : new Error('Invalid mime type!');
      cb(error, isValid);
    }
  }).any();


module.exports = fileUpload;

myas92 avatar Jan 30 '21 08:01 myas92

+req.rawHeaders.slice(-1)[0] is giving size of full content we are uploading , if we are passig an array of fiels and wants to validate size of each file inside array then this solution is not helping.

is there any other solution thrugh which we can get size of each file of array inside filefilter ?

ravi31srv avatar Jun 03 '22 07:06 ravi31srv