@@ -174,12 +174,14 @@ public final class Server<RequestHandler: HTTPServerRequestHandler> {
174174 )
175175
176176 case . certificateChainAndPrivateKey( let certificateChain, let privateKey) :
177+ let http2Config = NIOHTTP2Handler . Configuration ( httpServerHTTP2Configuration: configuration. http2)
177178 try await Self . serveSecureUpgrade (
178179 bindTarget: configuration. bindTarget,
179180 certificateChain: certificateChain,
180181 privateKey: privateKey,
181182 handler: handler,
182183 asyncChannelConfiguration: asyncChannelConfiguration,
184+ http2Configuration: http2Config,
183185 logger: logger
184186 )
185187 }
@@ -227,6 +229,7 @@ public final class Server<RequestHandler: HTTPServerRequestHandler> {
227229 privateKey: Certificate . PrivateKey ,
228230 handler: RequestHandler ,
229231 asyncChannelConfiguration: NIOAsyncChannel < HTTPRequestPart , HTTPResponsePart > . Configuration ,
232+ http2Configuration: NIOHTTP2Handler . Configuration ,
230233 logger: Logger
231234 ) async throws {
232235 switch bindTarget. backing {
@@ -263,7 +266,7 @@ public final class Server<RequestHandler: HTTPServerRequestHandler> {
263266 )
264267 )
265268 } . flatMap {
266- channel. configureAsyncHTTPServerPipeline { channel in
269+ channel. configureAsyncHTTPServerPipeline ( http2Configuration : http2Configuration ) { channel in
267270 channel. eventLoop. makeCompletedFuture {
268271 try channel. pipeline. syncOperations. addHandler ( HTTP1ToHTTPServerCodec ( secure: true ) )
269272
@@ -403,3 +406,49 @@ public final class Server<RequestHandler: HTTPServerRequestHandler> {
403406 }
404407 }
405408}
409+
410+ @available( macOS 26.0 , iOS 26.0 , watchOS 26.0 , tvOS 26.0 , visionOS 26.0 , * )
411+ extension NIOHTTP2 Handler. Configuration {
412+ init ( httpServerHTTP2Configuration http2 Config: HTTPServerConfiguration . HTTP2) {
413+ let clampedTargetWindowSize = Self . clampTargetWindowSize ( http2Config. targetWindowSize)
414+ let clampedMaxFrameSize = Self . clampMaxFrameSize ( http2Config. maxFrameSize)
415+
416+ var http2HandlerConnectionConfiguration = NIOHTTP2Handler . ConnectionConfiguration ( )
417+ var http2HandlerHTTP2Settings = HTTP2Settings ( [
418+ HTTP2Setting ( parameter: . initialWindowSize, value: clampedTargetWindowSize) ,
419+ HTTP2Setting ( parameter: . maxFrameSize, value: clampedMaxFrameSize) ,
420+ ] )
421+ if let maxConcurrentStreams = http2Config. maxConcurrentStreams {
422+ http2HandlerHTTP2Settings. append (
423+ HTTP2Setting ( parameter: . maxConcurrentStreams, value: maxConcurrentStreams)
424+ )
425+ }
426+ http2HandlerConnectionConfiguration. initialSettings = http2HandlerHTTP2Settings
427+
428+ var http2HandlerStreamConfiguration = NIOHTTP2Handler . StreamConfiguration ( )
429+ http2HandlerStreamConfiguration. targetWindowSize = clampedTargetWindowSize
430+
431+ self = NIOHTTP2Handler . Configuration (
432+ connection: http2HandlerConnectionConfiguration,
433+ stream: http2HandlerStreamConfiguration
434+ )
435+ }
436+
437+ /// Window size which mustn't exceed `2^31 - 1` (RFC 9113 § 6.5.2).
438+ private static func clampTargetWindowSize( _ targetWindowSize: Int ) -> Int {
439+ min ( targetWindowSize, Int ( Int32 . max) )
440+ }
441+
442+ /// Max frame size must be in the range `2^14 ..< 2^24` (RFC 9113 § 4.2).
443+ private static func clampMaxFrameSize( _ maxFrameSize: Int ) -> Int {
444+ let clampedMaxFrameSize : Int
445+ if maxFrameSize >= ( 1 << 24 ) {
446+ clampedMaxFrameSize = ( 1 << 24 ) - 1
447+ } else if maxFrameSize < ( 1 << 14 ) {
448+ clampedMaxFrameSize = ( 1 << 14 )
449+ } else {
450+ clampedMaxFrameSize = maxFrameSize
451+ }
452+ return clampedMaxFrameSize
453+ }
454+ }
0 commit comments