From c0be3e52a2d79e51db34acffb49f06dce0960c09 Mon Sep 17 00:00:00 2001 From: tursom Date: Fri, 14 May 2021 10:54:18 +0800 Subject: [PATCH] NettyHttpServer add SSL support --- .../cn/tursom/core/ws/WebSocketClient.kt | 14 ++---- .../cn/tursom/web/netty/NettyHttpServer.kt | 48 +++++++++++++++---- 2 files changed, 45 insertions(+), 17 deletions(-) diff --git a/ts-core/ts-ws-client/src/main/kotlin/cn/tursom/core/ws/WebSocketClient.kt b/ts-core/ts-ws-client/src/main/kotlin/cn/tursom/core/ws/WebSocketClient.kt index 98dea5b..f735842 100644 --- a/ts-core/ts-ws-client/src/main/kotlin/cn/tursom/core/ws/WebSocketClient.kt +++ b/ts-core/ts-ws-client/src/main/kotlin/cn/tursom/core/ws/WebSocketClient.kt @@ -5,10 +5,7 @@ import cn.tursom.core.buffer.impl.NettyByteBuffer import io.netty.bootstrap.Bootstrap import io.netty.buffer.ByteBuf import io.netty.buffer.Unpooled -import io.netty.channel.Channel -import io.netty.channel.ChannelFuture -import io.netty.channel.ChannelInitializer -import io.netty.channel.EventLoopGroup +import io.netty.channel.* import io.netty.channel.nio.NioEventLoopGroup import io.netty.channel.socket.SocketChannel import io.netty.channel.socket.nio.NioSocketChannel @@ -37,7 +34,8 @@ class WebSocketClient( var initChannel: ((ch: SocketChannel) -> Unit)? = null ) { private val uri: URI = URI.create(url) - internal var ch: Channel? = null + var ch: Channel? = null + internal set fun open() { close() @@ -111,10 +109,8 @@ class WebSocketClient( ch?.writeAndFlush(CloseWebSocketFrame()) } else { ch?.writeAndFlush(CloseWebSocketFrame(WebSocketCloseStatus.NORMAL_CLOSURE, reasonText)) - } - ch?.close() + }?.addListener(ChannelFutureListener.CLOSE) return ch?.closeFuture() - //ch?.closeFuture()?.sync() } fun write(text: String): ChannelFuture { @@ -194,6 +190,6 @@ class WebSocketClient( } companion object { - private val group: EventLoopGroup = NioEventLoopGroup() + val group: EventLoopGroup = NioEventLoopGroup() } } \ No newline at end of file diff --git a/ts-web/ts-web-netty/src/main/kotlin/cn/tursom/web/netty/NettyHttpServer.kt b/ts-web/ts-web-netty/src/main/kotlin/cn/tursom/web/netty/NettyHttpServer.kt index 46a7aa6..0db1360 100644 --- a/ts-web/ts-web-netty/src/main/kotlin/cn/tursom/web/netty/NettyHttpServer.kt +++ b/ts-web/ts-web-netty/src/main/kotlin/cn/tursom/web/netty/NettyHttpServer.kt @@ -5,6 +5,7 @@ import cn.tursom.web.HttpHandler import cn.tursom.web.HttpServer import cn.tursom.web.WebSocketHandler import io.netty.bootstrap.ServerBootstrap +import io.netty.buffer.ByteBufAllocator import io.netty.channel.ChannelFuture import io.netty.channel.ChannelInitializer import io.netty.channel.ChannelOption @@ -16,6 +17,7 @@ import io.netty.handler.codec.http.HttpObject import io.netty.handler.codec.http.HttpObjectAggregator import io.netty.handler.codec.http.HttpServerCodec import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler +import io.netty.handler.ssl.SslHandler import io.netty.handler.stream.ChunkedWriteHandler import io.netty.handler.timeout.ReadTimeoutHandler import io.netty.handler.timeout.WriteTimeoutHandler @@ -30,9 +32,12 @@ class NettyHttpServer( var webSocketPath: Iterable>> = listOf(), var readTimeout: Int? = 60, var writeTimeout: Int? = null, - decodeType: NettyHttpDecodeType = if (webSocketPath.iterator().hasNext()) NettyHttpDecodeType.FULL_HTTP else NettyHttpDecodeType.MULTI_PART, + decodeType: NettyHttpDecodeType = if (webSocketPath.iterator() + .hasNext() + ) NettyHttpDecodeType.FULL_HTTP else NettyHttpDecodeType.MULTI_PART, backlog: Int = 1024, val wrapWebSocketFrame: Boolean = false, + val sslHandlerBuilder: ((allocator: ByteBufAllocator) -> SslHandler)? = null, ) : HttpServer { constructor( port: Int, @@ -41,16 +46,27 @@ class NettyHttpServer( webSocketPath: Iterable>> = listOf(), readTimeout: Int? = 60, writeTimeout: Int? = null, - decodeType: NettyHttpDecodeType = if (webSocketPath.iterator().hasNext()) NettyHttpDecodeType.FULL_HTTP else NettyHttpDecodeType.MULTI_PART, + decodeType: NettyHttpDecodeType = if (webSocketPath.iterator() + .hasNext() + ) NettyHttpDecodeType.FULL_HTTP else NettyHttpDecodeType.MULTI_PART, backlog: Int = 1024, wrapWebSocketFrame: Boolean = false, + sslHandlerBuilder: ((allocator: ByteBufAllocator) -> SslHandler)? = null, handler: (content: NettyHttpContent) -> Unit, ) : this( port, object : HttpHandler { override fun handle(content: NettyHttpContent) = handler(content) }, - bodySize, autoRun, webSocketPath, readTimeout, writeTimeout, decodeType, backlog, wrapWebSocketFrame + bodySize, + autoRun, + webSocketPath, + readTimeout, + writeTimeout, + decodeType, + backlog, + wrapWebSocketFrame, + sslHandlerBuilder ) var decodeType: NettyHttpDecodeType = decodeType @@ -73,6 +89,12 @@ class NettyHttpServer( .childHandler(object : ChannelInitializer() { override fun initChannel(ch: SocketChannel) { val pipeline = ch.pipeline() + + val sslHandler = sslHandlerBuilder?.invoke(ch.alloc()) + if (sslHandler != null) { + pipeline.addLast(sslHandler) + } + readTimeout?.let { pipeline.addLast(ReadTimeoutHandler(it)) } @@ -97,22 +119,32 @@ class NettyHttpServer( .option(ChannelOption.SO_BACKLOG, backlog) // determining the number of connections queued .option(ChannelOption.SO_REUSEADDR, true) .childOption(ChannelOption.SO_KEEPALIVE, java.lang.Boolean.TRUE) - private val future: ChannelFuture = b.bind(port) + private var future: ChannelFuture? = null init { if (autoRun) run() } override fun run() { + if (future != null) return + future = b.bind(port) log?.warn("NettyHttpServer started on port {}", port) - log?.info("try http://localhost:{}/", port) - future.sync() + log?.info( + "try http{}://localhost:{}/", + if (sslHandlerBuilder == null) "" else "s", + when { + sslHandlerBuilder == null && port == 80 -> "" + sslHandlerBuilder != null && port == 443 -> "" + else -> port + } + ) + future!!.sync() } override fun close() { log?.warn("NettyHttpServer({}) closed", port) - future.cancel(false) - future.channel().close() + future?.cancel(false) + future?.channel()?.close() } private fun updateHandler(): SimpleChannelInboundHandler {