@@ -243,6 +243,99 @@ class HTTP2ConnectionTests: XCTestCase {
243
243
244
244
XCTAssertNoThrow ( try http2Connection. closeFuture. wait ( ) )
245
245
}
246
+
247
+ func testChildStreamsAreRemovedFromTheOpenChannelListOnceTheRequestIsDone( ) {
248
+ class SucceedPromiseOnRequestHandler : ChannelInboundHandler {
249
+ typealias InboundIn = HTTPServerRequestPart
250
+ typealias OutboundOut = HTTPServerResponsePart
251
+
252
+ let dataArrivedPromise : EventLoopPromise < Void >
253
+ let triggerResponseFuture : EventLoopFuture < Void >
254
+
255
+ init ( dataArrivedPromise: EventLoopPromise < Void > , triggerResponseFuture: EventLoopFuture < Void > ) {
256
+ self . dataArrivedPromise = dataArrivedPromise
257
+ self . triggerResponseFuture = triggerResponseFuture
258
+ }
259
+
260
+ func channelRead( context: ChannelHandlerContext , data: NIOAny ) {
261
+ self . dataArrivedPromise. succeed ( ( ) )
262
+
263
+ self . triggerResponseFuture. hop ( to: context. eventLoop) . whenSuccess {
264
+ switch self . unwrapInboundIn ( data) {
265
+ case . head:
266
+ context. write ( self . wrapOutboundOut ( . head( . init( version: . http2, status: . ok) ) ) , promise: nil )
267
+ context. writeAndFlush ( self . wrapOutboundOut ( . end( nil ) ) , promise: nil )
268
+ case . body, . end:
269
+ break
270
+ }
271
+ }
272
+ }
273
+ }
274
+
275
+ let eventLoopGroup = MultiThreadedEventLoopGroup ( numberOfThreads: 1 )
276
+ let eventLoop = eventLoopGroup. next ( )
277
+ defer { XCTAssertNoThrow ( try eventLoopGroup. syncShutdownGracefully ( ) ) }
278
+
279
+ let serverReceivedRequestPromise = eventLoop. makePromise ( of: Void . self)
280
+ let triggerResponsePromise = eventLoop. makePromise ( of: Void . self)
281
+ let httpBin = HTTPBin ( . http2( compress: false ) ) { _ in
282
+ SucceedPromiseOnRequestHandler (
283
+ dataArrivedPromise: serverReceivedRequestPromise,
284
+ triggerResponseFuture: triggerResponsePromise. futureResult
285
+ )
286
+ }
287
+ defer { XCTAssertNoThrow ( try httpBin. shutdown ( ) ) }
288
+
289
+ let connectionCreator = TestConnectionCreator ( )
290
+ let delegate = TestHTTP2ConnectionDelegate ( )
291
+ var maybeHTTP2Connection : HTTP2Connection ?
292
+ XCTAssertNoThrow ( maybeHTTP2Connection = try connectionCreator. createHTTP2Connection (
293
+ to: httpBin. port,
294
+ delegate: delegate,
295
+ on: eventLoop
296
+ ) )
297
+ guard let http2Connection = maybeHTTP2Connection else {
298
+ return XCTFail ( " Expected to have an HTTP2 connection here. " )
299
+ }
300
+
301
+ var maybeRequest : HTTPClient . Request ?
302
+ var maybeRequestBag : RequestBag < ResponseAccumulator > ?
303
+ XCTAssertNoThrow ( maybeRequest = try HTTPClient . Request ( url: " https://localhost: \( httpBin. port) " ) )
304
+ XCTAssertNoThrow ( maybeRequestBag = try RequestBag (
305
+ request: XCTUnwrap ( maybeRequest) ,
306
+ eventLoopPreference: . indifferent,
307
+ task: . init( eventLoop: eventLoop, logger: . init( label: " test " ) ) ,
308
+ redirectHandler: nil ,
309
+ connectionDeadline: . distantFuture,
310
+ requestOptions: . forTests( ) ,
311
+ delegate: ResponseAccumulator ( request: XCTUnwrap ( maybeRequest) )
312
+ ) )
313
+ guard let requestBag = maybeRequestBag else {
314
+ return XCTFail ( " Expected to have a request bag at this point " )
315
+ }
316
+
317
+ http2Connection. executeRequest ( requestBag)
318
+
319
+ XCTAssertNoThrow ( try serverReceivedRequestPromise. futureResult. wait ( ) )
320
+ var channelCount : Int ?
321
+ XCTAssertNoThrow ( channelCount = try eventLoop. submit { http2Connection. __forTesting_getStreamChannels ( ) . count } . wait ( ) )
322
+ XCTAssertEqual ( channelCount, 1 )
323
+ triggerResponsePromise. succeed ( ( ) )
324
+
325
+ XCTAssertNoThrow ( try requestBag. task. futureResult. wait ( ) )
326
+
327
+ // this is racy. for this reason we allow a couple of tries
328
+ var retryCount = 0
329
+ let maxRetries = 1000
330
+ while retryCount < maxRetries {
331
+ XCTAssertNoThrow ( channelCount = try eventLoop. submit { http2Connection. __forTesting_getStreamChannels ( ) . count } . wait ( ) )
332
+ if channelCount == 0 {
333
+ break
334
+ }
335
+ retryCount += 1
336
+ }
337
+ XCTAssertLessThan ( retryCount, maxRetries)
338
+ }
246
339
}
247
340
248
341
class TestConnectionCreator {
0 commit comments