From 8418fc12e20c61d77d328cf520b119a6866d308a Mon Sep 17 00:00:00 2001 From: viral32111 <19510403+viral32111@users.noreply.github.com> Date: Mon, 9 Jan 2023 13:06:08 +0000 Subject: [PATCH] Better errors for file too big/too many files --- Client/scripts/helpers/serverErrorCodes.js | 5 +- Server/source/enumerations/errorCodes.ts | 5 +- Server/source/enumerations/httpStatusCodes.ts | 1 + Server/source/routes/chat.ts | 70 ++++++++++++++----- 4 files changed, 62 insertions(+), 19 deletions(-) diff --git a/Client/scripts/helpers/serverErrorCodes.js b/Client/scripts/helpers/serverErrorCodes.js index 588a282..750212a 100644 --- a/Client/scripts/helpers/serverErrorCodes.js +++ b/Client/scripts/helpers/serverErrorCodes.js @@ -16,7 +16,10 @@ const serverErrorCodeMessages = { 12: "No files uploaded", 13: "No data available", 14: "Failed to perform operation(s) on the database", - 15: "WebSocket failed to broadcast payload" + 15: "WebSocket failed to broadcast payload", + 16: "You have uploaded too many files", + 17: "One or more of the files you uploaded is too large", + 18: "Failed to upload file(s)" } // Shows the feedback modal for a server API error diff --git a/Server/source/enumerations/errorCodes.ts b/Server/source/enumerations/errorCodes.ts index 7c33a8d..9c3508d 100644 --- a/Server/source/enumerations/errorCodes.ts +++ b/Server/source/enumerations/errorCodes.ts @@ -15,5 +15,8 @@ export enum ErrorCodes { NoFilesUploaded = 12, NoData = 13, DatabaseOperationFailure = 14, - BroadcastFailure = 15 + BroadcastFailure = 15, + UploadTooManyFiles = 16, + UploadFileTooLarge = 17, + UploadFailed = 18 } diff --git a/Server/source/enumerations/httpStatusCodes.ts b/Server/source/enumerations/httpStatusCodes.ts index ab79ded..f5c5513 100644 --- a/Server/source/enumerations/httpStatusCodes.ts +++ b/Server/source/enumerations/httpStatusCodes.ts @@ -4,6 +4,7 @@ export enum HTTPStatusCodes { BadRequest = 400, Unauthorized = 401, Forbidden = 403, + PayloadTooLarge = 413, UpgradeRequired = 426, InternalServerError = 500, NotImplemented = 501 diff --git a/Server/source/routes/chat.ts b/Server/source/routes/chat.ts index 4a6c989..156803d 100644 --- a/Server/source/routes/chat.ts +++ b/Server/source/routes/chat.ts @@ -3,6 +3,7 @@ import { getLogger } from "log4js" import { ObjectId } from "mongodb" import { Request } from "express" import { RawData, WebSocket } from "ws" +import { MulterError } from "multer" // Import code from other scripts import { expressApp, webSocketServer, multerMiddleware } from "../main" @@ -45,7 +46,8 @@ expressApp.get( "/api/chat", ( request, response ) => { } ) // Route for uploading files to use as message attachments -expressApp.put( "/api/upload", multerMiddleware.any(), ( request, response ) => { +const multerRequestHandler = multerMiddleware.any() +expressApp.put( "/api/upload", ( request, response ) => { // Fail if the guest has not chosen a name yet if ( request.session.guestId === undefined ) return respondToRequest( response, HTTPStatusCodes.Unauthorized, { @@ -62,26 +64,60 @@ expressApp.put( "/api/upload", multerMiddleware.any(), ( request, response ) => error: ErrorCodes.InvalidContentType } ) - // Fail if no files were uploaded - if ( request.files === undefined ) return respondToRequest( response, HTTPStatusCodes.BadRequest, { - error: ErrorCodes.NoFilesUploaded - } ) + // Attempt to receive any uploaded files + multerRequestHandler( request, response, ( error ) => { + + // If there was an Multer-specific error... + if ( error instanceof MulterError ) { + log.error( `Failed to handle uploaded files for guest '${ request.session.guestId }' in room '${ request.session.roomId } (${ error.message })!'` ) + + // Respond based on the type of error - https://github.com/expressjs/multer/blob/master/lib/multer-error.js + if ( error.code === "LIMIT_PART_COUNT" || error.code === "LIMIT_FILE_COUNT" || error.code === "LIMIT_FIELD_COUNT" ) { + return respondToRequest( response, HTTPStatusCodes.PayloadTooLarge, { + error: ErrorCodes.UploadTooManyFiles + } ) + } else if ( error.code === "LIMIT_FILE_SIZE" || error.code === "LIMIT_FIELD_VALUE" ) { + return respondToRequest( response, HTTPStatusCodes.PayloadTooLarge, { + error: ErrorCodes.UploadFileTooLarge + } ) + } else { + return respondToRequest( response, HTTPStatusCodes.BadRequest, { + error: ErrorCodes.UploadFailed + } ) + } + + // If there was a generic error... + } else if ( error ) { + log.error( `Failed to process uploaded files for guest '${ request.session.guestId }' in room '${ request.session.roomId } (${ error })!'` ) + return respondToRequest( response, HTTPStatusCodes.BadRequest, { + error: ErrorCodes.UploadFailed + } ) + } - // Cast because TypeScript doesn't know how to do this automatically - const uploadedFiles = request.files as Express.Multer.File[] + // If we got to this point, then no errors occured - // Loop through the uploaded files & add their type and URL to a payload for the response - const filesPayload: Attachment[] = [] - for ( const file of uploadedFiles ) filesPayload.push( { - type: file.mimetype, - path: `/attachments/${ file.filename }` - } ) + // Fail if no files were uploaded + if ( request.files === undefined || request.files.length <= 0 ) return respondToRequest( response, HTTPStatusCodes.BadRequest, { + error: ErrorCodes.NoFilesUploaded + } ) + + // Cast because TypeScript doesn't know how to do this automatically + const uploadedFiles = request.files as Express.Multer.File[] + + // Loop through the uploaded files & add their type and URL to a payload for the response + const filesPayload: Attachment[] = [] + for ( const file of uploadedFiles ) filesPayload.push( { + type: file.mimetype, + path: `/attachments/${ file.filename }` + } ) + + // Send back the list of uploaded files + respondToRequest( response, HTTPStatusCodes.OK, { + files: filesPayload + } ) + log.info( `Guest '${ request.session.guestId }' uploaded ${ uploadedFiles } files.` ) - // Send back the list of uploaded files - respondToRequest( response, HTTPStatusCodes.OK, { - files: filesPayload } ) - log.info( `Guest '${ request.session.guestId }' uploaded ${ uploadedFiles } files.` ) } )