replace connect-multiparty with Multer (#13439)

* post upload route

* more multer changes

keep name and type fields in file objects so we dont break all plugins using these

* remove log

* fix: thumbs delete

* test: add array check
This commit is contained in:
Barış Uşaklı
2025-05-20 10:45:56 -04:00
committed by GitHub
parent 3c09e6247f
commit 385f4f12be
12 changed files with 73 additions and 53 deletions

View File

@@ -5,7 +5,6 @@ const validator = require('validator');
const nconf = require('nconf');
const toobusy = require('toobusy-js');
const util = require('util');
const multipart = require('connect-multiparty');
const { csrfSynchronisedProtection } = require('./csrf');
const plugins = require('../plugins');
@@ -27,7 +26,7 @@ const delayCache = cacheCreate({
ttl: 1000 * 60,
max: 200,
});
const multipartMiddleware = multipart();
const middleware = module.exports;
@@ -101,17 +100,30 @@ middleware.pluginHooks = helpers.try(async (req, res, next) => {
});
middleware.validateFiles = function validateFiles(req, res, next) {
if (!req.files.files) {
if (!req.files) {
return next(new Error(['[[error:invalid-files]]']));
}
if (Array.isArray(req.files.files) && req.files.files.length) {
return next();
function makeFilesCompatible(files) {
if (Array.isArray(files)) {
// multer uses originalname and mimetype, but we use name and type
files.forEach((file) => {
if (file.originalname) {
file.name = file.originalname;
}
if (file.mimetype) {
file.type = file.mimetype;
}
});
}
next();
}
if (Array.isArray(req.files) && req.files.length) {
return makeFilesCompatible(req.files);
}
if (typeof req.files.files === 'object') {
req.files.files = [req.files.files];
return next();
if (typeof req.files === 'object') {
req.files = [req.files];
return makeFilesCompatible(req.files);
}
return next(new Error(['[[error:invalid-files]]']));
@@ -291,14 +303,3 @@ middleware.checkRequired = function (fields, req, res, next) {
controllers.helpers.formatApiResponse(400, res, new Error(`[[error:required-parameters-missing, ${missing.join(' ')}]]`));
};
middleware.handleMultipart = (req, res, next) => {
// Applies multipart handler on applicable content-type
const { 'content-type': contentType } = req.headers;
if (contentType && !contentType.startsWith('multipart/form-data')) {
return next();
}
multipartMiddleware(req, res, next);
};

View File

@@ -23,7 +23,7 @@ exports.ratelimit = helpers.try(async (req, res, next) => {
ttl: meta.config.uploadRateLimitCooldown * 1000,
});
}
const count = (cache.get(`${req.ip}:uploaded_file_count`) || 0) + req.files.files.length;
const count = (cache.get(`${req.ip}:uploaded_file_count`) || 0) + req.files.length;
if (count > meta.config.uploadRateLimitThreshold) {
return next(new Error(['[[error:upload-ratelimit-reached]]']));
}