diff --git a/Sources/HTTP/Responder/HTTPServer.swift b/Sources/HTTP/Responder/HTTPServer.swift index 20555a31..589f4c65 100644 --- a/Sources/HTTP/Responder/HTTPServer.swift +++ b/Sources/HTTP/Responder/HTTPServer.swift @@ -84,6 +84,14 @@ public final class HTTPServer { // MARK: Properties + /// The port the `HTTPServer` is bound to. + /// + /// Nil if `HTTPServer` is not bound to an IP port (eg. serving from a Unix socket or some other exotic channel). + public var port: Int? { + guard let port_uint16 = channel.localAddress?.port else { return nil } + return Int(exactly: port_uint16) + } + /// A future that will be signaled when the server closes. public var onClose: Future { return channel.closeFuture diff --git a/Tests/HTTPTests/HTTPTests.swift b/Tests/HTTPTests/HTTPTests.swift index 94315ba9..1537a655 100644 --- a/Tests/HTTPTests/HTTPTests.swift +++ b/Tests/HTTPTests/HTTPTests.swift @@ -76,20 +76,22 @@ class HTTPTests: XCTestCase { let worker = MultiThreadedEventLoopGroup(numberOfThreads: 1) let server = try HTTPServer.start( hostname: "localhost", - port: 8080, + port: 0, responder: LargeResponder(), on: worker ) { error in XCTFail("\(error)") }.wait() - - let client = try HTTPClient.connect(hostname: "localhost", port: 8080, on: worker).wait() + defer { + try! server.close().wait() + try! server.onClose.wait() + } + + let client = try HTTPClient.connect(hostname: "localhost", port: server.port, on: worker).wait() var req = HTTPRequest(method: .GET, url: "/") req.headers.replaceOrAdd(name: .connection, value: "close") let res = try client.send(req).wait() XCTAssertEqual(res.body.count, 2_000_000) - try server.close().wait() - try server.onClose.wait() } func testUpgradeFail() throws { @@ -119,6 +121,30 @@ class HTTPTests: XCTestCase { } } + func testServerPort() throws { + struct Responder: HTTPServerResponder { + func respond(to request: HTTPRequest, on worker: Worker) -> EventLoopFuture { + let res = HTTPResponse(status: .ok, body: "OK") + return worker.future(res) + } + } + + let worker = MultiThreadedEventLoopGroup(numberOfThreads: 1) + let server = try HTTPServer.start( + hostname: "localhost", + port: 0, + responder: Responder(), + on: worker + ) { error in XCTFail("\(error)") }.wait() + defer { + try! server.close().wait() + try! server.onClose.wait() + } + + XCTAssertNotNil(server.port) + XCTAssertGreaterThan(server.port!, 0) + } + static let allTests = [ ("testCookieParse", testCookieParse), ("testAcceptHeader", testAcceptHeader), @@ -127,5 +153,6 @@ class HTTPTests: XCTestCase { ("testMultipleCookiesAreSerializedCorrectly", testMultipleCookiesAreSerializedCorrectly), ("testLargeResponseClose", testLargeResponseClose), ("testUpgradeFail", testUpgradeFail), + ("testServerPort", testServerPort), ] }