@@ -158,6 +158,11 @@ function WritableState(options, stream, isDuplex) {
158
158
// Should .destroy() be called after 'finish' (and potentially 'end')
159
159
this . autoDestroy = ! ! ( options && options . autoDestroy ) ;
160
160
161
+ // Indicates whether the stream has errored. When true all write() calls
162
+ // should return false. This is needed since when autoDestroy
163
+ // is disabled we need a way to tell whether the stream has failed.
164
+ this . errored = false ;
165
+
161
166
// Count buffered requests
162
167
this . bufferedRequestCount = 0 ;
163
168
@@ -401,7 +406,7 @@ function writeOrBuffer(stream, state, isBuf, chunk, encoding, cb) {
401
406
if ( ! ret )
402
407
state . needDrain = true ;
403
408
404
- if ( state . writing || state . corked ) {
409
+ if ( state . writing || state . corked || state . errored ) {
405
410
var last = state . lastBufferedRequest ;
406
411
state . lastBufferedRequest = {
407
412
chunk,
@@ -420,7 +425,9 @@ function writeOrBuffer(stream, state, isBuf, chunk, encoding, cb) {
420
425
doWrite ( stream , state , false , len , chunk , encoding , cb ) ;
421
426
}
422
427
423
- return ret ;
428
+ // Return false if errored or destroyed in order to break
429
+ // any synchronous while(stream.write(data)) loops.
430
+ return ret && ! state . errored && ! state . destroyed ;
424
431
}
425
432
426
433
function doWrite ( stream , state , writev , len , chunk , encoding , cb ) {
@@ -437,18 +444,11 @@ function doWrite(stream, state, writev, len, chunk, encoding, cb) {
437
444
state . sync = false ;
438
445
}
439
446
440
- function onwriteError ( stream , state , sync , er , cb ) {
447
+ function onwriteError ( stream , state , er , cb ) {
441
448
-- state . pendingcb ;
442
449
443
- if ( sync ) {
444
- // Defer the callback if we are being called synchronously
445
- // to avoid piling up things on the stack
446
- process . nextTick ( cb , er ) ;
447
- } else {
448
- // The caller expect this to happen before if
449
- // it is async
450
- cb ( er ) ;
451
- }
450
+ cb ( er ) ;
451
+ // This can emit error, but error must always follow cb.
452
452
errorOrDestroy ( stream , er ) ;
453
453
}
454
454
@@ -465,9 +465,14 @@ function onwrite(stream, er) {
465
465
state . length -= state . writelen ;
466
466
state . writelen = 0 ;
467
467
468
- if ( er )
469
- onwriteError ( stream , state , sync , er , cb ) ;
470
- else {
468
+ if ( er ) {
469
+ state . errored = true ;
470
+ if ( sync ) {
471
+ process . nextTick ( onwriteError , stream , state , er , cb ) ;
472
+ } else {
473
+ onwriteError ( stream , state , er , cb ) ;
474
+ }
475
+ } else {
471
476
// Check if we're actually ready to finish, but don't emit yet
472
477
var finished = needFinish ( state ) || stream . destroyed ;
473
478
@@ -622,7 +627,7 @@ Object.defineProperty(Writable.prototype, 'writableLength', {
622
627
function needFinish ( state ) {
623
628
return ( state . ending &&
624
629
state . length === 0 &&
625
- ! state . errorEmitted &&
630
+ ! state . errored &&
626
631
state . bufferedRequest === null &&
627
632
! state . finished &&
628
633
! state . writing ) ;
0 commit comments