From a39a0e7f1a438939a839c11a71bc72df20658573 Mon Sep 17 00:00:00 2001 From: Nitzan Uziely Date: Fri, 26 Mar 2021 17:07:20 +0300 Subject: [PATCH 1/2] readline: fix pre-aborted signal question handling fix pre-aborted question handling --- lib/readline.js | 9 ++++++++- test/parallel/test-readline-interface.js | 25 ++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/lib/readline.js b/lib/readline.js index cd1bfb8b6aaa51..bea005c853c46f 100644 --- a/lib/readline.js +++ b/lib/readline.js @@ -376,6 +376,10 @@ Interface.prototype.question = function(query, options, cb) { options = typeof options === 'object' && options !== null ? options : {}; if (options.signal) { + if (options.signal.aborted) { + return; + } + options.signal.addEventListener('abort', () => { this[kQuestionCancel](); }, { once: true }); @@ -397,8 +401,11 @@ Interface.prototype.question[promisify.custom] = function(query, options) { options = typeof options === 'object' && options !== null ? options : {}; return new Promise((resolve, reject) => { - this.question(query, options, resolve); + if (options.signal?.aborted) { + throw new AbortError(); + } + this.question(query, options, resolve); if (options.signal) { options.signal.addEventListener('abort', () => { reject(new AbortError()); diff --git a/test/parallel/test-readline-interface.js b/test/parallel/test-readline-interface.js index 4660e5b9f56937..e9bf8142b82dd0 100644 --- a/test/parallel/test-readline-interface.js +++ b/test/parallel/test-readline-interface.js @@ -968,6 +968,31 @@ for (let i = 0; i < 12; i++) { rli.close(); } + // pre-aborted signal + { + const signal = AbortSignal.abort(); + const [rli] = getInterface({ terminal }); + rli.pause(); + rli.on('resume', common.mustNotCall()); + rli.question('hello?', { signal }, common.mustNotCall()); + rli.close(); + } + + // pre-aborted signal promisified question + { + const signal = AbortSignal.abort(); + const [rli] = getInterface({ terminal }); + const question = util.promisify(rli.question).bind(rli); + rli.on('resume', common.mustNotCall()); + rli.pause(); + question('hello?', { signal }) + .then(common.mustNotCall()) + .catch(common.mustCall((error) => { + assert.strictEqual(error.name, 'AbortError'); + })); + rli.close(); + } + // Can create a new readline Interface with a null output argument { const [rli, fi] = getInterface({ output: null, terminal }); From a676afe5443947a97dbaf8697b53cbea4d3aa708 Mon Sep 17 00:00:00 2001 From: Nitzan Uziely Date: Fri, 26 Mar 2021 20:09:28 +0300 Subject: [PATCH 2/2] fixup! readline: fix pre-aborted signal question handling --- lib/readline.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/readline.js b/lib/readline.js index bea005c853c46f..113314affc3a29 100644 --- a/lib/readline.js +++ b/lib/readline.js @@ -59,6 +59,7 @@ const { StringPrototypeStartsWith, StringPrototypeTrim, Promise, + PromiseReject, Symbol, SymbolAsyncIterator, SafeStringIterator, @@ -400,12 +401,13 @@ Interface.prototype.question = function(query, options, cb) { Interface.prototype.question[promisify.custom] = function(query, options) { options = typeof options === 'object' && options !== null ? options : {}; - return new Promise((resolve, reject) => { - if (options.signal?.aborted) { - throw new AbortError(); - } + if (options.signal && options.signal.aborted) { + return PromiseReject(new AbortError()); + } + return new Promise((resolve, reject) => { this.question(query, options, resolve); + if (options.signal) { options.signal.addEventListener('abort', () => { reject(new AbortError());