@@ -343,8 +343,6 @@ const SESSION_FLAGS_PENDING = 0x0;
343343const SESSION_FLAGS_READY = 0x1 ;
344344const SESSION_FLAGS_CLOSED = 0x2 ;
345345const SESSION_FLAGS_DESTROYED = 0x4 ;
346- const SESSION_FLAGS_CLOSE_QUEUED = 0x8 ;
347- const SESSION_FLAGS_CLOSE_EMITTED = 0x10 ;
348346
349347// Top level to avoid creating a closure
350348function emit ( self , ...args ) {
@@ -840,6 +838,10 @@ function requestOnConnect(headersList, options) {
840838 }
841839}
842840
841+ function requestOnError ( error ) {
842+ this . destroy ( error ) ;
843+ }
844+
843845// Validates that priority options are correct, specifically:
844846// 1. options.weight must be a number
845847// 2. options.parent must be a positive number
@@ -1158,26 +1160,11 @@ function setupHandle(socket, type, options) {
11581160// Emits an error event followed by a close event if err is truthy. Used
11591161// by Http2Session.prototype.destroy()
11601162function emitClose ( self , error ) {
1161- const state = self [ kState ] ;
1162- if ( state . flags & SESSION_FLAGS_CLOSE_EMITTED )
1163- return ;
1164-
1165- state . flags |= SESSION_FLAGS_CLOSE_EMITTED ;
1166-
11671163 if ( error )
11681164 self . emit ( 'error' , error ) ;
11691165 self . emit ( 'close' ) ;
11701166}
11711167
1172- function emitCloseNextTick ( self , error ) {
1173- const state = self [ kState ] ;
1174- if ( state . flags & ( SESSION_FLAGS_CLOSE_QUEUED | SESSION_FLAGS_CLOSE_EMITTED ) )
1175- return ;
1176-
1177- state . flags |= SESSION_FLAGS_CLOSE_QUEUED ;
1178- process . nextTick ( emitClose , self , error ) ;
1179- }
1180-
11811168function cleanupSession ( session ) {
11821169 const socket = session [ kSocket ] ;
11831170 const handle = session [ kHandle ] ;
@@ -1226,7 +1213,7 @@ function finishSessionClose(session, error) {
12261213 }
12271214 } ) ;
12281215 } else {
1229- emitCloseNextTick ( session , error ) ;
1216+ process . nextTick ( emitClose , session , error ) ;
12301217 }
12311218}
12321219
@@ -1243,13 +1230,6 @@ function closeSession(session, code, error) {
12431230
12441231 const socket = session [ kSocket ] ;
12451232 const handle = session [ kHandle ] ;
1246- const socketDestroyed = socket ?. destroyed === true ;
1247-
1248- // If the transport has already closed, queue the session close event before
1249- // stream callbacks are scheduled so clients can invalidate cached sessions
1250- // before associated streams finish closing.
1251- if ( socketDestroyed )
1252- emitCloseNextTick ( session , error ) ;
12531233
12541234 // Destroy any pending and open streams
12551235 if ( state . pendingStreams . size > 0 || state . streams . size > 0 ) {
@@ -1261,7 +1241,7 @@ function closeSession(session, code, error) {
12611241 // Destroy the handle if it exists at this point.
12621242 if ( handle !== undefined ) {
12631243 handle . ondone = finishSessionClose . bind ( null , session , error ) ;
1264- handle . destroy ( code , socketDestroyed ) ;
1244+ handle . destroy ( code , socket . destroyed ) ;
12651245 } else {
12661246 finishSessionClose ( session , error ) ;
12671247 }
@@ -1832,11 +1812,15 @@ class ClientHttp2Session extends Http2Session {
18321812 request ( headersParam , options ) {
18331813 debugSessionObj ( this , 'initiating request' ) ;
18341814
1835- if ( this . destroyed )
1836- throw new ERR_HTTP2_INVALID_SESSION ( ) ;
1837-
1838- if ( this . closed )
1839- throw new ERR_HTTP2_GOAWAY_SESSION ( ) ;
1815+ // Keep argument validation synchronous, but defer session-state failures
1816+ // to the returned stream so request retries from stream callbacks do not
1817+ // throw before session lifecycle handlers run.
1818+ let requestError ;
1819+ if ( this . destroyed ) {
1820+ requestError = new ERR_HTTP2_INVALID_SESSION ( ) ;
1821+ } else if ( this . closed ) {
1822+ requestError = new ERR_HTTP2_GOAWAY_SESSION ( ) ;
1823+ }
18401824
18411825 this [ kUpdateTimer ] ( ) ;
18421826
@@ -1922,19 +1906,24 @@ class ClientHttp2Session extends Http2Session {
19221906 }
19231907 }
19241908
1925- const onConnect = reqAsync . bind ( requestOnConnect . bind ( stream , headersList , options ) ) ;
1926- if ( this . connecting ) {
1927- if ( this [ kPendingRequestCalls ] !== null ) {
1928- this [ kPendingRequestCalls ] . push ( onConnect ) ;
1909+ if ( requestError ) {
1910+ process . nextTick ( reqAsync . bind ( requestOnError . bind ( stream , requestError ) ) ) ;
1911+ } else {
1912+ const onConnect = reqAsync . bind (
1913+ requestOnConnect . bind ( stream , headersList , options ) ) ;
1914+ if ( this . connecting ) {
1915+ if ( this [ kPendingRequestCalls ] !== null ) {
1916+ this [ kPendingRequestCalls ] . push ( onConnect ) ;
1917+ } else {
1918+ this [ kPendingRequestCalls ] = [ onConnect ] ;
1919+ this . once ( 'connect' , ( ) => {
1920+ this [ kPendingRequestCalls ] . forEach ( ( f ) => f ( ) ) ;
1921+ this [ kPendingRequestCalls ] = null ;
1922+ } ) ;
1923+ }
19291924 } else {
1930- this [ kPendingRequestCalls ] = [ onConnect ] ;
1931- this . once ( 'connect' , ( ) => {
1932- this [ kPendingRequestCalls ] . forEach ( ( f ) => f ( ) ) ;
1933- this [ kPendingRequestCalls ] = null ;
1934- } ) ;
1925+ onConnect ( ) ;
19351926 }
1936- } else {
1937- onConnect ( ) ;
19381927 }
19391928
19401929 if ( onClientStreamCreatedChannel . hasSubscribers ) {
0 commit comments