From cb53f584faa276c4333df4e7e0f1ede59c6f42b0 Mon Sep 17 00:00:00 2001 From: Leonard Martin Date: Fri, 10 Nov 2017 13:01:01 +0000 Subject: [PATCH] Fix #21 - handle empty payloads without crashing Not uploading any file will cause `Buffer.byteLength` to throw an error if called with an empty array in node >= 7, which is what `concat-stream` will return if no payload is provided. Remove `concat-stream` in favour of `bl`, which will reliably callback with Buffer instances for empty streams. --- README.md | 4 ++-- index.js | 5 +++-- package.json | 3 ++- test/index.js | 48 ++++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 51 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index ad4deef..5f8feb3 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ The middleware will add files to `req.files` in the following form: // req.files: { fieldName: { - data: "raw file data", + data: Buffer("raw file data"), name: "upload.txt", encoding: "utf8", mimetype: "text/plain", @@ -77,7 +77,7 @@ If the `multi` property is set: // req.files: { fieldName: [{ - data: "raw file data", + data: Buffer("raw file data"), name: "upload.txt", encoding: "utf8", mimetype: "text/plain", diff --git a/index.js b/index.js index 45c7c09..9266399 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,6 @@ var Busboy = require('busboy'), bytes = require('bytes'), - concat = require('concat-stream'), + bl = require('bl'), debug = require('debug')('busboy-body-parser'); var HARDLIMIT = bytes('250mb'); @@ -41,7 +41,8 @@ module.exports = function (settings) { req.body[key] = value; }); busboy.on('file', function (key, file, name, enc, mimetype) { - file.pipe(concat(function (d) { + file.pipe(bl(function (err, d) { + if (err || !name) { return; } var fileData = { data: file.truncated ? null : d, name: name, diff --git a/package.json b/package.json index 83b3a10..94e44b2 100644 --- a/package.json +++ b/package.json @@ -8,13 +8,14 @@ "license": "MIT", "repository": "lennym/busboy-body-parser", "dependencies": { + "bl": "^1.2.1", "busboy": "^0.2.9", "bytes": "^2.0.0", - "concat-stream": "^1.4.6", "debug": "^2.1.0" }, "devDependencies": { "chai": "^1.9.2", + "express": "^4.16.2", "mocha": "^2.0.1", "sinon": "^1.11.1", "sinon-chai": "^2.6.0" diff --git a/test/index.js b/test/index.js index ee9417c..6932657 100644 --- a/test/index.js +++ b/test/index.js @@ -96,7 +96,7 @@ describe('multipart form parser', function () { parser(req, res, function () { req.files.should.have.property('key'); req.files.key.should.eql({ - data: 'abc123', + data: Buffer('abc123'), name: 'test.jpg', encoding: 'binary', mimetype: 'image/jpeg', @@ -154,7 +154,7 @@ describe('multipart form parser', function () { req.files.should.have.property('key'); req.files.key.should.length(2); req.files.key[0].should.eql({ - data: 'abc123', + data: Buffer('abc123'), name: 'test.jpg', encoding: 'binary', mimetype: 'image/jpeg', @@ -162,7 +162,7 @@ describe('multipart form parser', function () { truncated: false }); req.files.key[1].should.eql({ - data: 'xyz789', + data: Buffer('xyz789'), name: 'test2.jpg', encoding: 'binary', mimetype: 'image/jpeg', @@ -172,6 +172,46 @@ describe('multipart form parser', function () { done(); }); - }) + }); + + it('can handle empty payloads', function (done) { + var file = { + pipe: function (s) { + s.end(); + // ensure 'finish' event fires after files are processed + process.nextTick(Busboy.prototype.on.withArgs('finish').args[0][1]); + }, + truncated: false + }; + Busboy.prototype.on.withArgs('file').yieldsAsync('key', file, '', '7bit', 'application/octet-stream'); + parser(req, res, function () { + req.files.should.eql({}); + done(); + }); + }); + + it('can handle empty files', function (done) { + var file = { + pipe: function (s) { + s.end(); + // ensure 'finish' event fires after files are processed + process.nextTick(Busboy.prototype.on.withArgs('finish').args[0][1]); + }, + truncated: false + }; + Busboy.prototype.on.withArgs('file').yieldsAsync('key', file, 'test.jpg', 'binary', 'image/jpeg'); + parser(req, res, function () { + req.files.should.have.property('key'); + req.files.key.should.eql({ + data: Buffer(''), + name: 'test.jpg', + encoding: 'binary', + mimetype: 'image/jpeg', + size: 0, + truncated: false + }); + done(); + }); + }); });