@@ -306,8 +306,23 @@ function onStreamClose(code) {
306306
307307 if ( state . fd !== undefined )
308308 tryClose ( state . fd ) ;
309- stream . push ( null ) ;
310- stream [ kMaybeDestroy ] ( null , code ) ;
309+
310+ // Defer destroy we actually emit end.
311+ if ( stream . _readableState . endEmitted || code !== NGHTTP2_NO_ERROR ) {
312+ // If errored or ended, we can destroy immediately.
313+ stream [ kMaybeDestroy ] ( null , code ) ;
314+ } else {
315+ // Wait for end to destroy.
316+ stream . on ( 'end' , stream [ kMaybeDestroy ] ) ;
317+ // Push a null so the stream can end whenever the client consumes
318+ // it completely.
319+ stream . push ( null ) ;
320+
321+ // Same as net.
322+ if ( stream . readableLength === 0 ) {
323+ stream . read ( 0 ) ;
324+ }
325+ }
311326}
312327
313328// Receives a chunk of data for a given stream and forwards it on
@@ -325,11 +340,19 @@ function onStreamRead(nread, buf) {
325340 }
326341 return ;
327342 }
343+
328344 // Last chunk was received. End the readable side.
329345 debug ( `Http2Stream ${ stream [ kID ] } [Http2Session ` +
330346 `${ sessionName ( stream [ kSession ] [ kType ] ) } ]: ending readable.` ) ;
331- stream . push ( null ) ;
332- stream [ kMaybeDestroy ] ( ) ;
347+
348+ // defer this until we actually emit end
349+ if ( stream . _readableState . endEmitted ) {
350+ stream [ kMaybeDestroy ] ( ) ;
351+ } else {
352+ stream . on ( 'end' , stream [ kMaybeDestroy ] ) ;
353+ stream . push ( null ) ;
354+ stream . read ( 0 ) ;
355+ }
333356}
334357
335358// Called when the remote peer settings have been updated.
@@ -1825,21 +1848,25 @@ class Http2Stream extends Duplex {
18251848 session [ kMaybeDestroy ] ( ) ;
18261849 process . nextTick ( emit , this , 'close' , code ) ;
18271850 callback ( err ) ;
1828- }
18291851
1852+ }
18301853 // The Http2Stream can be destroyed if it has closed and if the readable
18311854 // side has received the final chunk.
18321855 [ kMaybeDestroy ] ( error , code = NGHTTP2_NO_ERROR ) {
1833- if ( error == null ) {
1834- if ( code === NGHTTP2_NO_ERROR &&
1835- ( ! this . _readableState . ended ||
1836- ! this . _writableState . ended ||
1837- this . _writableState . pendingcb > 0 ||
1838- ! this . closed ) ) {
1839- return ;
1840- }
1856+ if ( error || code !== NGHTTP2_NO_ERROR ) {
1857+ this . destroy ( error ) ;
1858+ return ;
1859+ }
1860+
1861+ // TODO(mcollina): remove usage of _*State properties
1862+ if ( this . _readableState . ended &&
1863+ this . _writableState . ended &&
1864+ this . _writableState . pendingcb === 0 &&
1865+ this . closed ) {
1866+ this . destroy ( ) ;
1867+ // This should return, but eslint complains.
1868+ // return
18411869 }
1842- this . destroy ( error ) ;
18431870 }
18441871}
18451872
0 commit comments