Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

http: prevent aborted event when request is complete #18999

Closed
wants to merge 4 commits into from

Conversation

billywhizz
Copy link
Contributor

  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • documentation is changed or added
  • commit message follows commit guidelines
Affected core subsystem(s)

http

When socket is closed on a response for a request that is being piped to a stream
there is a condition where aborted event will be fired to http client when socket is
closing and the incomingMessage stream is still set to readable.

We need a check for request being complete and to only raise the 'aborted' event
on the http client if we have not yet completed reading the response from the server.

When socket is closed on a response for a request that is being piped to a stream
there is a condition where aborted event will be fired to http client when socket is
closing and the incomingMessage stream is still set to readable.

We need a check for request being complete and to only raise the 'aborted' event
on the http client if we have not yet completed reading the response from the server.

Fixes: nodejs#18756
Tests in progress to reproduce issue consistently.

Fixes: nodejs#18756
@nodejs-github-bot nodejs-github-bot added the http Issues or PRs related to the http subsystem. label Feb 26, 2018
headers['Content-Length'] = 50;
const socket = res.socket;
res.writeHead(200, headers);
setTimeout(() => res.write('aaaaaaaaaa'), 100);
Copy link
Contributor

@mscdex mscdex Feb 26, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't all of these timers be setTimeout(..., common.platformTimeout(n)) instead? Otherwise, is there a more reliable way to trigger this issue (perhaps using nextTick() and/or setImmediate() or something else)?

Copy link
Member

@mcollina mcollina left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good work! The change itself is fine, I've left some notes on the test.

res.pipe(fstream);
const _handle = res.socket._handle;
_handle._close = res.socket._handle.close;
_handle.close = function(callback) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain why are you overriding this here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because i could not find a way of forcing the condition we get intermittently in the wild. if you run this script and leave it it will eventually start aborting requests that are actually complete: https://gist.github.com/billywhizz/b500a0d4708f89625ddbb313601b5363. i was unable to figure out how to recreate those exact conditions in a test but after debugging i could see the aborted event was being fired even though req.res.complete was = true. so i overrode close here to recreate that condition.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to clarify, the error occurs when req.res.complete = true and res.readable is still = true. that is happening in the wild but don't know how to force it for a test. i imagine it will depend on a specific sequence of TCP session interactions.

const finishCountdown = new Countdown(N, common.mustCall(() => {
server.close();
}));
const reqCountdown = new Countdown(N, common.mustCall());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer if N was not a constant, but rather it uses a two steps approach, maybe with some helpers.

It's not clear why you are calling twice too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's running two tests - one to ensure we don't abort a good request, one to ensure we do abort a bad one. i can refactor to take out the countdown timers altogether. was trying to stay close to how other tests are constructed. if you can suggest how to change i am happy to refactor.

assert.strictEqual(res.statusCode, 200);
assert.strictEqual(res.headers.connection, 'close');
let aborted = false;
const fstream = fs.createWriteStream(fname);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this file can be made more simple.
No need to cleanup and fs module.

const { Writable } = require('stream');

// ...

const writable = new Writable({
  write(chunk, encoding, callback) {
    callback();
  }
});
res.pipe(writable);

// ...

writable.on('finish', () => {

@billywhizz
Copy link
Contributor Author

I've made changes suggested above by @Leko and @mscdex . @mcollina if you want me to make any further changes to the test let me know. it would be good if we could figure out how to recreate the exact error condition without having to override handle._close.

@mcollina
Copy link
Member

Copy link
Member

@mcollina mcollina left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@billywhizz
Copy link
Contributor Author

let me know if there is anything else i need to do guys. thx

@Leko
Copy link
Contributor

Leko commented Mar 1, 2018

Landed in 3828fc6...38eb0fa
Thanks!

@Leko Leko closed this Mar 1, 2018
Leko pushed a commit that referenced this pull request Mar 1, 2018
When socket is closed on a response for a request that is being piped to
a stream there is a condition where aborted event will be fired to http
client when socket is closing and the incomingMessage stream is still
set to readable.

We need a check for request being complete and to only raise the
'aborted' event on the http client if we have not yet completed reading
the response from the server.

Fixes: #18756

PR-URL: #18999
Reviewed-By: Shingo Inoue <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: James M Snell <[email protected]>
Leko pushed a commit that referenced this pull request Mar 1, 2018
Tests in progress to reproduce issue consistently.

Fixes: #18756

PR-URL: #18999
Reviewed-By: Shingo Inoue <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: James M Snell <[email protected]>
Leko pushed a commit that referenced this pull request Mar 1, 2018
PR-URL: #18999
Reviewed-By: Shingo Inoue <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: James M Snell <[email protected]>
@lpinca
Copy link
Member

lpinca commented Mar 1, 2018

@Leko please squash commits next time before landing.

@Leko
Copy link
Contributor

Leko commented Mar 3, 2018

@lpinca I got it. I'm sorry for mistaken.

@lpinca
Copy link
Member

lpinca commented Mar 3, 2018

No problem.

addaleax pushed a commit to addaleax/node that referenced this pull request Mar 5, 2018
When socket is closed on a response for a request that is being piped to
a stream there is a condition where aborted event will be fired to http
client when socket is closing and the incomingMessage stream is still
set to readable.

We need a check for request being complete and to only raise the
'aborted' event on the http client if we have not yet completed reading
the response from the server.

Fixes: nodejs#18756

PR-URL: nodejs#18999
Reviewed-By: Shingo Inoue <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: James M Snell <[email protected]>
addaleax pushed a commit to addaleax/node that referenced this pull request Mar 5, 2018
Tests in progress to reproduce issue consistently.

Fixes: nodejs#18756

PR-URL: nodejs#18999
Reviewed-By: Shingo Inoue <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: James M Snell <[email protected]>
addaleax pushed a commit to addaleax/node that referenced this pull request Mar 5, 2018
PR-URL: nodejs#18999
Reviewed-By: Shingo Inoue <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: James M Snell <[email protected]>
@MylesBorins MylesBorins mentioned this pull request Mar 6, 2018
MayaLekova pushed a commit to MayaLekova/node that referenced this pull request May 8, 2018
When socket is closed on a response for a request that is being piped to
a stream there is a condition where aborted event will be fired to http
client when socket is closing and the incomingMessage stream is still
set to readable.

We need a check for request being complete and to only raise the
'aborted' event on the http client if we have not yet completed reading
the response from the server.

Fixes: nodejs#18756

PR-URL: nodejs#18999
Reviewed-By: Shingo Inoue <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: James M Snell <[email protected]>
MayaLekova pushed a commit to MayaLekova/node that referenced this pull request May 8, 2018
Tests in progress to reproduce issue consistently.

Fixes: nodejs#18756

PR-URL: nodejs#18999
Reviewed-By: Shingo Inoue <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: James M Snell <[email protected]>
MayaLekova pushed a commit to MayaLekova/node that referenced this pull request May 8, 2018
PR-URL: nodejs#18999
Reviewed-By: Shingo Inoue <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: James M Snell <[email protected]>
jasnell pushed a commit to jasnell/node that referenced this pull request Aug 17, 2018
When socket is closed on a response for a request that is being piped to
a stream there is a condition where aborted event will be fired to http
client when socket is closing and the incomingMessage stream is still
set to readable.

We need a check for request being complete and to only raise the
'aborted' event on the http client if we have not yet completed reading
the response from the server.

Fixes: nodejs#18756

PR-URL: nodejs#18999
Reviewed-By: Shingo Inoue <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: James M Snell <[email protected]>
jasnell pushed a commit to jasnell/node that referenced this pull request Aug 17, 2018
Tests in progress to reproduce issue consistently.

Fixes: nodejs#18756

PR-URL: nodejs#18999
Reviewed-By: Shingo Inoue <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: James M Snell <[email protected]>
jasnell pushed a commit to jasnell/node that referenced this pull request Aug 17, 2018
PR-URL: nodejs#18999
Reviewed-By: Shingo Inoue <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: James M Snell <[email protected]>
MylesBorins pushed a commit that referenced this pull request Sep 6, 2018
When socket is closed on a response for a request that is being piped to
a stream there is a condition where aborted event will be fired to http
client when socket is closing and the incomingMessage stream is still
set to readable.

We need a check for request being complete and to only raise the
'aborted' event on the http client if we have not yet completed reading
the response from the server.

Fixes: #18756

Backport-PR-URL: #22380
PR-URL: #18999
Reviewed-By: Shingo Inoue <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: James M Snell <[email protected]>
MylesBorins pushed a commit that referenced this pull request Sep 6, 2018
Tests in progress to reproduce issue consistently.

Fixes: #18756

Backport-PR-URL: #22380
PR-URL: #18999
Reviewed-By: Shingo Inoue <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: James M Snell <[email protected]>
MylesBorins pushed a commit that referenced this pull request Sep 6, 2018
Backport-PR-URL: #22380
PR-URL: #18999
Reviewed-By: Shingo Inoue <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: James M Snell <[email protected]>
@MylesBorins MylesBorins mentioned this pull request Sep 6, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
http Issues or PRs related to the http subsystem.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants