How to upgrade an HTTP/1 server to support HTTP/2?

Correct. If you want to setup a pipeline that supports both HTTP/1.1 and HTTP/2 then something has to do the protocol negotiation for you. This is mostly done via TLS as you discovered. RFC 9113 also explains how to start an HTTP/2 connection with prior knowledge.

If you are up for the latest async APIs that we are working on, this setups a connection that handles both HTTP/1.1 and HTTP/2 and provides you our new NIOAsyncChannel based interfaces to handle incoming connections. (Omitted the sslContext creation)

let channel = try await ServerBootstrap(group: eventLoopGroup)
    .bind(host: "127.0.0.1", port: 8080) { channel in
        return channel.pipeline.addHandler(NIOSSLServerHandler(context: sslContext))
            .flatMap {
                channel.configureAsyncHTTPServerPipeline { http1ConnectionChannel in
                    http1ConnectionChannel.eventLoop.makeCompletedFuture {
                        try http1ConnectionChannel.pipeline.syncOperations.addHandler(HTTP1ToHTTPServerCodec(secure: false))
                        return try NIOAsyncChannel(
                            synchronouslyWrapping: http1ConnectionChannel,
                            configuration: .init(
                                inboundType: HTTPTypeRequestPart.self,
                                outboundType: HTTPTypeResponsePart.self
                            )
                        )
                    }
                } http2ConnectionInitializer: { http2ConnectionChannel in
                    http2ConnectionChannel.eventLoop.makeCompletedFuture {
                        try NIOAsyncChannel(
                            synchronouslyWrapping: http2ConnectionChannel,
                            configuration: .init(
                                inboundType: HTTP2Frame.self,
                                outboundType: HTTP2Frame.self
                            )
                        )
                    }
                } http2InboundStreamInitializer: { http2StreamChannel in
                    http2StreamChannel.eventLoop.makeCompletedFuture {
                        try http2StreamChannel.pipeline.syncOperations.addHandler(HTTP2FramePayloadToHTTPServerCodec())
                        return try NIOAsyncChannel(
                            synchronouslyWrapping: http2StreamChannel,
                            configuration: .init(
                                inboundType: HTTPTypeRequestPart.self,
                                outboundType: HTTPTypeResponsePart.self
                            )
                        )
                    }
                }
            }
    }
1 Like