diff --git a/lib/input.js b/lib/input.js index 9aebc3a0..80168876 100644 --- a/lib/input.js +++ b/lib/input.js @@ -115,9 +115,8 @@ function _write (chunk, encoding, callback) { /* istanbul ignore else */ if (is.buffer(chunk)) { if (this.options.input.buffer.length === 0) { - const that = this; - this.on('finish', function () { - that.streamInFinished = true; + this.on('finish', () => { + this.streamInFinished = true; }); } this.options.input.buffer.push(chunk); @@ -165,16 +164,15 @@ function _isStreamInput () { * @returns {Sharp} */ function clone () { - const that = this; // Clone existing options const clone = this.constructor.call(); clone.options = Object.assign({}, this.options); // Pass 'finish' event to clone for Stream-based input if (this._isStreamInput()) { - this.on('finish', function () { + this.on('finish', () => { // Clone inherits input data - that._flattenBufferIn(); - clone.options.bufferIn = that.options.bufferIn; + this._flattenBufferIn(); + clone.options.bufferIn = this.options.bufferIn; clone.emit('finish'); }); } @@ -224,12 +222,11 @@ function clone () { * @returns {Promise|Sharp} */ function metadata (callback) { - const that = this; if (is.fn(callback)) { if (this._isStreamInput()) { - this.on('finish', function () { - that._flattenBufferIn(); - sharp.metadata(that.options, callback); + this.on('finish', () => { + this._flattenBufferIn(); + sharp.metadata(this.options, callback); }); } else { sharp.metadata(this.options, callback); @@ -237,10 +234,10 @@ function metadata (callback) { return this; } else { if (this._isStreamInput()) { - return new Promise(function (resolve, reject) { - that.on('finish', function () { - that._flattenBufferIn(); - sharp.metadata(that.options, function (err, metadata) { + return new Promise((resolve, reject) => { + this.on('finish', () => { + this._flattenBufferIn(); + sharp.metadata(this.options, (err, metadata) => { if (err) { reject(err); } else { @@ -250,8 +247,8 @@ function metadata (callback) { }); }); } else { - return new Promise(function (resolve, reject) { - sharp.metadata(that.options, function (err, metadata) { + return new Promise((resolve, reject) => { + sharp.metadata(this.options, (err, metadata) => { if (err) { reject(err); } else { @@ -293,12 +290,11 @@ function metadata (callback) { * @returns {Promise} */ function stats (callback) { - const that = this; if (is.fn(callback)) { if (this._isStreamInput()) { - this.on('finish', function () { - that._flattenBufferIn(); - sharp.stats(that.options, callback); + this.on('finish', () => { + this._flattenBufferIn(); + sharp.stats(this.options, callback); }); } else { sharp.stats(this.options, callback); @@ -306,10 +302,10 @@ function stats (callback) { return this; } else { if (this._isStreamInput()) { - return new Promise(function (resolve, reject) { - that.on('finish', function () { - that._flattenBufferIn(); - sharp.stats(that.options, function (err, stats) { + return new Promise((resolve, reject) => { + this.on('finish', function () { + this._flattenBufferIn(); + sharp.stats(this.options, (err, stats) => { if (err) { reject(err); } else { @@ -319,8 +315,8 @@ function stats (callback) { }); }); } else { - return new Promise(function (resolve, reject) { - sharp.stats(that.options, function (err, stats) { + return new Promise((resolve, reject) => { + sharp.stats(this.options, (err, stats) => { if (err) { reject(err); } else { diff --git a/lib/output.js b/lib/output.js index 861ce655..19fd0f44 100644 --- a/lib/output.js +++ b/lib/output.js @@ -650,6 +650,7 @@ function _setBooleanOption (key, val) { * @private */ function _read () { + /* istanbul ignore else */ if (!this.options.streamOut) { this.options.streamOut = true; this._pipeline(); @@ -662,14 +663,13 @@ function _read () { * @private */ function _pipeline (callback) { - const that = this; if (typeof callback === 'function') { // output=file/buffer if (this._isStreamInput()) { // output=file/buffer, input=stream - this.on('finish', function () { - that._flattenBufferIn(); - sharp.pipeline(that.options, callback); + this.on('finish', () => { + this._flattenBufferIn(); + sharp.pipeline(this.options, callback); }); } else { // output=file/buffer, input=file/buffer @@ -680,41 +680,31 @@ function _pipeline (callback) { // output=stream if (this._isStreamInput()) { // output=stream, input=stream - if (this.streamInFinished) { + this.once('finish', () => { this._flattenBufferIn(); - sharp.pipeline(this.options, function (err, data, info) { + sharp.pipeline(this.options, (err, data, info) => { if (err) { - that.emit('error', err); + this.emit('error', err); } else { - that.emit('info', info); - that.push(data); + this.emit('info', info); + this.push(data); } - that.push(null); - }); - } else { - this.on('finish', function () { - that._flattenBufferIn(); - sharp.pipeline(that.options, function (err, data, info) { - if (err) { - that.emit('error', err); - } else { - that.emit('info', info); - that.push(data); - } - that.push(null); - }); + this.push(null); }); + }); + if (this.streamInFinished) { + this.emit('finish'); } } else { // output=stream, input=file/buffer - sharp.pipeline(this.options, function (err, data, info) { + sharp.pipeline(this.options, (err, data, info) => { if (err) { - that.emit('error', err); + this.emit('error', err); } else { - that.emit('info', info); - that.push(data); + this.emit('info', info); + this.push(data); } - that.push(null); + this.push(null); }); } return this; @@ -722,15 +712,15 @@ function _pipeline (callback) { // output=promise if (this._isStreamInput()) { // output=promise, input=stream - return new Promise(function (resolve, reject) { - that.on('finish', function () { - that._flattenBufferIn(); - sharp.pipeline(that.options, function (err, data, info) { + return new Promise((resolve, reject) => { + this.once('finish', () => { + this._flattenBufferIn(); + sharp.pipeline(this.options, (err, data, info) => { if (err) { reject(err); } else { - if (that.options.resolveWithObject) { - resolve({ data: data, info: info }); + if (this.options.resolveWithObject) { + resolve({ data, info }); } else { resolve(data); } @@ -740,12 +730,12 @@ function _pipeline (callback) { }); } else { // output=promise, input=file/buffer - return new Promise(function (resolve, reject) { - sharp.pipeline(that.options, function (err, data, info) { + return new Promise((resolve, reject) => { + sharp.pipeline(this.options, (err, data, info) => { if (err) { reject(err); } else { - if (that.options.resolveWithObject) { + if (this.options.resolveWithObject) { resolve({ data: data, info: info }); } else { resolve(data); diff --git a/package.json b/package.json index 016dc32c..41985949 100644 --- a/package.json +++ b/package.json @@ -99,7 +99,7 @@ "nan": "^2.14.0", "npmlog": "^4.1.2", "prebuild-install": "^5.3.0", - "semver": "^6.2.0", + "semver": "^6.3.0", "simple-get": "^3.0.3", "tar": "^4.4.10", "tunnel-agent": "^0.6.0" diff --git a/test/unit/io.js b/test/unit/io.js index 6161ddaf..053b4dcd 100644 --- a/test/unit/io.js +++ b/test/unit/io.js @@ -392,6 +392,22 @@ describe('Input/output', function () { }); }); + it('Stream input with corrupt header fails gracefully', function (done) { + const transformer = sharp(); + transformer + .toBuffer() + .then(function () { + done(new Error('Unexpectedly resolved Promise')); + }) + .catch(function (err) { + assert.strictEqual(true, !!err); + done(); + }); + fs + .createReadStream(fixtures.inputJpgWithCorruptHeader) + .pipe(transformer); + }); + describe('Output filename with unknown extension', function () { it('Match JPEG input', function (done) { sharp(fixtures.inputJpg)