diff --git a/Sources/Vapor/HTTP/Server/HTTPServer.swift b/Sources/Vapor/HTTP/Server/HTTPServer.swift index 7309b7df2..8ca7e5246 100644 --- a/Sources/Vapor/HTTP/Server/HTTPServer.swift +++ b/Sources/Vapor/HTTP/Server/HTTPServer.swift @@ -48,23 +48,34 @@ public final class HTTPServer: Server, Sendable { /// Port the server will bind to. public var port: Int { - get { - switch address { - case .hostname(_, let port): - return port ?? Self.defaultPort - default: - return Self.defaultPort - } - } - set { - switch address { - case .hostname(let hostname, _): - address = .hostname(hostname, port: newValue) - default: - address = .hostname(nil, port: newValue) - } - } - } + get { + switch address { + case .hostname(_, let port): + return port ?? Self.defaultPort + default: + return Self.defaultPort + } + } + set { + switch address { + case .hostname(let hostname, _): + address = .hostname(hostname, port: newValue) + default: + address = .hostname(nil, port: newValue) + } + } + } + + /// A human-readable description of the configured address. Used in log messages when starting server. + var addressDescription: String { + let scheme = tlsConfiguration == nil ? "http" : "https" + switch address { + case .hostname(let hostname, let port): + return "\(scheme)://\(hostname ?? Self.defaultHostname):\(port ?? Self.defaultPort)" + case .unixDomainSocket(let socketPath): + return "\(scheme)+unix: \(socketPath)" + } + } /// Listen backlog. public var backlog: Int @@ -307,19 +318,10 @@ public final class HTTPServer: Server, Sendable { /// Override the socket path. configuration.address = address! } - - /// Print starting message. - let scheme = configuration.tlsConfiguration == nil ? "http" : "https" - let addressDescription: String - switch configuration.address { - case .hostname(let hostname, let port): - addressDescription = "\(scheme)://\(hostname ?? configuration.hostname):\(port ?? configuration.port)" - case .unixDomainSocket(let socketPath): - addressDescription = "\(scheme)+unix: \(socketPath)" - } - - self.configuration.logger.notice("Server starting on \(addressDescription)") + /// Log starting message for debugging before attempting to start the server. + configuration.logger.debug("Server starting on \(configuration.addressDescription)") + /// Start the actual `HTTPServer`. try self.connection.withLockedValue { $0 = try HTTPServerConnection.start( @@ -331,6 +333,19 @@ public final class HTTPServer: Server, Sendable { ).wait() } + /// Overwrite configuration with actual address, if applicable. + /// They may differ from the provided configuation if port 0 was provided, for example. + if let localAddress = self.localAddress { + if let hostname = localAddress.hostname, let port = localAddress.port { + configuration.address = .hostname(hostname, port: port) + } else if let pathname = localAddress.pathname { + configuration.address = .unixDomainSocket(path: pathname) + } + } + + /// Log started message with the actual configuration. + configuration.logger.notice("Server started on \(configuration.addressDescription)") + self.configuration = configuration self.didStart.withLockedValue { $0 = true } } diff --git a/Tests/VaporTests/ApplicationTests.swift b/Tests/VaporTests/ApplicationTests.swift index a46cfafde..2aaff1faf 100644 --- a/Tests/VaporTests/ApplicationTests.swift +++ b/Tests/VaporTests/ApplicationTests.swift @@ -179,7 +179,7 @@ final class ApplicationTests: XCTestCase { XCTAssertNotNil(app.http.server.shared.localAddress) XCTAssertEqual("0.0.0.0", app.http.server.configuration.hostname) - XCTAssertEqual(0, app.http.server.configuration.port) + XCTAssertEqual(app.http.server.shared.localAddress?.port, app.http.server.configuration.port) guard let localAddress = app.http.server.shared.localAddress, localAddress.ipAddress != nil, @@ -190,7 +190,7 @@ final class ApplicationTests: XCTestCase { let response = try app.client.get("http://localhost:\(port)/hello").wait() let returnedConfig = try response.content.decode(AddressConfig.self) XCTAssertEqual(returnedConfig.hostname, "0.0.0.0") - XCTAssertEqual(returnedConfig.port, 0) + XCTAssertEqual(returnedConfig.port, port) } func testConfigurationAddressDetailsReflectedWhenProvidedThroughServeCommand() throws { diff --git a/Tests/VaporTests/ServerTests.swift b/Tests/VaporTests/ServerTests.swift index bcf7a0a7d..4254978e9 100644 --- a/Tests/VaporTests/ServerTests.swift +++ b/Tests/VaporTests/ServerTests.swift @@ -1409,6 +1409,16 @@ final class ServerTests: XCTestCase { } } + func testConfigurationHasActualPortAfterStart() throws { + let app = Application(.testing) + app.http.server.configuration.port = 0 + defer { app.shutdown() } + try app.start() + + XCTAssertNotEqual(app.http.server.configuration.port, 0) + XCTAssertEqual(app.http.server.configuration.port, app.http.server.shared.localAddress?.port) + } + override class func setUp() { XCTAssertTrue(isLoggingConfigured) }