From a10fa54371a2373dc4fe37ceab8f0e28a289967e Mon Sep 17 00:00:00 2001 From: ShakMR Date: Tue, 2 Jan 2018 23:36:08 +0100 Subject: [PATCH] Adding option to select between two behaviour when file over fileSize --- .gitignore | 1 + README.md | 2 ++ lib/index.js | 11 +++--- test/fileLimitUploads.spec.js | 66 +++++++++++++++++++++++++---------- test/server.js | 13 +++++++ 5 files changed, 71 insertions(+), 22 deletions(-) diff --git a/.gitignore b/.gitignore index 2afb857..9864688 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ ehthumbs.db Desktop.ini .directory *~ +.idea npm-debug.log node_modules *.log diff --git a/README.md b/README.md index 036d8be..883fef1 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,7 @@ The **req.files.foo** object will contain the following: * `req.files.foo.mv`: A function to move the file elsewhere on your server * `req.files.foo.mimetype`: The mimetype of your file * `req.files.foo.data`: A buffer representation of your file +* `req.files.foo.truncated`: A boolean that represents if the file is over the size limit ### Full Example **Your node.js code:** @@ -120,6 +121,7 @@ Option | Acceptable Values | Details --- | --- | --- safeFileNames | | Strips characters from the upload's filename. You can use custom regex to determine what to strip. If set to `true`, non-alphanumeric characters _except_ dashes and underscores will be stripped. This option is off by default.

**Example #1 (strip slashes from file names):** `app.use(fileUpload({ safeFileNames: /\\/g }))`
**Example #2:** `app.use(fileUpload({ safeFileNames: true }))` preserveExtension | | Preserves filename extension when using safeFileNames option. If set to true, will default to an extension length of 3. If set to *Number*, this will be the max allowable extension length. If an extension is smaller than the extension length, it remains untouched. If the extension is longer, it is shifted.

**Example #1 (true):**
app.use(fileUpload({ safeFileNames: true, preserveExtension: true }));
*myFileName.ext* --> *myFileName.ext*

**Example #2 (max extension length 2, extension shifted):**
app.use(fileUpload({ safeFileNames: true, preserveExtension: 2 }));
*myFileName.ext* --> *myFileNamee.xt* +abortOnLimit | | Returns a HTTP 413 when the file is bigger than the size limit if true. Otherwise, it will add a truncate = true to the resulting file structure. # Help Wanted Pull Requests are welcomed! diff --git a/lib/index.js b/lib/index.js index 712ff78..02965ac 100644 --- a/lib/index.js +++ b/lib/index.js @@ -74,8 +74,10 @@ function processMultipart(options, req, res, next) { let safeFileNameRegex = /[^\w-]/g; file.on('limit', () => { - res.writeHead(413, {'Connection': 'close'}); - res.end('File size limit has been reached'); + if (options.abortOnLimit) { + res.writeHead(413, {'Connection': 'close'}); + res.end('File size limit has been reached'); + } }); file.on('data', function(data) { @@ -138,6 +140,7 @@ function processMultipart(options, req, res, next) { name: filename, data: buf, encoding: encoding, + truncated: file.truncated, mimetype: mime, mv: function(path, callback) { // Callback is passed in, use the callback API @@ -161,8 +164,8 @@ function processMultipart(options, req, res, next) { /** * Local function that moves the file to a different location on the filesystem * Takes two function arguments to make it compatible w/ Promise or Callback APIs - * @param {Function} successFunc - * @param {Function} errorFunc + * @param {Function} successFunc + * @param {Function} errorFunc */ function doMove(successFunc, errorFunc) { const fstream = fs.createWriteStream(path); diff --git a/test/fileLimitUploads.spec.js b/test/fileLimitUploads.spec.js index c1278ef..c88b4cf 100644 --- a/test/fileLimitUploads.spec.js +++ b/test/fileLimitUploads.spec.js @@ -2,35 +2,65 @@ const path = require('path'); const request = require('supertest'); +const assert = require('assert'); const server = require('./server'); -const app = server.setup({ - limits: {fileSize: 200 * 1024} // set 200kb upload limit -}); const clearUploadsDir = server.clearUploadsDir; const fileDir = server.fileDir; describe('Test Single File Upload With File Size Limit', function() { - it(`upload 'basketball.png' (~154kb) with 200kb size limit`, function(done) { - let filePath = path.join(fileDir, 'basketball.png'); + let app; + beforeEach(function() { clearUploadsDir(); + }); + + describe('abort connection on limit reached', function() { + before(function() { + app = server.setup({ + limits: {fileSize: 200 * 1024}, // set 200kb upload limit + abortOnLimit: true + }); + }); + + it(`upload 'basketball.png' (~154kb) with 200kb size limit`, function(done) { + let filePath = path.join(fileDir, 'basketball.png'); - request(app) - .post('/upload/single') - .attach('testFile', filePath) - .expect(200) - .end(done); + request(app) + .post('/upload/single/truncated') + .attach('testFile', filePath) + .expect(200) + .end(done); + }); + + it(`fail when uploading 'car.png' (~269kb) with 200kb size limit`, function(done) { + let filePath = path.join(fileDir, 'car.png'); + + request(app) + .post('/upload/single/truncated') + .attach('testFile', filePath) + .expect(413) + .end(done); + }); }); - it(`fail when uploading 'car.png' (~269kb) with 200kb size limit`, function(done) { - let filePath = path.join(fileDir, 'car.png'); + describe('pass truncated file to the next handler', function() { + before(function() { + app = server.setup({ + limits: {fileSize: 200 * 1024} // set 200kb upload limit + }); + }); - clearUploadsDir(); + it(`fail when uploading 'car.png' (~269kb) with 200kb size limit`, function(done) { + let filePath = path.join(fileDir, 'car.png'); - request(app) - .post('/upload/single') - .attach('testFile', filePath) - .expect(413) - .end(done); + request(app) + .post('/upload/single/truncated') + .attach('testFile', filePath) + .expect(400) + .end(function(err, res) { + assert.ok(res.error.text === 'File too big'); + done(); + }); + }); }); }); diff --git a/test/server.js b/test/server.js index ea305c2..826b653 100644 --- a/test/server.js +++ b/test/server.js @@ -92,6 +92,19 @@ const setup = function(fileUploadOptions) { }); }); + app.all('/upload/single/truncated', function(req, res) { + if (!req.files) { + return res.status(400).send('No files were uploaded.'); + } + + if (req.files.testFile.truncated) { + // status 400 to differentiate from ending the request in the on limit + return res.status(400).send(`File too big`); + } + + return res.status(200).send('Upload succeed'); + }); + app.all('/upload/multiple', function(req, res) { if (!req.files) { return res.status(400).send('No files were uploaded.');