@@ -26,23 +26,37 @@ let PassThrough;
2626let createReadableStreamAsyncIterator ;
2727
2828function destroyer ( stream , reading , writing , callback ) {
29- callback = once ( callback ) ;
30- let destroyed = false ;
29+ const _destroy = once ( ( err ) => {
30+ destroyImpl . destroyer ( stream , err ) ;
31+ callback ( err ) ;
32+ } ) ;
3133
3234 if ( eos === undefined ) eos = require ( 'internal/streams/end-of-stream' ) ;
3335 eos ( stream , { readable : reading , writable : writing } , ( err ) => {
34- if ( destroyed ) return ;
35- destroyed = true ;
36- destroyImpl . destroyer ( stream , err ) ;
37- callback ( err ) ;
36+ const rState = stream . _readableState ;
37+ if (
38+ err &&
39+ err . code === 'ERR_STREAM_PREMATURE_CLOSE' &&
40+ reading &&
41+ ( rState && rState . ended && ! rState . errored && ! rState . errorEmitted )
42+ ) {
43+ // Some readable streams will emit 'close' before 'end'. However, since
44+ // this is on the readable side 'end' should still be emitted if the
45+ // stream has been ended and no error emitted. This should be allowed in
46+ // favor of backwards compatibility. Since the stream is piped to a
47+ // destination this should not result in any observable difference.
48+ // We don't need to check if this is a writable premature close since
49+ // eos will only fail with premature close on the reading side for
50+ // duplex streams.
51+ stream
52+ . once ( 'end' , _destroy )
53+ . once ( 'error' , _destroy ) ;
54+ } else {
55+ _destroy ( err ) ;
56+ }
3857 } ) ;
3958
40- return ( err ) => {
41- if ( destroyed ) return ;
42- destroyed = true ;
43- destroyImpl . destroyer ( stream , err ) ;
44- callback ( err || new ERR_STREAM_DESTROYED ( 'pipe' ) ) ;
45- } ;
59+ return ( err ) => _destroy ( err || new ERR_STREAM_DESTROYED ( 'pipe' ) ) ;
4660}
4761
4862function popCallback ( streams ) {
0 commit comments