@@ -24,7 +24,9 @@ const {
24
24
kOnError,
25
25
kMaxConcurrentStreams,
26
26
kHTTP2Session,
27
- kResume
27
+ kResume,
28
+ kSize,
29
+ kHTTPContext
28
30
} = require ( '../core/symbols.js' )
29
31
30
32
const kOpenStreams = Symbol ( 'open streams' )
@@ -160,11 +162,10 @@ async function connectH2 (client, socket) {
160
162
version : 'h2' ,
161
163
defaultPipelining : Infinity ,
162
164
write ( ...args ) {
163
- // TODO (fix): return
164
- writeH2 ( client , ...args )
165
+ return writeH2 ( client , ...args )
165
166
} ,
166
167
resume ( ) {
167
-
168
+ resumeH2 ( client )
168
169
} ,
169
170
destroy ( err , callback ) {
170
171
if ( closed ) {
@@ -183,6 +184,20 @@ async function connectH2 (client, socket) {
183
184
}
184
185
}
185
186
187
+ function resumeH2 ( client ) {
188
+ const socket = client [ kSocket ]
189
+
190
+ if ( socket ?. destroyed === false ) {
191
+ if ( client [ kSize ] === 0 && client [ kMaxConcurrentStreams ] === 0 ) {
192
+ socket . unref ( )
193
+ client [ kHTTP2Session ] . unref ( )
194
+ } else {
195
+ socket . ref ( )
196
+ client [ kHTTP2Session ] . ref ( )
197
+ }
198
+ }
199
+ }
200
+
186
201
function onHttp2SessionError ( err ) {
187
202
assert ( err . code !== 'ERR_TLS_CERT_ALTNAME_INVALID' )
188
203
@@ -210,17 +225,32 @@ function onHttp2SessionEnd () {
210
225
* along with the socket right away
211
226
*/
212
227
function onHTTP2GoAway ( code ) {
213
- const err = new RequestAbortedError ( `HTTP/2: "GOAWAY" frame received with code ${ code } ` )
228
+ // 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 ) )
230
+ const client = this [ kClient ]
214
231
215
- // We need to trigger the close cycle right away
216
- // We need to destroy the session and the socket
217
- // Requests should be failed with the error after the current one is handled
218
- this [ kSocket ] [ kError ] = err
219
- this [ kClient ] [ kOnError ] ( err )
232
+ client [ kSocket ] = null
233
+ client [ kHTTPContext ] = null
220
234
221
- this . unref ( )
235
+ if ( this [ kHTTP2Session ] != null ) {
236
+ this [ kHTTP2Session ] . destroy ( err )
237
+ this [ kHTTP2Session ] = null
238
+ }
222
239
223
240
util . destroy ( this [ kSocket ] , err )
241
+
242
+ // Fail head of pipeline.
243
+ const request = client [ kQueue ] [ client [ kRunningIdx ] ]
244
+ client [ kQueue ] [ client [ kRunningIdx ] ++ ] = null
245
+ util . errorRequest ( client , request , err )
246
+
247
+ client [ kPendingIdx ] = client [ kRunningIdx ]
248
+
249
+ assert ( client [ kRunning ] === 0 )
250
+
251
+ client . emit ( 'disconnect' , client [ kUrl ] , [ client ] , err )
252
+
253
+ client [ kResume ] ( )
224
254
}
225
255
226
256
// https://www.rfc-editor.org/rfc/rfc7230#section-3.3.2
@@ -237,10 +267,6 @@ function writeH2 (client, request) {
237
267
return false
238
268
}
239
269
240
- if ( request . aborted ) {
241
- return false
242
- }
243
-
244
270
const headers = { }
245
271
for ( let n = 0 ; n < reqHeaders . length ; n += 2 ) {
246
272
const key = reqHeaders [ n + 0 ]
@@ -283,6 +309,8 @@ function writeH2 (client, request) {
283
309
// We do not destroy the socket as we can continue using the session
284
310
// the stream get's destroyed and the session remains to create new streams
285
311
util . destroy ( body , err )
312
+ client [ kQueue ] [ client [ kRunningIdx ] ++ ] = null
313
+ client [ kResume ] ( )
286
314
}
287
315
288
316
try {
@@ -293,6 +321,10 @@ function writeH2 (client, request) {
293
321
util . errorRequest ( client , request , err )
294
322
}
295
323
324
+ if ( request . aborted ) {
325
+ return false
326
+ }
327
+
296
328
if ( method === 'CONNECT' ) {
297
329
session . ref ( )
298
330
// We are already connected, streams are pending, first request
@@ -304,10 +336,12 @@ function writeH2 (client, request) {
304
336
if ( stream . id && ! stream . pending ) {
305
337
request . onUpgrade ( null , null , stream )
306
338
++ session [ kOpenStreams ]
339
+ client [ kQueue ] [ client [ kRunningIdx ] ++ ] = null
307
340
} else {
308
341
stream . once ( 'ready' , ( ) => {
309
342
request . onUpgrade ( null , null , stream )
310
343
++ session [ kOpenStreams ]
344
+ client [ kQueue ] [ client [ kRunningIdx ] ++ ] = null
311
345
} )
312
346
}
313
347
@@ -428,17 +462,20 @@ function writeH2 (client, request) {
428
462
// Present specially when using pipeline or stream
429
463
if ( stream . state ?. state == null || stream . state . state < 6 ) {
430
464
request . onComplete ( [ ] )
431
- return
432
465
}
433
466
434
- // Stream is closed or half-closed-remote (6), decrement counter and cleanup
435
- // It does not have sense to continue working with the stream as we do not
436
- // have yet RST_STREAM support on client-side
437
467
if ( session [ kOpenStreams ] === 0 ) {
468
+ // Stream is closed or half-closed-remote (6), decrement counter and cleanup
469
+ // It does not have sense to continue working with the stream as we do not
470
+ // have yet RST_STREAM support on client-side
471
+
438
472
session . unref ( )
439
473
}
440
474
441
475
abort ( new InformationalError ( 'HTTP/2: stream half-closed (remote)' ) )
476
+ client [ kQueue ] [ client [ kRunningIdx ] ++ ] = null
477
+ client [ kPendingIdx ] = client [ kRunningIdx ]
478
+ client [ kResume ] ( )
442
479
} )
443
480
444
481
stream . once ( 'close' , ( ) => {
0 commit comments