From ff448f98a162051a3fa879c53b0c64bdbce1a02b Mon Sep 17 00:00:00 2001 From: Adam Fowler Date: Tue, 19 Dec 2023 12:38:48 +0100 Subject: [PATCH 1/8] Fix hello tests --- hello/Packages/hummingbird | 1 + hello/Sources/App/Application+build.swift | 5 ++--- hello/Tests/AppTests/AppTests.swift | 19 ++++++++----------- 3 files changed, 11 insertions(+), 14 deletions(-) create mode 120000 hello/Packages/hummingbird diff --git a/hello/Packages/hummingbird b/hello/Packages/hummingbird new file mode 120000 index 00000000..e3aaea80 --- /dev/null +++ b/hello/Packages/hummingbird @@ -0,0 +1 @@ +/Users/adamfowler/Developer/server/hummingbird-project/hummingbird \ No newline at end of file diff --git a/hello/Sources/App/Application+build.swift b/hello/Sources/App/Application+build.swift index dffcf62c..9cc48950 100644 --- a/hello/Sources/App/Application+build.swift +++ b/hello/Sources/App/Application+build.swift @@ -2,9 +2,8 @@ import Hummingbird import HummingbirdCore import HummingbirdFoundation -func buildApplication(configuration: HBApplicationConfiguration) -> HBApplication, HTTP1Channel> { - let router = HBRouterBuilder() - router.middlewares.add(HBFileMiddleware()) +func buildApplication(configuration: HBApplicationConfiguration) -> some HBApplicationProtocol { + let router = HBRouter() router.get("/") { _, _ in return "Hello" } diff --git a/hello/Tests/AppTests/AppTests.swift b/hello/Tests/AppTests/AppTests.swift index 4f81c487..07d1438b 100644 --- a/hello/Tests/AppTests/AppTests.swift +++ b/hello/Tests/AppTests/AppTests.swift @@ -1,19 +1,16 @@ -import App +@testable import App import Hummingbird import HummingbirdXCT import XCTest final class AppTests: XCTestCase { - func testApp() throws { - let app = HBApplication(testing: .live) - try app.configure() - - try app.XCTStart() - defer { app.XCTStop() } - - try app.XCTExecute(uri: "/", method: .GET) { response in - XCTAssertEqual(response.status, .ok) - XCTAssertEqual(response.body.map { String(buffer: $0) }, "Hello") + func testApp() async throws { + let app = buildApplication(configuration: .init()) + try await app.test(.router) { client in + try await client.XCTExecute(uri: "/", method: .get) { response in + XCTAssertEqual(response.status, .ok) + XCTAssertEqual(response.body.map { String(buffer: $0) }, "Hello") + } } } } From 64a01e07a7878ec38f526a63efea179e834ae083 Mon Sep 17 00:00:00 2001 From: Adam Fowler Date: Wed, 20 Dec 2023 18:43:53 +0100 Subject: [PATCH 2/8] HTTP2 --- hello/Sources/App/Application+build.swift | 2 - http2/Package.swift | 11 ++--- http2/Packages/hummingbird | 1 + http2/Sources/App/Application+build.swift | 49 +++++++++++++++++++ http2/Sources/App/app.swift | 16 +++--- http2/Sources/App/application+configure.swift | 24 --------- http2/Tests/AppTests/AppTests.swift | 30 +++++------- 7 files changed, 72 insertions(+), 61 deletions(-) create mode 120000 http2/Packages/hummingbird create mode 100644 http2/Sources/App/Application+build.swift delete mode 100644 http2/Sources/App/application+configure.swift diff --git a/hello/Sources/App/Application+build.swift b/hello/Sources/App/Application+build.swift index 9cc48950..5f3cd0b6 100644 --- a/hello/Sources/App/Application+build.swift +++ b/hello/Sources/App/Application+build.swift @@ -1,6 +1,4 @@ import Hummingbird -import HummingbirdCore -import HummingbirdFoundation func buildApplication(configuration: HBApplicationConfiguration) -> some HBApplicationProtocol { let router = HBRouter() diff --git a/http2/Package.swift b/http2/Package.swift index 52d9f42d..207d1170 100644 --- a/http2/Package.swift +++ b/http2/Package.swift @@ -1,19 +1,17 @@ -// swift-tools-version:5.7 +// swift-tools-version:5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "http2", - platforms: [.macOS(.v10_14)], + platforms: [.macOS(.v14)], products: [ .executable(name: "App", targets: ["App"]), ], dependencies: [ .package(url: "https://github.com/apple/swift-certificates.git", from: "1.0.0"), - .package(url: "https://github.com/hummingbird-project/hummingbird-core.git", from: "1.0.0"), - .package(url: "https://github.com/hummingbird-project/hummingbird.git", from: "1.0.0"), - .package(url: "https://github.com/hummingbird-project/hummingbird-xct-async-http-client.git", from: "0.1.0"), + .package(url: "https://github.com/hummingbird-project/hummingbird.git", branch: "2.x.x"), .package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.0.0"), ], targets: [ @@ -21,7 +19,7 @@ let package = Package( name: "App", dependencies: [ .product(name: "Hummingbird", package: "hummingbird"), - .product(name: "HummingbirdHTTP2", package: "hummingbird-core"), + .product(name: "HummingbirdHTTP2", package: "hummingbird"), .product(name: "ArgumentParser", package: "swift-argument-parser"), ], swiftSettings: [ @@ -37,7 +35,6 @@ let package = Package( .byName(name: "App"), .product(name: "X509", package: "swift-certificates"), .product(name: "HummingbirdXCT", package: "hummingbird"), - .product(name: "HBXCTAsyncHTTPClient", package: "hummingbird-xct-async-http-client"), ] ), ] diff --git a/http2/Packages/hummingbird b/http2/Packages/hummingbird new file mode 120000 index 00000000..e3aaea80 --- /dev/null +++ b/http2/Packages/hummingbird @@ -0,0 +1 @@ +/Users/adamfowler/Developer/server/hummingbird-project/hummingbird \ No newline at end of file diff --git a/http2/Sources/App/Application+build.swift b/http2/Sources/App/Application+build.swift new file mode 100644 index 00000000..7df2516d --- /dev/null +++ b/http2/Sources/App/Application+build.swift @@ -0,0 +1,49 @@ +import Hummingbird +import HummingbirdHTTP2 +import Logging +import NIOCore +import NIOHTTPTypesHTTP2 + +public protocol AppArguments { + var tlsConfiguration: TLSConfiguration { get throws } +} + +struct ChannelRequestContext: HBRequestContext { + init(eventLoop: EventLoop, allocator: ByteBufferAllocator, logger: Logger) { + self.coreContext = .init(eventLoop: eventLoop, allocator: allocator, logger: logger) + self.channel = nil + } + + init(channel: Channel, logger: Logger) { + self.coreContext = .init(eventLoop: channel.eventLoop, allocator: channel.allocator, logger: logger) + self.channel = channel + } + + var hasHTTP2Handler: Bool { + get async { + if let channel = self.channel { + return (try? await channel.pipeline.handler(type: HTTP2FramePayloadToHTTPServerCodec.self).get()) != nil + } + return false + } + } + + var coreContext: HBCoreRequestContext + let channel: Channel? +} + +import Hummingbird + +func buildApplication(arguments: some AppArguments, configuration: HBApplicationConfiguration) throws -> some HBApplicationProtocol { + let router = HBRouter(context: ChannelRequestContext.self) + router.get("/http") { _, context in + return "Using http v\(await context.hasHTTP2Handler ? "2.0" : "1.1")" + } + + let app = try HBApplication( + responder: router.buildResponder(), + channelSetup: .http2(tlsConfiguration: arguments.tlsConfiguration), + configuration: configuration + ) + return app +} diff --git a/http2/Sources/App/app.swift b/http2/Sources/App/app.swift index e4f31ad9..55efe687 100644 --- a/http2/Sources/App/app.swift +++ b/http2/Sources/App/app.swift @@ -3,12 +3,12 @@ import Hummingbird import NIOSSL @main -struct HummingbirdArguments: ParsableCommand, AppArguments { +struct HummingbirdArguments: AsyncParsableCommand, AppArguments { @Option(name: .shortAndLong) var hostname: String = "127.0.0.1" @Option(name: .shortAndLong) - var port: Int = 8080 + var port: Int = 8081 @Option(name: .shortAndLong, help: "PEM file containing certificate chain") var certificateChain: String @@ -27,16 +27,14 @@ struct HummingbirdArguments: ParsableCommand, AppArguments { } } - func run() throws { - let app = HBApplication( + func run() async throws { + let app = try buildApplication( + arguments: self, configuration: .init( address: .hostname(self.hostname, port: self.port), - serverName: "Hummingbird", - idleTimeoutConfiguration: .init(readTimeout: .seconds(5), writeTimeout: .seconds(5)) + serverName: "Hummingbird" ) ) - try app.configure(self) - try app.start() - app.wait() + try await app.runService() } } diff --git a/http2/Sources/App/application+configure.swift b/http2/Sources/App/application+configure.swift deleted file mode 100644 index 812fcae6..00000000 --- a/http2/Sources/App/application+configure.swift +++ /dev/null @@ -1,24 +0,0 @@ -import Hummingbird -import HummingbirdHTTP2 - -public protocol AppArguments { - var tlsConfiguration: TLSConfiguration { get throws } -} - -extension HBApplication { - /// configure your application - /// add middleware - /// setup the encoder/decoder - /// add your routes - public func configure(_ arguments: AppArguments) throws { - // Add HTTP2 TLS Upgrade option - try server.addHTTP2Upgrade( - tlsConfiguration: arguments.tlsConfiguration, - idleReadTimeout: .seconds(30) - ) - - router.get("/http") { request in - return "Using http v\(request.version.major).\(request.version.minor)" - } - } -} diff --git a/http2/Tests/AppTests/AppTests.swift b/http2/Tests/AppTests/AppTests.swift index 4dbf2390..7b607a47 100644 --- a/http2/Tests/AppTests/AppTests.swift +++ b/http2/Tests/AppTests/AppTests.swift @@ -48,27 +48,19 @@ struct TestAppArguments: AppArguments { } final class AppTests: XCTestCase { - func testApp() throws { - var clientConfiguration = TLSConfiguration.makeClientConfiguration() - clientConfiguration.certificateVerification = .none - let app = HBApplication( - testing: .ahc(scheme: .https), - configuration: .init(idleTimeoutConfiguration: .init(readTimeout: .seconds(5), writeTimeout: .seconds(5))), - clientConfiguration: .init(tlsConfiguration: clientConfiguration) - ) - try app.configure(TestAppArguments()) + func testApp() async throws { + let app = try buildApplication(arguments: TestAppArguments(), configuration: .init()) - try app.XCTStart() - defer { app.XCTStop() } - - try app.XCTExecute(uri: "/http", method: .GET) { response in - XCTAssertEqual(response.status, .ok) - XCTAssertEqual(response.body.map { String(buffer: $0) }, "Using http v2.0") - } + try await app.test(.ahc(.https)) { client in + try await client.XCTExecute(uri: "/http", method: .get) { response in + XCTAssertEqual(response.status, .ok) + XCTAssertEqual(response.body.map { String(buffer: $0) }, "Using http v2.0") + } - try app.XCTExecute(uri: "/http", method: .GET) { response in - XCTAssertEqual(response.status, .ok) - XCTAssertEqual(response.body.map { String(buffer: $0) }, "Using http v2.0") + try await client.XCTExecute(uri: "/http", method: .get) { response in + XCTAssertEqual(response.status, .ok) + XCTAssertEqual(response.body.map { String(buffer: $0) }, "Using http v2.0") + } } } } From 89e084c4486c240079e46101905eabb51e33f2db Mon Sep 17 00:00:00 2001 From: Adam Fowler Date: Wed, 17 Jan 2024 09:40:48 +0000 Subject: [PATCH 3/8] Update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bc64ba1b..fe1c5f18 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ Examples converted to Hummingbird 2.0 - [hello](https://github.com/hummingbird-project/hummingbird-examples/tree/main/hello) - Basic application setup +- [http2](https://github.com/hummingbird-project/hummingbird-examples/tree/main/http2) - Basic application with HTTP2 upgrade added - [todos-dynamodb](https://github.com/hummingbird-project/hummingbird-examples/tree/main/todos-dynamodb) - Todos application, based off [TodoBackend](http://todobackend.com) spec, using DynamoDB Examples still working with Hummingbird 1.0 @@ -10,7 +11,6 @@ Examples still working with Hummingbird 1.0 - [auth-srp](https://github.com/hummingbird-project/hummingbird-examples/tree/main/auth-srp) - Secure Remote Password authentication. - [graphql-server](https://github.com/hummingbird-project/hummingbird-examples/tree/main/graphql-server) - GraphQL server using [Graphiti](https://github.com/GraphQLSwift/Graphiti) - [html-form](https://github.com/hummingbird-project/hummingbird-examples/tree/main/html-form) - Link HTML form to Hummingbird application -- [http2](https://github.com/hummingbird-project/hummingbird-examples/tree/main/http2) - Basic application with HTTP2 upgrade added - [ios-image-server](https://github.com/hummingbird-project/hummingbird-examples/tree/main/ios-image-server) - iOS web server that provides access to iPhone photo library. - [jobs](https://github.com/hummingbird-project/hummingbird-examples/tree/main/jobs) - Demonstrating offloading of jobs to another server. - [multipart-form](https://github.com/hummingbird-project/hummingbird-examples/tree/main/multipart-form) - HTML form using Multipart form data, using MultipartKit From eb29592205c63fe8b3655eab94e2bb9e54792e0e Mon Sep 17 00:00:00 2001 From: Adam Fowler Date: Wed, 20 Dec 2023 18:45:21 +0100 Subject: [PATCH 4/8] Update README --- hello/Sources/App/Application+build.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hello/Sources/App/Application+build.swift b/hello/Sources/App/Application+build.swift index 5f3cd0b6..c6f53074 100644 --- a/hello/Sources/App/Application+build.swift +++ b/hello/Sources/App/Application+build.swift @@ -7,7 +7,7 @@ func buildApplication(configuration: HBApplicationConfiguration) -> some HBAppli } let app = HBApplication( - responder: router.buildResponder(), + router: router, configuration: configuration ) return app From 7fd1062871a265848db3a82a3f8e01ab5deb346f Mon Sep 17 00:00:00 2001 From: Adam Fowler Date: Sat, 23 Dec 2023 08:41:32 +0100 Subject: [PATCH 5/8] Update for changes on 2.x.x --- hello/Packages/hummingbird | 1 - http2/Packages/hummingbird | 1 - http2/Sources/App/Application+build.swift | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) delete mode 120000 hello/Packages/hummingbird delete mode 120000 http2/Packages/hummingbird diff --git a/hello/Packages/hummingbird b/hello/Packages/hummingbird deleted file mode 120000 index e3aaea80..00000000 --- a/hello/Packages/hummingbird +++ /dev/null @@ -1 +0,0 @@ -/Users/adamfowler/Developer/server/hummingbird-project/hummingbird \ No newline at end of file diff --git a/http2/Packages/hummingbird b/http2/Packages/hummingbird deleted file mode 120000 index e3aaea80..00000000 --- a/http2/Packages/hummingbird +++ /dev/null @@ -1 +0,0 @@ -/Users/adamfowler/Developer/server/hummingbird-project/hummingbird \ No newline at end of file diff --git a/http2/Sources/App/Application+build.swift b/http2/Sources/App/Application+build.swift index 7df2516d..da791f42 100644 --- a/http2/Sources/App/Application+build.swift +++ b/http2/Sources/App/Application+build.swift @@ -42,7 +42,7 @@ func buildApplication(arguments: some AppArguments, configuration: HBApplication let app = try HBApplication( responder: router.buildResponder(), - channelSetup: .http2(tlsConfiguration: arguments.tlsConfiguration), + server: .http2(tlsConfiguration: arguments.tlsConfiguration), configuration: configuration ) return app From 99c447362550a3b0e60c745b1c3299729bdd38cd Mon Sep 17 00:00:00 2001 From: Adam Fowler Date: Sun, 24 Dec 2023 14:53:45 +0100 Subject: [PATCH 6/8] =?UTF-8?q?Don=E2=80=99t=20export=20HBXCTAsyncHTTPClie?= =?UTF-8?q?nt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- http2/Tests/AppTests/AppTests.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/http2/Tests/AppTests/AppTests.swift b/http2/Tests/AppTests/AppTests.swift index 7b607a47..94760d65 100644 --- a/http2/Tests/AppTests/AppTests.swift +++ b/http2/Tests/AppTests/AppTests.swift @@ -1,6 +1,5 @@ @testable import App import Crypto -import HBXCTAsyncHTTPClient import Hummingbird import HummingbirdXCT import NIOHTTP2 From a5fcf447908385b153d35b2cfd35a864fc500723 Mon Sep 17 00:00:00 2001 From: Adam Fowler Date: Tue, 16 Jan 2024 16:46:46 +0000 Subject: [PATCH 7/8] Update http2/Sources/App/Application+build.swift Co-authored-by: Joannis Orlandos --- http2/Sources/App/Application+build.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/http2/Sources/App/Application+build.swift b/http2/Sources/App/Application+build.swift index da791f42..b3aa4e2a 100644 --- a/http2/Sources/App/Application+build.swift +++ b/http2/Sources/App/Application+build.swift @@ -41,7 +41,7 @@ func buildApplication(arguments: some AppArguments, configuration: HBApplication } let app = try HBApplication( - responder: router.buildResponder(), + router: router, server: .http2(tlsConfiguration: arguments.tlsConfiguration), configuration: configuration ) From 7b49cc8d8f85cdd487d648ea29794230b14be3b4 Mon Sep 17 00:00:00 2001 From: Adam Fowler Date: Tue, 16 Jan 2024 17:00:59 +0000 Subject: [PATCH 8/8] Fix up after changes to Hummingbird --- hello/Package.swift | 1 + hello/Tests/AppTests/AppTests.swift | 2 +- http2/Sources/App/Application+build.swift | 7 ++++--- http2/Tests/AppTests/AppTests.swift | 4 ++-- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/hello/Package.swift b/hello/Package.swift index 6c7a2957..53044228 100644 --- a/hello/Package.swift +++ b/hello/Package.swift @@ -29,6 +29,7 @@ let package = Package( name: "AppTests", dependencies: [ .byName(name: "App"), + .product(name: "Hummingbird", package: "hummingbird"), .product(name: "HummingbirdXCT", package: "hummingbird"), ] ), diff --git a/hello/Tests/AppTests/AppTests.swift b/hello/Tests/AppTests/AppTests.swift index 07d1438b..b9f10ab5 100644 --- a/hello/Tests/AppTests/AppTests.swift +++ b/hello/Tests/AppTests/AppTests.swift @@ -9,7 +9,7 @@ final class AppTests: XCTestCase { try await app.test(.router) { client in try await client.XCTExecute(uri: "/", method: .get) { response in XCTAssertEqual(response.status, .ok) - XCTAssertEqual(response.body.map { String(buffer: $0) }, "Hello") + XCTAssertEqual(String(buffer: response.body), "Hello") } } } diff --git a/http2/Sources/App/Application+build.swift b/http2/Sources/App/Application+build.swift index b3aa4e2a..e8f76a03 100644 --- a/http2/Sources/App/Application+build.swift +++ b/http2/Sources/App/Application+build.swift @@ -9,13 +9,13 @@ public protocol AppArguments { } struct ChannelRequestContext: HBRequestContext { - init(eventLoop: EventLoop, allocator: ByteBufferAllocator, logger: Logger) { - self.coreContext = .init(eventLoop: eventLoop, allocator: allocator, logger: logger) + init(allocator: ByteBufferAllocator, logger: Logger) { + self.coreContext = .init(allocator: allocator, logger: logger) self.channel = nil } init(channel: Channel, logger: Logger) { - self.coreContext = .init(eventLoop: channel.eventLoop, allocator: channel.allocator, logger: logger) + self.coreContext = .init(allocator: channel.allocator, logger: logger) self.channel = channel } @@ -37,6 +37,7 @@ import Hummingbird func buildApplication(arguments: some AppArguments, configuration: HBApplicationConfiguration) throws -> some HBApplicationProtocol { let router = HBRouter(context: ChannelRequestContext.self) router.get("/http") { _, context in + // return "Using http v\(request.head. == "h2" ? "2.0" : "1.1")" return "Using http v\(await context.hasHTTP2Handler ? "2.0" : "1.1")" } diff --git a/http2/Tests/AppTests/AppTests.swift b/http2/Tests/AppTests/AppTests.swift index 94760d65..bda9aae2 100644 --- a/http2/Tests/AppTests/AppTests.swift +++ b/http2/Tests/AppTests/AppTests.swift @@ -53,12 +53,12 @@ final class AppTests: XCTestCase { try await app.test(.ahc(.https)) { client in try await client.XCTExecute(uri: "/http", method: .get) { response in XCTAssertEqual(response.status, .ok) - XCTAssertEqual(response.body.map { String(buffer: $0) }, "Using http v2.0") + XCTAssertEqual(String(buffer: response.body), "Using http v2.0") } try await client.XCTExecute(uri: "/http", method: .get) { response in XCTAssertEqual(response.status, .ok) - XCTAssertEqual(response.body.map { String(buffer: $0) }, "Using http v2.0") + XCTAssertEqual(String(buffer: response.body), "Using http v2.0") } } }