-
Notifications
You must be signed in to change notification settings - Fork 29.6k
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: emit ERR_STREAM_DESTROYED if the socket is destroyed #29227
Conversation
}); | ||
|
||
req.on('response', common.mustNotCall()); | ||
req.on('error', 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.
If I am not mistaken, this results in the ERR_STREAM_DESTROYED
as well?
req.on('error', common.mustCall()); | |
req.on('error', common.expectsError({ | |
code: 'ERR_STREAM_DESTROYED' | |
})); |
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.
ping @mcollina Does that suggestion above seem good to you? (Seems good to me....)
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.
That's going to be 'ECONNRESET' on my machine.
lib/_http_outgoing.js
Outdated
callback(err); | ||
} | ||
if (this.listenerCount('error') > 0 && this[kErrored] === undefined) { | ||
this[kErrored] = true; |
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.
Is there a specific reason to silence all errors besides the first one?
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.
@BridgeAR: that's how streams do it, see destroy.js
.
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.
The reason is that this will normally be called 4 times in case this condition is met, as a response is composed of 4 chunks.
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.
Should probably also apply the kErrored
logic got writeAfterEndNT
, and maybe _implicitHeader
and pipe
. Maybe refactored out into a helper along the lines of errorOrDestroy
?
lib/_http_outgoing.js
Outdated
if (callback) { | ||
callback(err); | ||
} | ||
if (this.listenerCount('error') > 0 && this[kErrored] === undefined) { |
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.
What's the reason for the listener count check? We don't do this for streams?
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.
nit, !this[kErrored]
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.
The reason is not to break a lot of tests, and keep this semver-minor.
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.
Could you add a comment for that at least? Then maybe we can "fix" it in a semver-major in the future?
lib/_http_outgoing.js
Outdated
@@ -56,6 +57,7 @@ const HIGH_WATER_MARK = getDefaultHighWaterMark(); | |||
const { CRLF, debug } = common; | |||
|
|||
const kIsCorked = Symbol('isCorked'); | |||
const kErrored = Symbol('errored'); |
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.
nit kErrorEmitted
to more closely follow streams
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.
Should we initialize kErrored
in the constructor? Or will that unnecessarily increase object size?
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'm not adding that to the constructor exactly because of that. I can add it if we think it's worth adding, it's not a big deal anyway.
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.
Sounds good either way to me. Just checking if it was intentional.
lib/_http_outgoing.js
Outdated
} | ||
if (this.listenerCount('error') > 0 && this[kErrored] === undefined) { | ||
this[kErrored] = true; | ||
this.emit('error', err); |
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 believe this should be emitted in next tick? That's what we want in stream?
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.
Maybe same thing with 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.
I'm actually removing calling the callback here. It's not needed to fix the actual issue, and it can be done in a later step.
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.
We cannot remove the callback or something else is going to fail. Essentially if we want to emit error here, we need to call the callback synchronously first :/.
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.
Something else, as in a test? Add another comment for future semver-major?
I'm not sure about that. The reason I added |
44b241f
to
28a771d
Compare
Could you explain a little further? In |
The overall reason for not doing that in this PR is to keep it as strictly semver-minor as possible, so it can be backported. |
Sounds reasonable. I'm willing to make a semver-major PR in the future to make it more stream-like. |
55dc8b6
to
40c62a6
Compare
Rebased and force-pushed to get rid of conflict. |
e2f7aec
to
d2cfed1
Compare
eca886a
to
a085d91
Compare
CI is not flaky, windows is failing :/
|
8ae28ff
to
2935f72
Compare
@ronag if you would like to take this over please do. |
This issue/PR was marked as stalled, it will be automatically closed in 30 days. If it should remain open, please leave a comment explaining why it should remain open. |
@ronag wdyt? Should we revive this or should I close it? |
@mcollina: I think this PR is no longer making correct assumptions. Streams do not emit If the underlying socket is prematurely destroyed (without error) that should already error the What we should probably fix is:
I would recommend we close this PR and make an issue for the callback and pipeline issue. Thoughts? |
I'll close this. Could you open the issue? |
The pipeline utility assumes that a stream is going to error if it
could not be written to it. If an http.OutgoingMessage was piped after
the underlining socket had been destroyed, the whole pipeline would not
be teared down, resulting in a file descriptor and memory leak.
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passes