Skip to content

Commit fe0f12b

Browse files
committed
Merge remote-tracking branch 'ry/v0.10'
2 parents f97a126 + 5458079 commit fe0f12b

2 files changed

Lines changed: 85 additions & 4 deletions

File tree

lib/_stream_readable.js

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -540,15 +540,23 @@ Readable.prototype.pipe = function(dest, pipeOpts) {
540540

541541
// if the dest has an error, then stop piping into it.
542542
// however, don't suppress the throwing behavior for this.
543-
// check for listeners before emit removes one-time listeners.
544-
var errListeners = EE.listenerCount(dest, 'error');
545543
function onerror(er) {
546544
debug('onerror', er);
547545
unpipe();
548-
if (errListeners === 0 && EE.listenerCount(dest, 'error') === 0)
546+
dest.removeListener('error', onerror);
547+
if (EE.listenerCount(dest, 'error') === 0)
549548
dest.emit('error', er);
550549
}
551-
dest.once('error', onerror);
550+
// This is a brutally ugly hack to make sure that our error handler
551+
// is attached before any userland ones. NEVER DO THIS.
552+
if (!dest._events.error)
553+
dest.on('error', onerror);
554+
else if (Array.isArray(dest._events.error))
555+
dest._events.error.unshift(onerror);
556+
else
557+
dest._events.error = [onerror, dest._events.error];
558+
559+
552560

553561
// Both close and finish should trigger unpipe, but only once.
554562
function onclose() {

test/simple/test-stream-pipe-error-handling.js

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,76 @@ var Stream = require('stream').Stream;
5656

5757
assert.strictEqual(gotErr, err);
5858
})();
59+
60+
(function testErrorWithRemovedListenerThrows() {
61+
var EE = require('events').EventEmitter;
62+
var R = Stream.Readable;
63+
var W = Stream.Writable;
64+
65+
var r = new R;
66+
var w = new W;
67+
var removed = false;
68+
var didTest = false;
69+
70+
process.on('exit', function() {
71+
assert(didTest);
72+
console.log('ok');
73+
});
74+
75+
r._read = function() {
76+
setTimeout(function() {
77+
assert(removed);
78+
assert.throws(function() {
79+
w.emit('error', new Error('fail'));
80+
});
81+
didTest = true;
82+
});
83+
};
84+
85+
w.on('error', myOnError);
86+
r.pipe(w);
87+
w.removeListener('error', myOnError);
88+
removed = true;
89+
90+
function myOnError(er) {
91+
throw new Error('this should not happen');
92+
}
93+
})();
94+
95+
(function testErrorWithRemovedListenerThrows() {
96+
var EE = require('events').EventEmitter;
97+
var R = Stream.Readable;
98+
var W = Stream.Writable;
99+
100+
var r = new R;
101+
var w = new W;
102+
var removed = false;
103+
var didTest = false;
104+
var caught = false;
105+
106+
process.on('exit', function() {
107+
assert(didTest);
108+
console.log('ok');
109+
});
110+
111+
r._read = function() {
112+
setTimeout(function() {
113+
assert(removed);
114+
w.emit('error', new Error('fail'));
115+
didTest = true;
116+
});
117+
};
118+
119+
w.on('error', myOnError);
120+
w._write = function() {};
121+
122+
r.pipe(w);
123+
// Removing some OTHER random listener should not do anything
124+
w.removeListener('error', function() {});
125+
removed = true;
126+
127+
function myOnError(er) {
128+
assert(!caught);
129+
caught = true;
130+
}
131+
})();

0 commit comments

Comments
 (0)