-
Notifications
You must be signed in to change notification settings - Fork 29.8k
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
Conversation
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
headers['Content-Length'] = 50; | ||
const socket = res.socket; | ||
res.writeHead(200, headers); | ||
setTimeout(() => res.write('aaaaaaaaaa'), 100); |
There was a problem hiding this comment.
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)?
There was a problem hiding this 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) { |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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()); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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', () => {
CI: https://ci.nodejs.org/job/node-test-pull-request/13394/ Let's see what CI and CITGM think. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
let me know if there is anything else i need to do guys. thx |
Landed in 3828fc6...38eb0fa |
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]>
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]>
PR-URL: #18999 Reviewed-By: Shingo Inoue <[email protected]> Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: James M Snell <[email protected]>
@Leko please squash commits next time before landing. |
@lpinca I got it. I'm sorry for mistaken. |
No problem. |
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]>
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]>
PR-URL: nodejs#18999 Reviewed-By: Shingo Inoue <[email protected]> Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: James M Snell <[email protected]>
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]>
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]>
PR-URL: nodejs#18999 Reviewed-By: Shingo Inoue <[email protected]> Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: James M Snell <[email protected]>
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]>
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]>
PR-URL: nodejs#18999 Reviewed-By: Shingo Inoue <[email protected]> Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: James M Snell <[email protected]>
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]>
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]>
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]>
make -j4 test
(UNIX), orvcbuild test
(Windows) passesAffected 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.