@@ -243,6 +243,99 @@ class HTTP2ConnectionTests: XCTestCase {
243243
244244 XCTAssertNoThrow ( try http2Connection. closeFuture. wait ( ) )
245245 }
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+ }
246339}
247340
248341class TestConnectionCreator {
0 commit comments