-
-
Notifications
You must be signed in to change notification settings - Fork 7.3k
RangeErrors caused by removeAllListeners change in v0.7 #3425
Description
A common code pattern I see in projects that need to attach to another http.Server
is this:
// We want myAwesomeHandler to run before
// other event listeners. We also may hijack the
// event for our own purposes. This is useful for
// attaching to other servers (say, we want to
// only respond to requests starting with "/yeti")
// or for handling HTTP upgrades befor anything
// else (say, for Socket.io).
var listeners = server.listeners("request");
server.removeAllListeners("request");
server.on("request", function myAwesomeHandler(req, res) {
if (req.url.indexOf("/awesome") !== -1) {
// We're going to handle this one.
handleAwesomeRequest(req, res);
return;
}
// The original listeners should handle this one.
listeners.forEach(function (fn) {
// In Node.js v0.7, listeners now contains myAwesomeHandler!
// myAwesomeHandler is now called recursively.
fn.call(this, req, res);
}
});
The problem is that 78dc13f causes removeAllListeners to maintain the array reference returned by the listeners call, which results in new side effects: since Node v0.7, the listeners array shown above will be updated with new event listeners attached.
In Node v0.6, the call to listeners() acted like a copy, so this code would not result in a loop.
If the listeners array is copied before being used, the v0.6-style behavior can be obtained. For exmaple, see: yui/yeti@51aa577#L1R25
This is currently a problem for the dnode project, which uses Socket.io 0.8.6 that uses this pattern for handling HTTP upgrades. This was also a problem with my own code as well.
For the sake of easy upgrades from v0.6, I request for the existing behavior to be maintained.
If this request is denied, the wiki about 6-to-8 changes should be updated to reflect this behavior change: https://github.com/joyent/node/wiki/API-changes-between-v0.6-and-v0.8