Skip to content

Commit

Permalink
Moving stuff about, Get TLS working
Browse files Browse the repository at this point in the history
  • Loading branch information
adam-fowler committed Nov 7, 2023
1 parent 9372df3 commit 6a14e21
Show file tree
Hide file tree
Showing 45 changed files with 1,580 additions and 1,415 deletions.
135 changes: 59 additions & 76 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ let package = Package(
name: "hummingbird",
platforms: [.macOS(.v14), .iOS(.v17), .tvOS(.v17)],
products: [
.library(name: "Hummingbird", targets: ["Hummingbird"]),
.library(name: "HummingbirdFoundation", targets: ["HummingbirdFoundation"]),
.library(name: "HummingbirdJobs", targets: ["HummingbirdJobs"]),
.library(name: "HummingbirdXCT", targets: ["HummingbirdXCT"]),
.executable(name: "PerformanceTest", targets: ["PerformanceTest"]),
// .library(name: "Hummingbird", targets: ["Hummingbird"]),
// .library(name: "HummingbirdFoundation", targets: ["HummingbirdFoundation"]),
// .library(name: "HummingbirdJobs", targets: ["HummingbirdJobs"]),
// .library(name: "HummingbirdXCT", targets: ["HummingbirdXCT"]),
// .executable(name: "PerformanceTest", targets: ["PerformanceTest"]),
],
dependencies: [
.package(url: "https://github.com/apple/swift-async-algorithms.git", from: "0.1.0"),
Expand All @@ -26,46 +26,37 @@ let package = Package(
.package(url: "https://github.com/swift-server/swift-service-lifecycle.git", from: "2.0.0"),
],
targets: [
.target(name: "Hummingbird", dependencies: [
.byName(name: "HummingbirdCore"),
.product(name: "ServiceLifecycle", package: "swift-service-lifecycle"),
.product(name: "AsyncAlgorithms", package: "swift-async-algorithms"),
.product(name: "Logging", package: "swift-log"),
.product(name: "Metrics", package: "swift-metrics"),
.product(name: "Tracing", package: "swift-distributed-tracing"),
.product(name: "NIOCore", package: "swift-nio"),
.product(name: "NIOPosix", package: "swift-nio"),
.product(name: "NIOHTTP1", package: "swift-nio"),
]),
.target(name: "HummingbirdFoundation", dependencies: [
.byName(name: "Hummingbird"),
.product(name: "NIOCore", package: "swift-nio"),
.product(name: "NIOPosix", package: "swift-nio"),
.product(name: "NIOFoundationCompat", package: "swift-nio"),
]),
.target(name: "HummingbirdJobs", dependencies: [
.byName(name: "Hummingbird"),
.product(name: "Logging", package: "swift-log"),
]),
.target(name: "HummingbirdXCT", dependencies: [
.byName(name: "Hummingbird"),
.byName(name: "HummingbirdCoreXCT"),
.product(name: "NIOCore", package: "swift-nio"),
.product(name: "NIOEmbedded", package: "swift-nio"),
.product(name: "NIOPosix", package: "swift-nio"),
.product(name: "NIOHTTP1", package: "swift-nio"),
]),
/* .target(name: "Hummingbird", dependencies: [
.byName(name: "HummingbirdCore"),
.product(name: "ServiceLifecycle", package: "swift-service-lifecycle"),
.product(name: "AsyncAlgorithms", package: "swift-async-algorithms"),
.product(name: "Logging", package: "swift-log"),
.product(name: "Metrics", package: "swift-metrics"),
.product(name: "Tracing", package: "swift-distributed-tracing"),
.product(name: "NIOCore", package: "swift-nio"),
.product(name: "NIOPosix", package: "swift-nio"),
.product(name: "NIOHTTP1", package: "swift-nio"),
]),
.target(name: "HummingbirdFoundation", dependencies: [
.byName(name: "Hummingbird"),
.product(name: "NIOCore", package: "swift-nio"),
.product(name: "NIOPosix", package: "swift-nio"),
.product(name: "NIOFoundationCompat", package: "swift-nio"),
]),
.target(name: "HummingbirdJobs", dependencies: [
.byName(name: "Hummingbird"),
.product(name: "Logging", package: "swift-log"),
]),
.target(name: "HummingbirdXCT", dependencies: [
.byName(name: "Hummingbird"),
.byName(name: "HummingbirdCoreXCT"),
.product(name: "NIOCore", package: "swift-nio"),
.product(name: "NIOEmbedded", package: "swift-nio"),
.product(name: "NIOPosix", package: "swift-nio"),
.product(name: "NIOHTTP1", package: "swift-nio"),
]),*/
.target(name: "HummingbirdCore", dependencies: [
.product(name: "Logging", package: "swift-log"),
.product(name: "NIOCore", package: "swift-nio"),
.product(name: "NIOConcurrencyHelpers", package: "swift-nio"),
.product(name: "NIOExtras", package: "swift-nio-extras"),
.product(name: "NIOHTTP1", package: "swift-nio"),
.product(name: "NIOPosix", package: "swift-nio"),
.product(name: "NIOTransportServices", package: "swift-nio-transport-services"),
.product(name: "ServiceLifecycle", package: "swift-service-lifecycle"),
]),
.target(name: "HummingbirdCoreAsync", dependencies: [
.product(name: "AsyncAlgorithms", package: "swift-async-algorithms"),
.product(name: "Logging", package: "swift-log"),
.product(name: "NIOCore", package: "swift-nio"),
.product(name: "NIOConcurrencyHelpers", package: "swift-nio"),
Expand All @@ -82,36 +73,36 @@ let package = Package(
.product(name: "NIOPosix", package: "swift-nio"),
.product(name: "NIOSSL", package: "swift-nio-ssl"),
]),
.target(name: "HummingbirdHTTP2", dependencies: [
.byName(name: "HummingbirdCore"),
.product(name: "NIOCore", package: "swift-nio"),
.product(name: "NIOHTTP2", package: "swift-nio-http2"),
.product(name: "NIOSSL", package: "swift-nio-ssl"),
]),
/* .target(name: "HummingbirdHTTP2", dependencies: [
.byName(name: "HummingbirdCore"),
.product(name: "NIOCore", package: "swift-nio"),
.product(name: "NIOHTTP2", package: "swift-nio-http2"),
.product(name: "NIOSSL", package: "swift-nio-ssl"),
]),*/
.target(name: "HummingbirdTLS", dependencies: [
.byName(name: "HummingbirdCore"),
.product(name: "NIOCore", package: "swift-nio"),
.product(name: "NIOSSL", package: "swift-nio-ssl"),
]),
.executableTarget(name: "PerformanceTest", dependencies: [
.byName(name: "Hummingbird"),
.byName(name: "HummingbirdFoundation"),
.product(name: "NIOPosix", package: "swift-nio"),
]),
/* .executableTarget(name: "PerformanceTest", dependencies: [
.byName(name: "Hummingbird"),
.byName(name: "HummingbirdFoundation"),
.product(name: "NIOPosix", package: "swift-nio"),
]),*/
// test targets
.testTarget(name: "HummingbirdTests", dependencies: [
.byName(name: "Hummingbird"),
.byName(name: "HummingbirdFoundation"),
.byName(name: "HummingbirdXCT"),
]),
.testTarget(name: "HummingbirdFoundationTests", dependencies: [
.byName(name: "HummingbirdFoundation"),
.byName(name: "HummingbirdXCT"),
]),
.testTarget(name: "HummingbirdJobsTests", dependencies: [
.byName(name: "HummingbirdJobs"),
.byName(name: "HummingbirdXCT"),
]),
/* .testTarget(name: "HummingbirdTests", dependencies: [
.byName(name: "Hummingbird"),
.byName(name: "HummingbirdFoundation"),
.byName(name: "HummingbirdXCT"),
]),
.testTarget(name: "HummingbirdFoundationTests", dependencies: [
.byName(name: "HummingbirdFoundation"),
.byName(name: "HummingbirdXCT"),
]),
.testTarget(name: "HummingbirdJobsTests", dependencies: [
.byName(name: "HummingbirdJobs"),
.byName(name: "HummingbirdXCT"),
]),*/
.testTarget(
name: "HummingbirdCoreTests",
dependencies:
Expand All @@ -123,13 +114,5 @@ let package = Package(
],
resources: [.process("Certificates")]
),
.testTarget(
name: "HummingbirdCoreAsyncTests",
dependencies:
[
.byName(name: "HummingbirdCoreAsync"),
.byName(name: "HummingbirdCoreXCT"),
]
),
]
)
13 changes: 4 additions & 9 deletions Sources/HummingbirdCore/Error/HTTPErrorResponse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,13 @@ extension HBHTTPResponseError {
/// Generate response from error
/// - Parameter allocator: Byte buffer allocator used to allocate message body
/// - Returns: Response
public func response(version: HTTPVersion, allocator: ByteBufferAllocator) -> HBHTTPResponse {
var headers: HTTPHeaders = self.headers

public func response(allocator: ByteBufferAllocator) -> HBHTTPResponse {
let body: HBResponseBody
if let buffer = self.body(allocator: allocator) {
body = .byteBuffer(buffer)
headers.replaceOrAdd(name: "content-length", value: String(describing: buffer.readableBytes))
body = .init(byteBuffer: buffer)
} else {
body = .empty
headers.replaceOrAdd(name: "content-length", value: "0")
body = .init()
}
let responseHead = HTTPResponseHead(version: version, status: self.status, headers: headers)
return .init(head: responseHead, body: body)
return .init(status: status, headers: headers, body: body)
}
}
115 changes: 31 additions & 84 deletions Sources/HummingbirdCore/Request/RequestBody.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//
// This source file is part of the Hummingbird server framework project
//
// Copyright (c) 2021-2021 the Hummingbird authors
// Copyright (c) 2023 the Hummingbird authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
Expand All @@ -12,103 +12,50 @@
//
//===----------------------------------------------------------------------===//

import AsyncAlgorithms
import NIOCore
import NIOHTTP1

/// Request Body. Either a ByteBuffer or a ByteBuffer streamer
public enum HBRequestBody: Sendable {
/// Static ByteBuffer
case byteBuffer(ByteBuffer?)
/// ByteBuffer streamer
case stream(HBByteBufferStreamer)
/// A type that represents an HTTP request body.
public struct HBRequestBody: Sendable, AsyncSequence {
public typealias Element = ByteBuffer

/// Return as ByteBuffer
public var buffer: ByteBuffer? {
switch self {
case .byteBuffer(let buffer):
return buffer
default:
preconditionFailure("Cannot get buffer on streaming RequestBody")
}
}
public struct AsyncIterator: AsyncIteratorProtocol {
public typealias Element = ByteBuffer

fileprivate var underlyingIterator: AsyncThrowingChannel<ByteBuffer, Error>.AsyncIterator

/// Return as streamer if it is a streamer
public var stream: HBStreamerProtocol? {
switch self {
case .stream(let streamer):
return streamer
case .byteBuffer(let buffer):
guard let buffer = buffer else {
return nil
}
return HBStaticStreamer(buffer)
public mutating func next() async throws -> ByteBuffer? {
try await self.underlyingIterator.next()
}
}

/// Provide body as a single ByteBuffer
/// - Parameter eventLoop: EventLoop to use
/// - Returns: EventLoopFuture that will be fulfilled with ByteBuffer. If no body is include then return `nil`
@available(*, deprecated, message: "Use the version of `consumeBody` which sets a maximum size for the resultant ByteBuffer")
public func consumeBody(on eventLoop: EventLoop) -> EventLoopFuture<ByteBuffer?> {
switch self {
case .byteBuffer(let buffer):
return eventLoop.makeSucceededFuture(buffer)
case .stream(let streamer):
return streamer.collate(maxSize: .max).hop(to: eventLoop)
}
/// HBRequestBody is internally represented by AsyncThrowingChannel
private var channel: AsyncThrowingChannel<ByteBuffer, Error>

/// Creates a new HTTP request body
public init() {
self.channel = .init()
}

/// Provide body as a single ByteBuffer
/// - Parameters
/// - maxSize: Maximum size of ByteBuffer to generate
/// - eventLoop: EventLoop to use
/// - Returns: EventLoopFuture that will be fulfilled with ByteBuffer. If no body is include then return `nil`
public func consumeBody(maxSize: Int, on eventLoop: EventLoop) -> EventLoopFuture<ByteBuffer?> {
switch self {
case .byteBuffer(let buffer):
return eventLoop.makeSucceededFuture(buffer)
case .stream(let streamer):
return streamer.collate(maxSize: maxSize).hop(to: eventLoop)
}
public func makeAsyncIterator() -> AsyncIterator {
AsyncIterator(underlyingIterator: self.channel.makeAsyncIterator())
}
}

extension HBRequestBody: CustomStringConvertible {
public var description: String {
let maxOutput = 256
switch self {
case .byteBuffer(let buffer):
guard var buffer2 = buffer else { return "empty" }
if let string = buffer2.readString(length: min(maxOutput, buffer2.readableBytes)),
string.allSatisfy(\.isASCII)
{
if buffer2.readableBytes > 0 {
return "\"\(string)...\""
} else {
return "\"\(string)\""
}
} else {
return "\(buffer!.readableBytes) bytes"
}
extension HBRequestBody {
/// push a single ByteBuffer to the HTTP request body stream
func send(_ buffer: ByteBuffer) async {
await self.channel.send(buffer)
}

case .stream:
return "byte stream"
}
/// pass error to HTTP request body
func fail(_ error: Error) {
self.channel.fail(error)
}
}

@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
extension HBRequestBody {
/// Provide body as a single ByteBuffer
/// - Parameters
/// - maxSize: Maximum size of ByteBuffer to generate
/// - eventLoop: EventLoop to use
/// - Returns: EventLoopFuture that will be fulfilled with ByteBuffer. If no body is include then return `nil`
public func consumeBody(maxSize: Int) async throws -> ByteBuffer? {
switch self {
case .byteBuffer(let buffer):
return buffer
case .stream(let streamer):
return try await streamer.collate(maxSize: maxSize).get()
}
/// Finish HTTP request body stream
func finish() {
self.channel.finish()
}
}
Loading

0 comments on commit 6a14e21

Please sign in to comment.