diff --git a/Sources/Development/configure.swift b/Sources/Development/configure.swift index ab026581f4..03f37b5d33 100644 --- a/Sources/Development/configure.swift +++ b/Sources/Development/configure.swift @@ -1,5 +1,7 @@ import Vapor import NIOConcurrencyHelpers +import NIOPosix +import NIO public func configure(_ app: Application) throws { app.logger.logLevel = .debug @@ -21,6 +23,15 @@ public func configure(_ app: Application) throws { app.http.server.configuration.port = 8080 } + + app.http.server.configuration.serverChannelOptionConfiguration = { serverBootstrap in + serverBootstrap.serverChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: SocketOptionValue(1)) + } + + app.http.server.configuration.childChannelOptionConfiguration = { serverBootstrap in + serverBootstrap.childChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: SocketOptionValue(1)) + } + // routes try routes(app) } diff --git a/Sources/Vapor/HTTP/Server/HTTPServer.swift b/Sources/Vapor/HTTP/Server/HTTPServer.swift index e7c5ada489..8b8086fab0 100644 --- a/Sources/Vapor/HTTP/Server/HTTPServer.swift +++ b/Sources/Vapor/HTTP/Server/HTTPServer.swift @@ -155,7 +155,13 @@ public final class HTTPServer: Server { /// An optional callback that will be called instead of using swift-nio-ssl's regular certificate verification logic. public var customCertificateVerifyCallback: NIOSSLCustomVerificationCallback? + + /// An optional configuration for the setting the servers channels options + public var serverChannelOptionConfiguration: (ServerBootstrap) -> (ServerBootstrap) + /// An optional configuration for the setting the servers child channels options + public var childChannelOptionConfiguration: (ServerBootstrap) -> (ServerBootstrap) + public init( hostname: String = Self.defaultHostname, port: Int = Self.defaultPort, @@ -170,7 +176,9 @@ public final class HTTPServer: Server { serverName: String? = nil, reportMetrics: Bool = true, logger: Logger? = nil, - shutdownTimeout: TimeAmount = .seconds(10) + shutdownTimeout: TimeAmount = .seconds(10), + serverChannelOptionConfiguration: @escaping (ServerBootstrap) -> ServerBootstrap = { bootstrap in return bootstrap }, + childChannelOptionConfiguration: @escaping (ServerBootstrap) -> ServerBootstrap = { bootstrap in return bootstrap } ) { self.init( address: .hostname(hostname, port: port), @@ -185,7 +193,9 @@ public final class HTTPServer: Server { serverName: serverName, reportMetrics: reportMetrics, logger: logger, - shutdownTimeout: shutdownTimeout + shutdownTimeout: shutdownTimeout, + serverChannelOptionConfiguration: serverChannelOptionConfiguration, + childChannelOptionConfiguration: childChannelOptionConfiguration ) } @@ -202,7 +212,9 @@ public final class HTTPServer: Server { serverName: String? = nil, reportMetrics: Bool = true, logger: Logger? = nil, - shutdownTimeout: TimeAmount = .seconds(10) + shutdownTimeout: TimeAmount = .seconds(10), + serverChannelOptionConfiguration: @escaping (ServerBootstrap) -> ServerBootstrap = { bootstrap in return bootstrap }, + childChannelOptionConfiguration: @escaping (ServerBootstrap) -> ServerBootstrap = { bootstrap in return bootstrap } ) { self.address = address self.backlog = backlog @@ -222,6 +234,8 @@ public final class HTTPServer: Server { self.logger = logger ?? Logger(label: "codes.vapor.http-server") self.shutdownTimeout = shutdownTimeout self.customCertificateVerifyCallback = nil + self.serverChannelOptionConfiguration = serverChannelOptionConfiguration + self.childChannelOptionConfiguration = childChannelOptionConfiguration } } @@ -345,7 +359,7 @@ private final class HTTPServerConnection { // Specify backlog and enable SO_REUSEADDR for the server itself .serverChannelOption(ChannelOptions.backlog, value: Int32(configuration.backlog)) .serverChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: configuration.reuseAddress ? SocketOptionValue(1) : SocketOptionValue(0)) - + .serverChannelOption(configuation: configuration.serverChannelOptionConfiguration) // Set handlers that are applied to the Server's channel .serverChannelInitializer { channel in channel.pipeline.addHandler(quiesce.makeServerChannelHandler(channel: channel)) @@ -407,6 +421,7 @@ private final class HTTPServerConnection { .childChannelOption(ChannelOptions.socket(IPPROTO_TCP, TCP_NODELAY), value: configuration.tcpNoDelay ? SocketOptionValue(1) : SocketOptionValue(0)) .childChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: configuration.reuseAddress ? SocketOptionValue(1) : SocketOptionValue(0)) .childChannelOption(ChannelOptions.maxMessagesPerRead, value: 1) + .childChannelOption(configuation: configuration.childChannelOptionConfiguration) let channel: EventLoopFuture switch configuration.address { @@ -461,6 +476,16 @@ final class HTTPServerErrorHandler: ChannelInboundHandler { } } +extension ServerBootstrap { + func serverChannelOption(configuation: (ServerBootstrap) -> ServerBootstrap) -> ServerBootstrap { + return configuation(self) + } + + func childChannelOption(configuation: (ServerBootstrap) -> ServerBootstrap) -> ServerBootstrap { + return configuation(self) + } +} + extension ChannelPipeline { func addVaporHTTP2Handlers( application: Application,