From c235d2dc136a67c51095f188742c743d8cb32839 Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Wed, 9 Aug 2023 10:50:35 +0200 Subject: [PATCH] Do not double send the response if the request is destroyed but not aborted (#4963) Signed-off-by: Matteo Collina --- lib/wrapThenable.js | 5 ++++- test/wrapThenable.test.js | 22 ++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/lib/wrapThenable.js b/lib/wrapThenable.js index b746a62e92..0d4e7ba812 100644 --- a/lib/wrapThenable.js +++ b/lib/wrapThenable.js @@ -18,7 +18,10 @@ function wrapThenable (thenable, reply) { // the request may be terminated during the reply. in this situation, // it require an extra checking of request.aborted to see whether // the request is killed by client. - if (payload !== undefined || (reply.sent === false && reply.raw.headersSent === false && reply.request.raw.aborted === false)) { + // Most of the times aborted will be true when destroyed is true, + // however there is a race condition where the request is not + // aborted but only destroyed. + if (payload !== undefined || (reply.sent === false && reply.raw.headersSent === false && reply.request.raw.aborted === false && reply.request.raw.destroyed === false)) { // we use a try-catch internally to avoid adding a catch to another // promise, increase promise perf by 10% try { diff --git a/test/wrapThenable.test.js b/test/wrapThenable.test.js index e953d29c16..df0ba33458 100644 --- a/test/wrapThenable.test.js +++ b/test/wrapThenable.test.js @@ -27,3 +27,25 @@ test('should reject immediately when reply[kReplyHijacked] is true', t => { const thenable = Promise.reject(new Error('Reply sent already')) wrapThenable(thenable, reply) }) + +test('should not send the payload if the raw socket was destroyed but not aborted', async t => { + const reply = { + sent: false, + raw: { + headersSent: false + }, + request: { + raw: { + aborted: false, + destroyed: true + } + }, + send () { + t.fail('should not send') + } + } + const thenable = Promise.resolve() + wrapThenable(thenable, reply) + + await thenable +})