summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorRobert Nagy <ronagy@icloud.com>2019-09-28 10:24:56 +0200
committerAnna Henningsen <anna@addaleax.net>2019-11-19 16:06:35 +0100
commit9d09969f4c29b7f2bacc9cb44e210c4e269945a4 (patch)
treec9643bd0e7696d763eaa64ae991202ea0240fc84 /lib
parent535e9571f5252ea9ce6f5db12f700f73af6df055 (diff)
downloadandroid-node-v8-9d09969f4c29b7f2bacc9cb44e210c4e269945a4.tar.gz
android-node-v8-9d09969f4c29b7f2bacc9cb44e210c4e269945a4.tar.bz2
android-node-v8-9d09969f4c29b7f2bacc9cb44e210c4e269945a4.zip
stream: always invoke end callback
Ensure that the callback passed into end() is always invoke in order to avoid bug such as deadlock the user. PR-URL: https://github.com/nodejs/node/pull/29747 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/_stream_writable.js34
1 files changed, 30 insertions, 4 deletions
diff --git a/lib/_stream_writable.js b/lib/_stream_writable.js
index 9b4036e476..c7a3047dc7 100644
--- a/lib/_stream_writable.js
+++ b/lib/_stream_writable.js
@@ -611,11 +611,11 @@ Writable.prototype.end = function(chunk, encoding, cb) {
}
// Ignore unnecessary end() calls.
- if (!state.ending)
+ if (!state.ending) {
endWritable(this, state, cb);
- else if (typeof cb === 'function') {
+ } else if (typeof cb === 'function') {
if (!state.finished) {
- this.once('finish', cb);
+ onFinished(this, state, cb);
} else {
cb(new ERR_STREAM_ALREADY_FINISHED('end'));
}
@@ -695,7 +695,7 @@ function endWritable(stream, state, cb) {
if (state.finished)
process.nextTick(cb);
else
- stream.once('finish', cb);
+ onFinished(stream, state, cb);
}
state.ended = true;
stream.writable = false;
@@ -715,6 +715,32 @@ function onCorkedFinish(corkReq, state, err) {
state.corkedRequestsFree.next = corkReq;
}
+function onFinished(stream, state, cb) {
+ if (state.destroyed && state.errorEmitted) {
+ // TODO(ronag): Backwards compat. Should be moved to end() without
+ // errorEmitted check and with errorOrDestroy.
+ const err = new ERR_STREAM_DESTROYED('end');
+ process.nextTick(cb, err);
+ return;
+ }
+
+ function onerror(err) {
+ stream.removeListener('finish', onfinish);
+ stream.removeListener('error', onerror);
+ cb(err);
+ if (stream.listenerCount('error') === 0) {
+ stream.emit('error', err);
+ }
+ }
+ function onfinish() {
+ stream.removeListener('finish', onfinish);
+ stream.removeListener('error', onerror);
+ cb();
+ }
+ stream.on('finish', onfinish);
+ stream.prependListener('error', onerror);
+}
+
Object.defineProperty(Writable.prototype, 'destroyed', {
// Making it explicit this property is not enumerable
// because otherwise some prototype manipulation in