@@ -158,6 +158,11 @@ function WritableState(options, stream, isDuplex) {
158158 // Should .destroy() be called after 'finish' (and potentially 'end')
159159 this . autoDestroy = ! ! ( options && options . autoDestroy ) ;
160160
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+
161166 // Count buffered requests
162167 this . bufferedRequestCount = 0 ;
163168
@@ -401,7 +406,7 @@ function writeOrBuffer(stream, state, isBuf, chunk, encoding, cb) {
401406 if ( ! ret )
402407 state . needDrain = true ;
403408
404- if ( state . writing || state . corked ) {
409+ if ( state . writing || state . corked || state . errored ) {
405410 var last = state . lastBufferedRequest ;
406411 state . lastBufferedRequest = {
407412 chunk,
@@ -420,7 +425,9 @@ function writeOrBuffer(stream, state, isBuf, chunk, encoding, cb) {
420425 doWrite ( stream , state , false , len , chunk , encoding , cb ) ;
421426 }
422427
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 ;
424431}
425432
426433function doWrite ( stream , state , writev , len , chunk , encoding , cb ) {
@@ -437,18 +444,11 @@ function doWrite(stream, state, writev, len, chunk, encoding, cb) {
437444 state . sync = false ;
438445}
439446
440- function onwriteError ( stream , state , sync , er , cb ) {
447+ function onwriteError ( stream , state , er , cb ) {
441448 -- state . pendingcb ;
442449
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.
452452 errorOrDestroy ( stream , er ) ;
453453}
454454
@@ -465,9 +465,14 @@ function onwrite(stream, er) {
465465 state . length -= state . writelen ;
466466 state . writelen = 0 ;
467467
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 {
471476 // Check if we're actually ready to finish, but don't emit yet
472477 var finished = needFinish ( state ) || stream . destroyed ;
473478
@@ -622,7 +627,7 @@ Object.defineProperty(Writable.prototype, 'writableLength', {
622627function needFinish ( state ) {
623628 return ( state . ending &&
624629 state . length === 0 &&
625- ! state . errorEmitted &&
630+ ! state . errored &&
626631 state . bufferedRequest === null &&
627632 ! state . finished &&
628633 ! state . writing ) ;
0 commit comments