Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add hooks for socket configuration #2918

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 11 additions & 0 deletions 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
Expand All @@ -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)
}
Expand Down
33 changes: 29 additions & 4 deletions Sources/Vapor/HTTP/Server/HTTPServer.swift
Expand Up @@ -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,
Expand All @@ -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),
Expand All @@ -185,7 +193,9 @@ public final class HTTPServer: Server {
serverName: serverName,
reportMetrics: reportMetrics,
logger: logger,
shutdownTimeout: shutdownTimeout
shutdownTimeout: shutdownTimeout,
serverChannelOptionConfiguration: serverChannelOptionConfiguration,
childChannelOptionConfiguration: childChannelOptionConfiguration
)
}

Expand All @@ -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 },
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really don't like adding this niche use case to the initializer

childChannelOptionConfiguration: @escaping (ServerBootstrap) -> ServerBootstrap = { bootstrap in return bootstrap }
) {
self.address = address
self.backlog = backlog
Expand All @@ -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
}
}

Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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<Channel>
switch configuration.address {
Expand Down Expand Up @@ -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,
Expand Down