From df971207b88628c9f2cb4148732b85db2de7b1bd Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Sun, 13 Nov 2022 10:04:55 +0000 Subject: [PATCH] Prevent possible race condition when reading metadata #3451 --- docs/changelog.md | 5 +++++ lib/input.js | 9 +++++++-- test/unit/metadata.js | 13 +++++++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/docs/changelog.md b/docs/changelog.md index 1c8093d9..154c897f 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -4,6 +4,11 @@ Requires libvips v8.13.3 +### v0.31.3 - TBD + +* Prevent possible race condition awaiting metadata of Stream-based input. + [#3451](https://github.com/lovell/sharp/issues/3451) + ### v0.31.2 - 4th November 2022 * Upgrade to libvips v8.13.3 for upstream bug fixes. diff --git a/lib/input.js b/lib/input.js index 7c3f40ee..29b7c86e 100644 --- a/lib/input.js +++ b/lib/input.js @@ -469,7 +469,7 @@ function metadata (callback) { } else { if (this._isStreamInput()) { return new Promise((resolve, reject) => { - this.on('finish', () => { + const finished = () => { this._flattenBufferIn(); sharp.metadata(this.options, (err, metadata) => { if (err) { @@ -478,7 +478,12 @@ function metadata (callback) { resolve(metadata); } }); - }); + }; + if (this.writableFinished) { + finished(); + } else { + this.once('finish', finished); + } }); } else { return new Promise((resolve, reject) => { diff --git a/test/unit/metadata.js b/test/unit/metadata.js index df5f1d61..125541cf 100644 --- a/test/unit/metadata.js +++ b/test/unit/metadata.js @@ -439,6 +439,19 @@ describe('Image metadata', function () { ); }); + it('Stream in, finish event fires before metadata is requested', (done) => { + const create = { width: 1, height: 1, channels: 3, background: 'red' }; + const image1 = sharp({ create }).png().pipe(sharp()); + const image2 = sharp({ create }).png().pipe(sharp()); + process.nextTick(async () => { + const data1 = await image1.metadata(); + assert.strictEqual('png', data1.format); + const data2 = await image2.metadata(); + assert.strictEqual('png', data2.format); + done(); + }); + }); + it('Stream', function (done) { const readable = fs.createReadStream(fixtures.inputJpg); const pipeline = sharp().metadata(function (err, metadata) {