Open briannielson opened 4 years ago
There was another issue that referenced this change in Node 10 that I think might be responsible, but I'm unsure. https://github.com/nodejs/node/pull/18868
Is there any progress on this issue?
Changing the name of the event worked for me as well!
Is there any progress on this issue?
I did not fix tests, so the PR I posted is not mergable. However, the change appeared to fix the issue in our production environment.
I ran into this bug as well and looked into it a bit more. I wanted to leave here what I found in case it helps someone (or me in the future if I can get back to it).
On a second look, the aborted
event used here does actually exist. That's because req
in this context is an IncomingMessage
object which does expose this event (see here). So the reported "fix" to rename aborted
to abort
really just prevents that event from firing (since it doesn't exist), thus preventing the proxyReq.abort()
call shown below.
// Ensure we abort proxy if request is aborted
req.on('aborted', function () {
proxyReq.abort();
});
Ultimately, it's this proxyReq.abort()
that ends up triggering the error handler with an ECONNRESET
error for the proxied outgoing request to the upstream server. There, the following if statement block is skipped because req.socket.destroyed
is false
I believe because the socket from the client hasn't yet fully destroyed.
if (req.socket.destroyed && err.code === 'ECONNRESET') {
server.emit('econnreset', err, req, res, url);
return proxyReq.abort();
}
At this point, the http-proxy error callback or event is triggered and the caller ends up getting the ECONNRESET
error for the intentional aborted request to the upstream server.
After some quick testing, simply removing the aborted
event handler, while it prevents the http-proxy error event from firing, also appears to prevent the socket from closing normally on the upstream server. At least, I don't see the close
event fire there.
Another potential fix I was playing with is changing the if statement shown above in the error handler to use req.aborted
instead of req.socket.destroyed
. This value will be true after the aborted
event is fired, so I think it's safe, but not entirely confident.
if (req.aborted && err.code === 'ECONNRESET') {
server.emit('econnreset', err, req, res, url);
return proxyReq.abort();
}
@gsf4726, I believe you are correct. I tested your theory, and indeed, the event handler was never firing after renaming the event from aborted
to abort
. I implemented your change, and it does seem to work.
@gsf4726, I can confirm that proposed change allows all tests to pass, so I think we can say that this is a better solution.
After some quick testing, simply removing the
aborted
event handler, while it prevents the http-proxy error event from firing, also appears to prevent the socket from closing normally on the upstream server. At least, I don't see theclose
event fire there.
We haven't seen EMFILE
errors on our production servers, so it appears that these sockets are eventually getting cleaned up. I was having issues getting tests to run so I am going to leave this issue open until I have time to spend on getting a PR ready.
Your analysis looks correct and I am inclined to agree with you that that is the better solution. If it is an IncomingMessage
the effect of what I did was remove the event listener entirely.
@gsf4726, I can confirm that proposed change allows all tests to pass, so I think we can say that this is a better solution.
@ujwal-setlur if you end up opening a PR, make sure to reference this issue so it can be closed and so I can get a notification and patch our system.
@briannielson @ujwal-setlur I actually had some time today to get back to this. I found that the existing test (should proxy the request and handle timeout error
) reproduces a similar failure path with the connection to the client being aborted, but from the proxy side by timing out the socket for the request. In this case, req.socket.destroyed
is true (though so is req.aborted
) and the current code works.
I've been working on adding a new test that better represents the real-life case we've run up against where the client aborts the request. I should be able to get a PR together soon.
Hi Just wanted to know the progress in regards to the merging of this PR thanks.
+1
I've tested the fix locally and it works great. Would really love to see this merged and released so I can stop monkey-patching
Further confirming this fix solves my issue which PR #1542 should implement. Thanks guys, that made my life much easier!
any plans on merging this fix?
I found that for Node 10+ if a request is cancelled before being proxied, the proxyServer emits an error instead of an
econnreset
event. This does not happen for < Node 8. I believe this is due to a change in the lifetime of error event listeners on the original request socket.I think the underlying issue is that in
lib/http-proxy/passes/web-incoming.js
there is an event listener on theaborted
event on a request.aborted
is a property, I believe the event should beabort
. Making this change fixes the issue in my reproduction path.https://github.com/http-party/node-http-proxy/blob/master/lib/http-proxy/passes/web-incoming.js#L146
Versions:
Reproduction path:
curl http://127.0.0.1:8080/echo
Server code: