@@ -26,7 +26,8 @@ const {
26
26
kHTTP2Session,
27
27
kResume,
28
28
kSize,
29
- kHTTPContext
29
+ kHTTPContext,
30
+ kClosed
30
31
} = require ( '../core/symbols.js' )
31
32
32
33
const kOpenStreams = Symbol ( 'open streams' )
@@ -93,82 +94,37 @@ async function connectH2 (client, socket) {
93
94
session [ kOpenStreams ] = 0
94
95
session [ kClient ] = client
95
96
session [ kSocket ] = socket
97
+ session [ kHTTP2Session ] = null
96
98
97
99
util . addListener ( session , 'error' , onHttp2SessionError )
98
100
util . addListener ( session , 'frameError' , onHttp2FrameError )
99
101
util . addListener ( session , 'end' , onHttp2SessionEnd )
100
- util . addListener ( session , 'goaway' , onHTTP2GoAway )
101
- util . addListener ( session , 'close' , function ( ) {
102
- const { [ kClient ] : client } = this
103
- const { [ kSocket ] : socket } = client
104
-
105
- const err = this [ kSocket ] [ kError ] || this [ kError ] || new SocketError ( 'closed' , util . getSocketInfo ( socket ) )
106
-
107
- client [ kHTTP2Session ] = null
108
-
109
- if ( client . destroyed ) {
110
- assert ( client [ kPending ] === 0 )
111
-
112
- // Fail entire queue.
113
- const requests = client [ kQueue ] . splice ( client [ kRunningIdx ] )
114
- for ( let i = 0 ; i < requests . length ; i ++ ) {
115
- const request = requests [ i ]
116
- util . errorRequest ( client , request , err )
117
- }
118
- }
119
- } )
102
+ util . addListener ( session , 'goaway' , onHttp2SessionGoAway )
103
+ util . addListener ( session , 'close' , onHttp2SessionClose )
120
104
121
105
session . unref ( )
122
106
123
107
client [ kHTTP2Session ] = session
124
108
socket [ kHTTP2Session ] = session
125
109
126
- util . addListener ( socket , 'error' , function ( err ) {
127
- assert ( err . code !== 'ERR_TLS_CERT_ALTNAME_INVALID' )
128
-
129
- this [ kError ] = err
130
-
131
- this [ kClient ] [ kOnError ] ( err )
132
- } )
133
-
134
- util . addListener ( socket , 'end' , function ( ) {
135
- util . destroy ( this , new SocketError ( 'other side closed' , util . getSocketInfo ( this ) ) )
136
- } )
137
-
138
- util . addListener ( socket , 'close' , function ( ) {
139
- const err = this [ kError ] || new SocketError ( 'closed' , util . getSocketInfo ( this ) )
140
-
141
- client [ kSocket ] = null
110
+ util . addListener ( socket , 'error' , onHttp2SocketError )
111
+ util . addListener ( socket , 'end' , onHttp2SocketEnd )
112
+ util . addListener ( socket , 'close' , onHttp2SocketClose )
142
113
143
- if ( this [ kHTTP2Session ] != null ) {
144
- this [ kHTTP2Session ] . destroy ( err )
145
- }
146
-
147
- client [ kPendingIdx ] = client [ kRunningIdx ]
148
-
149
- assert ( client [ kRunning ] === 0 )
150
-
151
- client . emit ( 'disconnect' , client [ kUrl ] , [ client ] , err )
152
-
153
- client [ kResume ] ( )
154
- } )
155
-
156
- let closed = false
157
- socket . on ( 'close' , ( ) => {
158
- closed = true
159
- } )
114
+ socket [ kClosed ] = false
115
+ socket . on ( 'close' , onSocketClose )
160
116
161
117
return {
162
118
version : 'h2' ,
163
119
defaultPipelining : Infinity ,
164
- write ( ... args ) {
165
- return writeH2 ( client , ... args )
120
+ write ( request ) {
121
+ return writeH2 ( client , request )
166
122
} ,
167
123
resume ( ) {
168
124
resumeH2 ( client )
169
125
} ,
170
126
destroy ( err , callback ) {
171
- if ( closed ) {
127
+ if ( socket [ kClosed ] ) {
172
128
queueMicrotask ( callback )
173
129
} else {
174
130
// Destroying the socket will trigger the session close
@@ -223,16 +179,19 @@ function onHttp2SessionEnd () {
223
179
* This is the root cause of #3011
224
180
* We need to handle GOAWAY frames properly, and trigger the session close
225
181
* along with the socket right away
182
+ *
183
+ * @this {import('http2').ClientHttp2Session}
184
+ * @param {number } errorCode
226
185
*/
227
- function onHTTP2GoAway ( code ) {
186
+ function onHttp2SessionGoAway ( errorCode ) {
228
187
// We cannot recover, so best to close the session and the socket
229
- const err = this [ kError ] || new SocketError ( `HTTP/2: "GOAWAY" frame received with code ${ code } ` , util . getSocketInfo ( this ) )
188
+ const err = this [ kError ] || new SocketError ( `HTTP/2: "GOAWAY" frame received with code ${ errorCode } ` , util . getSocketInfo ( this [ kSocket ] ) )
230
189
const client = this [ kClient ]
231
190
232
191
client [ kSocket ] = null
233
192
client [ kHTTPContext ] = null
234
193
235
- if ( this [ kHTTP2Session ] != null ) {
194
+ if ( this [ kHTTP2Session ] !== null ) {
236
195
this [ kHTTP2Session ] . destroy ( err )
237
196
this [ kHTTP2Session ] = null
238
197
}
@@ -253,6 +212,62 @@ function onHTTP2GoAway (code) {
253
212
client [ kResume ] ( )
254
213
}
255
214
215
+ function onHttp2SessionClose ( ) {
216
+ const { [ kClient ] : client } = this
217
+ const { [ kSocket ] : socket } = client
218
+
219
+ const err = this [ kSocket ] [ kError ] || this [ kError ] || new SocketError ( 'closed' , util . getSocketInfo ( socket ) )
220
+
221
+ client [ kHTTP2Session ] = null
222
+
223
+ if ( client . destroyed ) {
224
+ assert ( client [ kPending ] === 0 )
225
+
226
+ // Fail entire queue.
227
+ const requests = client [ kQueue ] . splice ( client [ kRunningIdx ] )
228
+ for ( let i = 0 ; i < requests . length ; i ++ ) {
229
+ const request = requests [ i ]
230
+ util . errorRequest ( client , request , err )
231
+ }
232
+ }
233
+ }
234
+
235
+ function onHttp2SocketClose ( ) {
236
+ const err = this [ kError ] || new SocketError ( 'closed' , util . getSocketInfo ( this ) )
237
+
238
+ const client = this [ kHTTP2Session ] [ kClient ]
239
+
240
+ client [ kSocket ] = null
241
+
242
+ if ( this [ kHTTP2Session ] !== null ) {
243
+ this [ kHTTP2Session ] . destroy ( err )
244
+ }
245
+
246
+ client [ kPendingIdx ] = client [ kRunningIdx ]
247
+
248
+ assert ( client [ kRunning ] === 0 )
249
+
250
+ client . emit ( 'disconnect' , client [ kUrl ] , [ client ] , err )
251
+
252
+ client [ kResume ] ( )
253
+ }
254
+
255
+ function onHttp2SocketError ( err ) {
256
+ assert ( err . code !== 'ERR_TLS_CERT_ALTNAME_INVALID' )
257
+
258
+ this [ kError ] = err
259
+
260
+ this [ kClient ] [ kOnError ] ( err )
261
+ }
262
+
263
+ function onHttp2SocketEnd ( ) {
264
+ util . destroy ( this , new SocketError ( 'other side closed' , util . getSocketInfo ( this ) ) )
265
+ }
266
+
267
+ function onSocketClose ( ) {
268
+ this [ kClosed ] = true
269
+ }
270
+
256
271
// https://www.rfc-editor.org/rfc/rfc7230#section-3.3.2
257
272
function shouldSendContentLength ( method ) {
258
273
return method !== 'GET' && method !== 'HEAD' && method !== 'OPTIONS' && method !== 'TRACE' && method !== 'CONNECT'
0 commit comments