From 618d9539fd362964fb8ffbb56e8005d52da94988 Mon Sep 17 00:00:00 2001 From: Devin Ivy Date: Tue, 2 Mar 2021 23:54:49 -0500 Subject: [PATCH 1/2] Allow for res to have already closed during transmission --- lib/request.js | 7 +++++++ lib/transmit.js | 7 +++++++ test/transmit.js | 11 ++++++++--- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/lib/request.js b/lib/request.js index 6f425d561..deeb577d5 100755 --- a/lib/request.js +++ b/lib/request.js @@ -24,6 +24,7 @@ exports = module.exports = internals.Request = class { constructor(server, req, res, options) { this._allowInternals = !!options.allowInternals; + this._closed = false; // true once the response has closed (esp. early) and will not emit any more events this._core = server._core; this._entity = null; // Entity information set via h.entity() this._eventContext = { request: this }; @@ -311,6 +312,7 @@ exports = module.exports = internals.Request = class { this.raw.req.on('close', internals.event.bind(this.raw.req, this._eventContext, 'close')); this.raw.req.on('error', internals.event.bind(this.raw.req, this._eventContext, 'error')); this.raw.req.on('aborted', internals.event.bind(this.raw.req, this._eventContext, 'abort')); + this.raw.res.once('close', internals.closed.bind(this.raw.res, this)); } _lookup() { @@ -687,6 +689,11 @@ internals.Info = class { }; +internals.closed = function (request) { + + request._closed = true; +}; + internals.event = function ({ request }, event, err) { if (!request) { diff --git a/lib/transmit.js b/lib/transmit.js index 195737f11..45a27ad25 100755 --- a/lib/transmit.js +++ b/lib/transmit.js @@ -244,6 +244,13 @@ internals.pipe = function (request, stream) { const env = { stream, request, team }; + if (request._closed) { + // No more events will be fired, so we proactively close-up shop + request.raw.res.end(); // Ensure res is finished so internals.end() doesn't think we're responding + internals.end(env, 'close'); + return team.work; + } + const aborted = internals.end.bind(null, env, 'aborted'); const close = internals.end.bind(null, env, 'close'); const end = internals.end.bind(null, env, null); diff --git a/test/transmit.js b/test/transmit.js index d77cc691e..d31c3c262 100755 --- a/test/transmit.js +++ b/test/transmit.js @@ -538,10 +538,15 @@ describe('transmission', () => { // Use state autoValue function to intercept marshal stage server.state('always', { - autoValue() { + async autoValue(request) { - client.destroy(); - return team.work; // Continue once the request has been aborted + const close = new Teamwork.Team(); + request.raw.res.once('close', () => close.attend()); + + client.destroy(); // Will trigger abort then close. Prior to node v15.7.0 the res close came + await close.work; // asynchronously after req abort, but since then it comes in the same tick. + + return team.work; // Continue marshalling once the request has been aborted and response closed. } }); From 04bb16864fcf95ff12596f608d724fd5d1966ee2 Mon Sep 17 00:00:00 2001 From: devin ivy Date: Fri, 12 Mar 2021 13:58:04 -0500 Subject: [PATCH 2/2] Fix comment placement in transmit test --- test/transmit.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/transmit.js b/test/transmit.js index d31c3c262..0eb38ca0a 100755 --- a/test/transmit.js +++ b/test/transmit.js @@ -543,8 +543,10 @@ describe('transmission', () => { const close = new Teamwork.Team(); request.raw.res.once('close', () => close.attend()); - client.destroy(); // Will trigger abort then close. Prior to node v15.7.0 the res close came - await close.work; // asynchronously after req abort, but since then it comes in the same tick. + // Will trigger abort then close. Prior to node v15.7.0 the res close came + // asynchronously after req abort, but since then it comes in the same tick. + client.destroy(); + await close.work; return team.work; // Continue marshalling once the request has been aborted and response closed. }