@@ -184,18 +184,19 @@ function onHttp2SessionEnd () {
184184 * @param {number } errorCode
185185 */
186186function onHttp2SessionGoAway ( errorCode ) {
187- // We cannot recover, so best to close the session and the socket
187+ // TODO(mcollina): Verify if GOAWAY implements the spec correctly:
188+ // https://datatracker.ietf.org/doc/html/rfc7540#section-6.8
189+ // Specifically, we do not verify the "valid" stream id.
190+
188191 const err = this [ kError ] || new SocketError ( `HTTP/2: "GOAWAY" frame received with code ${ errorCode } ` , util . getSocketInfo ( this [ kSocket ] ) )
189192 const client = this [ kClient ]
190193
191194 client [ kSocket ] = null
192195 client [ kHTTPContext ] = null
193196
194- if ( this [ kHTTP2Session ] !== null ) {
195- this [ kHTTP2Session ] . close ( )
196- this [ kHTTP2Session ] . destroy ( err )
197- this [ kHTTP2Session ] = null
198- }
197+ // this is an HTTP2 session
198+ this . close ( )
199+ this [ kHTTP2Session ] = null
199200
200201 util . destroy ( this [ kSocket ] , err )
201202
@@ -321,13 +322,15 @@ function writeH2 (client, request) {
321322 util . errorRequest ( client , request , err )
322323
323324 if ( stream != null ) {
325+ // Some chunks might still come after abort,
326+ // let's ignore them
327+ stream . removeAllListeners ( 'data' )
328+
324329 // On Abort, we close the stream to send RST_STREAM frame
325330 stream . close ( )
326- // We delay the destroy to allow the stream to send the RST_STREAM frame
327- queueMicrotask ( ( ) => util . destroy ( stream , err ) )
331+
328332 // We move the running index to the next request
329- client [ kQueue ] [ client [ kRunningIdx ] ++ ] = null
330- client [ kPendingIdx ] = client [ kRunningIdx ]
333+ client [ kOnError ] ( err )
331334 client [ kResume ] ( )
332335 }
333336
@@ -356,7 +359,7 @@ function writeH2 (client, request) {
356359 // We disabled endStream to allow the user to write to the stream
357360 stream = session . request ( headers , { endStream : false , signal } )
358361
359- if ( stream . id && ! stream . pending ) {
362+ if ( ! stream . pending ) {
360363 request . onUpgrade ( null , null , stream )
361364 ++ session [ kOpenStreams ]
362365 client [ kQueue ] [ client [ kRunningIdx ] ++ ] = null
@@ -463,26 +466,31 @@ function writeH2 (client, request) {
463466 // for those scenarios, best effort is to destroy the stream immediately
464467 // as there's no value to keep it open.
465468 if ( request . aborted ) {
469+ stream . removeAllListeners ( 'data' )
466470 return
467471 }
468472
469473 if ( request . onHeaders ( Number ( statusCode ) , parseH2Headers ( realHeaders ) , stream . resume . bind ( stream ) , '' ) === false ) {
470474 stream . pause ( )
471475 }
476+ } )
472477
473- stream . on ( 'data' , ( chunk ) => {
474- if ( request . onData ( chunk ) === false ) {
475- stream . pause ( )
476- }
477- } )
478+ stream . on ( 'data' , ( chunk ) => {
479+ if ( request . onData ( chunk ) === false ) {
480+ stream . pause ( )
481+ }
478482 } )
479483
480484 stream . once ( 'end' , ( err ) => {
485+ stream . removeAllListeners ( 'data' )
481486 // When state is null, it means we haven't consumed body and the stream still do not have
482487 // a state.
483488 // Present specially when using pipeline or stream
484489 if ( stream . state ?. state == null || stream . state . state < 6 ) {
485- request . onComplete ( [ ] )
490+ // Do not complete the request if it was aborted
491+ if ( ! request . aborted ) {
492+ request . onComplete ( [ ] )
493+ }
486494
487495 client [ kQueue ] [ client [ kRunningIdx ] ++ ] = null
488496 client [ kResume ] ( )
@@ -503,6 +511,7 @@ function writeH2 (client, request) {
503511 } )
504512
505513 stream . once ( 'close' , ( ) => {
514+ stream . removeAllListeners ( 'data' )
506515 session [ kOpenStreams ] -= 1
507516 if ( session [ kOpenStreams ] === 0 ) {
508517 session . unref ( )
0 commit comments