Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions lib/request.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -687,6 +689,11 @@ internals.Info = class {
};


internals.closed = function (request) {

request._closed = true;
};

internals.event = function ({ request }, event, err) {

if (!request) {
Expand Down
7 changes: 7 additions & 0 deletions lib/transmit.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
11 changes: 9 additions & 2 deletions test/transmit.js
Original file line number Diff line number Diff line change
Expand Up @@ -538,10 +538,17 @@ describe('transmission', () => {
// Use state autoValue function to intercept marshal stage

server.state('always', {
autoValue() {
async autoValue(request) {

const close = new Teamwork.Team();
request.raw.res.once('close', () => close.attend());

// 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();
return team.work; // Continue once the request has been aborted
await close.work;

return team.work; // Continue marshalling once the request has been aborted and response closed.
}
});

Expand Down