Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 1 addition & 5 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// swift-tools-version:5.10
// swift-tools-version:6.0
//===----------------------------------------------------------------------===//
//
// This source file is part of the AsyncHTTPClient open source project
Expand All @@ -19,10 +19,6 @@ let strictConcurrencyDevelopment = false

let strictConcurrencySettings: [SwiftSetting] = {
var initialSettings: [SwiftSetting] = []
initialSettings.append(contentsOf: [
.enableUpcomingFeature("StrictConcurrency"),
.enableUpcomingFeature("InferSendableFromCaptures"),
])

if strictConcurrencyDevelopment {
// -warnings-as-errors here is a workaround so that IDE-based development can
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ Please have a look at [SECURITY.md](SECURITY.md) for AsyncHTTPClient's security

## Supported Versions

The most recent versions of AsyncHTTPClient support Swift 5.10 and newer. The minimum Swift version supported by AsyncHTTPClient releases are detailed below:
The most recent versions of AsyncHTTPClient support Swift 6.0 and newer. The minimum Swift version supported by AsyncHTTPClient releases are detailed below:

AsyncHTTPClient | Minimum Swift Version
--------------------|----------------------
Expand All @@ -318,4 +318,5 @@ AsyncHTTPClient | Minimum Swift Version
`1.20.0 ..< 1.21.0` | 5.7
`1.21.0 ..< 1.26.0` | 5.8
`1.26.0 ..< 1.27.0` | 5.9
`1.27.0 ...` | 5.10
`1.27.0 ..< 1.30.0` | 5.10
`1.30.0 ...` | 6.0
4 changes: 2 additions & 2 deletions Sources/AsyncHTTPClient/DeconstructedURL.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ extension DeconstructedURL {

switch scheme {
case .http, .https:
#if !canImport(Darwin) && compiler(>=6.0)
#if !canImport(Darwin)
guard let urlHost = url.host, !urlHost.isEmpty else {
throw HTTPClientError.emptyHost
}
Expand Down Expand Up @@ -89,7 +89,7 @@ extension DeconstructedURL {
}
}

#if !canImport(Darwin) && compiler(>=6.0)
#if !canImport(Darwin)
extension String {
@inlinable internal func trimIPv6Brackets() -> String {
var utf8View = self.utf8[...]
Expand Down
27 changes: 0 additions & 27 deletions Sources/AsyncHTTPClient/HTTPClient+StructuredConcurrency.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import NIO

@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
extension HTTPClient {
#if compiler(>=6.0)
/// Start & automatically shut down a new ``HTTPClient``.
///
/// This method allows to start & automatically dispose of a ``HTTPClient`` following the principle of Structured Concurrency.
Expand All @@ -43,30 +42,4 @@ extension HTTPClient {
try await httpClient.shutdown()
}
}
#else
/// Start & automatically shut down a new ``HTTPClient``.
///
/// This method allows to start & automatically dispose of a ``HTTPClient`` following the principle of Structured Concurrency.
/// The ``HTTPClient`` is guaranteed to be shut down upon return, whether `body` throws or not.
///
/// This may be particularly useful if you cannot use the shared singleton (``HTTPClient/shared``).
public static func withHTTPClient<Return: Sendable>(
eventLoopGroup: any EventLoopGroup = HTTPClient.defaultEventLoopGroup,
configuration: Configuration = Configuration(),
backgroundActivityLogger: Logger? = nil,
_ body: (HTTPClient) async throws -> Return
) async throws -> Return {
let logger = (backgroundActivityLogger ?? HTTPClient.loggingDisabled)
let httpClient = HTTPClient(
eventLoopGroup: eventLoopGroup,
configuration: configuration,
backgroundActivityLogger: logger
)
return try await asyncDo {
try await body(httpClient)
} finally: { _ in
try await httpClient.shutdown()
}
}
#endif
}
7 changes: 1 addition & 6 deletions Sources/AsyncHTTPClient/HTTPHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//

import Algorithms
import Foundation
import Logging
import NIOConcurrencyHelpers
import NIOCore
Expand All @@ -21,12 +22,6 @@ import NIOPosix
import NIOSSL
import Tracing

#if compiler(>=6.0)
import Foundation
#else
@preconcurrency import Foundation
#endif

extension HTTPClient {
/// A request body.
public struct Body: Sendable {
Expand Down
40 changes: 3 additions & 37 deletions Sources/AsyncHTTPClient/StructuredConcurrencyHelpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,13 @@
// Note: Whitespace changes are used to workaround compiler bug
// https://github.com/swiftlang/swift/issues/79285

#if compiler(>=6.0)
@inlinable
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
internal func asyncDo<R>(
isolation: isolated (any Actor)? = #isolation,
// DO NOT FIX THE WHITESPACE IN THE NEXT LINE UNTIL 5.10 IS UNSUPPORTED
// https://github.com/swiftlang/swift/issues/79285
_ body: () async throws -> sending R, finally: sending @escaping ((any Error)?) async throws -> Void) async throws -> sending R {
_ body: () async throws -> sending R,
finally: sending @escaping ((any Error)?) async throws -> Void
) async throws -> sending R {
let result: R
do {
result = try await body()
Expand All @@ -48,36 +47,3 @@ internal func asyncDo<R>(
}.value
return result
}
#else
@inlinable
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
internal func asyncDo<R: Sendable>(
_ body: () async throws -> R,
finally: @escaping @Sendable ((any Error)?) async throws -> Void
) async throws -> R {
let result: R
do {
result = try await body()
} catch {
// `body` failed, we need to invoke `finally` with the `error`.

// This _looks_ unstructured but isn't really because we unconditionally always await the return.
// We need to have an uncancelled task here to assure this is actually running in case we hit a
// cancellation error.
try await Task {
try await finally(error)
}.value
throw error
}

// `body` succeeded, we need to invoke `finally` with `nil` (no error).

// This _looks_ unstructured but isn't really because we unconditionally always await the return.
// We need to have an uncancelled task here to assure this is actually running in case we hit a
// cancellation error.
try await Task {
try await finally(nil)
}.value
return result
}
#endif
2 changes: 1 addition & 1 deletion Tests/AsyncHTTPClientTests/HTTPClientTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ final class HTTPClientTests: XCTestCaseHTTPClientTestsBaseClass {

let request3 = try Request(url: "unix:///tmp/file")
XCTAssertEqual(request3.host, "")
#if os(Linux) && compiler(>=6.0) && compiler(<6.1)
#if os(Linux) && compiler(<6.1)
XCTAssertEqual(request3.url.host, "")
#else
XCTAssertNil(request3.url.host)
Expand Down
37 changes: 0 additions & 37 deletions Tests/AsyncHTTPClientTests/TransactionTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -657,7 +657,6 @@ private actor Promise<Value: Sendable> {

@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
extension Transaction {
#if compiler(>=6.0)
fileprivate static func makeWithResultTask(
request: sending PreparedRequest,
requestOptions: RequestOptions = .forTests(),
Expand Down Expand Up @@ -685,40 +684,4 @@ extension Transaction {

return (await transactionPromise.value, task)
}
#else
fileprivate static func makeWithResultTask(
request: PreparedRequest,
requestOptions: RequestOptions = .forTests(),
logger: Logger = Logger(label: "test"),
connectionDeadline: NIODeadline = .distantFuture,
preferredEventLoop: EventLoop
) async -> (Transaction, _Concurrency.Task<HTTPClientResponse, Error>) {
// It isn't sendable ... but on 6.0 and later we use 'sending'.
struct UnsafePrepareRequest: @unchecked Sendable {
var value: PreparedRequest
}

let transactionPromise = Promise<Transaction>()
let unsafe = UnsafePrepareRequest(value: request)
let task = Task {
try await withCheckedThrowingContinuation {
(continuation: CheckedContinuation<HTTPClientResponse, Error>) in
let request = unsafe.value
let transaction = Transaction(
request: request,
requestOptions: requestOptions,
logger: logger,
connectionDeadline: connectionDeadline,
preferredEventLoop: preferredEventLoop,
responseContinuation: continuation
)
Task {
await transactionPromise.fulfil(transaction)
}
}
}

return (await transactionPromise.value, task)
}
#endif
}