@@ -45,6 +45,8 @@ const {
45
45
ERR_UNKNOWN_ENCODING
46
46
} = require ( 'internal/errors' ) . codes ;
47
47
48
+ const { errorOrDestroy } = destroyImpl ;
49
+
48
50
util . inherits ( Writable , Stream ) ;
49
51
50
52
function nop ( ) { }
@@ -147,6 +149,9 @@ function WritableState(options, stream, isDuplex) {
147
149
// Should close be emitted on destroy. Defaults to true.
148
150
this . emitClose = options . emitClose !== false ;
149
151
152
+ // Should .destroy() be called after 'finish' (and potentially 'end')
153
+ this . autoDestroy = ! ! options . autoDestroy ;
154
+
150
155
// count buffered requests
151
156
this . bufferedRequestCount = 0 ;
152
157
@@ -235,14 +240,14 @@ function Writable(options) {
235
240
236
241
// Otherwise people can pipe Writable streams, which is just wrong.
237
242
Writable . prototype . pipe = function ( ) {
238
- this . emit ( 'error' , new ERR_STREAM_CANNOT_PIPE ( ) ) ;
243
+ errorOrDestroy ( this , new ERR_STREAM_CANNOT_PIPE ( ) ) ;
239
244
} ;
240
245
241
246
242
247
function writeAfterEnd ( stream , cb ) {
243
248
var er = new ERR_STREAM_WRITE_AFTER_END ( ) ;
244
249
// TODO: defer error events consistently everywhere, not just the cb
245
- stream . emit ( 'error' , er ) ;
250
+ errorOrDestroy ( stream , er ) ;
246
251
process . nextTick ( cb , er ) ;
247
252
}
248
253
@@ -258,7 +263,7 @@ function validChunk(stream, state, chunk, cb) {
258
263
er = new ERR_INVALID_ARG_TYPE ( 'chunk' , [ 'string' , 'Buffer' ] , chunk ) ;
259
264
}
260
265
if ( er ) {
261
- stream . emit ( 'error' , er ) ;
266
+ errorOrDestroy ( stream , er ) ;
262
267
process . nextTick ( cb , er ) ;
263
268
return false ;
264
269
}
@@ -422,13 +427,13 @@ function onwriteError(stream, state, sync, er, cb) {
422
427
// after error
423
428
process . nextTick ( finishMaybe , stream , state ) ;
424
429
stream . _writableState . errorEmitted = true ;
425
- stream . emit ( 'error' , er ) ;
430
+ errorOrDestroy ( stream , er ) ;
426
431
} else {
427
432
// the caller expect this to happen before if
428
433
// it is async
429
434
cb ( er ) ;
430
435
stream . _writableState . errorEmitted = true ;
431
- stream . emit ( 'error' , er ) ;
436
+ errorOrDestroy ( stream , er ) ;
432
437
// this can emit finish, but finish must
433
438
// always follow error
434
439
finishMaybe ( stream , state ) ;
@@ -612,7 +617,7 @@ function callFinal(stream, state) {
612
617
stream . _final ( ( err ) => {
613
618
state . pendingcb -- ;
614
619
if ( err ) {
615
- stream . emit ( 'error' , err ) ;
620
+ errorOrDestroy ( stream , err ) ;
616
621
}
617
622
state . prefinished = true ;
618
623
stream . emit ( 'prefinish' ) ;
@@ -639,6 +644,15 @@ function finishMaybe(stream, state) {
639
644
if ( state . pendingcb === 0 ) {
640
645
state . finished = true ;
641
646
stream . emit ( 'finish' ) ;
647
+
648
+ if ( state . autoDestroy ) {
649
+ // In case of duplex streams we need a way to detect
650
+ // if the readable side is ready for autoDestroy as well
651
+ const rState = stream . _readableState ;
652
+ if ( ! rState || ( rState . autoDestroy && rState . endEmitted ) ) {
653
+ stream . destroy ( ) ;
654
+ }
655
+ }
642
656
}
643
657
}
644
658
return need ;
0 commit comments