diff --git a/Package@swift-6.1.swift b/Package@swift-6.1.swift deleted file mode 100644 index eb896f89b..000000000 --- a/Package@swift-6.1.swift +++ /dev/null @@ -1,124 +0,0 @@ -// swift-tools-version:6.1 -//===----------------------------------------------------------------------===// -// -// This source file is part of the AsyncHTTPClient open source project -// -// Copyright (c) 2018-2019 Apple Inc. and the AsyncHTTPClient project authors -// Licensed under Apache License v2.0 -// -// See LICENSE.txt for license information -// See CONTRIBUTORS.txt for the list of AsyncHTTPClient project authors -// -// SPDX-License-Identifier: Apache-2.0 -// -//===----------------------------------------------------------------------===// - -import PackageDescription - -let strictConcurrencyDevelopment = false - -let strictConcurrencySettings: [SwiftSetting] = { - var initialSettings: [SwiftSetting] = [] - - if strictConcurrencyDevelopment { - // -warnings-as-errors here is a workaround so that IDE-based development can - // get tripped up on -require-explicit-sendable. - initialSettings.append(.unsafeFlags(["-Xfrontend", "-require-explicit-sendable", "-warnings-as-errors"])) - } - - return initialSettings -}() - -let package = Package( - name: "async-http-client", - products: [ - .library(name: "AsyncHTTPClient", targets: ["AsyncHTTPClient"]) - ], - dependencies: [ - .package(url: "https://github.com/apple/swift-nio.git", from: "2.100.0"), - .package(url: "https://github.com/apple/swift-nio-ssl.git", from: "2.30.0"), - .package(url: "https://github.com/apple/swift-nio-http2.git", from: "1.36.0"), - .package(url: "https://github.com/apple/swift-nio-extras.git", from: "1.26.0"), - .package(url: "https://github.com/apple/swift-nio-transport-services.git", from: "1.24.0"), - .package(url: "https://github.com/apple/swift-log.git", from: "1.7.1"), - .package(url: "https://github.com/apple/swift-atomics.git", from: "1.0.2"), - .package(url: "https://github.com/apple/swift-algorithms.git", from: "1.0.0"), - .package(url: "https://github.com/apple/swift-distributed-tracing.git", from: "1.3.0"), - ], - targets: [ - .target( - name: "CAsyncHTTPClient", - cSettings: [ - .define("_GNU_SOURCE") - ] - ), - .target( - name: "AsyncHTTPClient", - dependencies: [ - .target(name: "CAsyncHTTPClient"), - .product(name: "NIO", package: "swift-nio"), - .product(name: "NIOTLS", package: "swift-nio"), - .product(name: "NIOCore", package: "swift-nio"), - .product(name: "NIOPosix", package: "swift-nio"), - .product(name: "NIOHTTP1", package: "swift-nio"), - .product(name: "NIOConcurrencyHelpers", package: "swift-nio"), - .product(name: "NIOHTTP2", package: "swift-nio-http2"), - .product(name: "NIOSSL", package: "swift-nio-ssl"), - .product(name: "NIOHTTPCompression", package: "swift-nio-extras"), - .product(name: "NIOSOCKS", package: "swift-nio-extras"), - .product(name: "NIOTransportServices", package: "swift-nio-transport-services"), - .product(name: "Atomics", package: "swift-atomics"), - .product(name: "Algorithms", package: "swift-algorithms"), - // Observability support - .product(name: "Logging", package: "swift-log"), - .product(name: "Tracing", package: "swift-distributed-tracing"), - ], - swiftSettings: strictConcurrencySettings - ), - .testTarget( - name: "AsyncHTTPClientTests", - dependencies: [ - .target(name: "AsyncHTTPClient"), - .product(name: "NIOTLS", package: "swift-nio"), - .product(name: "NIOCore", package: "swift-nio"), - .product(name: "NIOConcurrencyHelpers", package: "swift-nio"), - .product(name: "NIOEmbedded", package: "swift-nio"), - .product(name: "NIOFoundationCompat", package: "swift-nio"), - .product(name: "NIOTestUtils", package: "swift-nio"), - .product(name: "NIOSSL", package: "swift-nio-ssl"), - .product(name: "NIOHTTP2", package: "swift-nio-http2"), - .product(name: "NIOSOCKS", package: "swift-nio-extras"), - .product(name: "Atomics", package: "swift-atomics"), - .product(name: "Algorithms", package: "swift-algorithms"), - // Observability support - .product(name: "Logging", package: "swift-log"), - .product(name: "InMemoryLogging", package: "swift-log"), - .product(name: "Tracing", package: "swift-distributed-tracing"), - .product(name: "InMemoryTracing", package: "swift-distributed-tracing"), - ], - resources: [ - .copy("Resources/self_signed_cert.pem"), - .copy("Resources/self_signed_key.pem"), - .copy("Resources/example.com.cert.pem"), - .copy("Resources/example.com.private-key.pem"), - ], - swiftSettings: strictConcurrencySettings - ), - ] -) - -// --- STANDARD CROSS-REPO SETTINGS DO NOT EDIT --- // -for target in package.targets { - switch target.type { - case .regular, .test, .executable: - var settings = target.swiftSettings ?? [] - // https://github.com/swiftlang/swift-evolution/blob/main/proposals/0444-member-import-visibility.md - settings.append(.enableUpcomingFeature("MemberImportVisibility")) - target.swiftSettings = settings - case .macro, .plugin, .system, .binary: - () // not applicable - @unknown default: - () // we don't know what to do here, do nothing - } -} -// --- END: STANDARD CROSS-REPO SETTINGS DO NOT EDIT --- // diff --git a/README.md b/README.md index eab0173f7..428608242 100644 --- a/README.md +++ b/README.md @@ -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 6.1 and newer. The minimum Swift version supported by AsyncHTTPClient releases are detailed below: +The most recent versions of AsyncHTTPClient support Swift 6.2 and newer. The minimum Swift version supported by AsyncHTTPClient releases are detailed below: AsyncHTTPClient | Minimum Swift Version --------------------|---------------------- @@ -320,4 +320,5 @@ AsyncHTTPClient | Minimum Swift Version `1.26.0 ..< 1.27.0` | 5.9 `1.27.0 ..< 1.30.0` | 5.10 `1.30.0 ..< 1.34.0` | 6.0 -`1.34.0 ...` | 6.1 +`1.34.0 ..< 1.36.2` | 6.1 +`1.37.0 ...` | 6.2 diff --git a/Sources/AsyncHTTPClient/ConnectionPool/HTTPRequestStateMachine.swift b/Sources/AsyncHTTPClient/ConnectionPool/HTTPRequestStateMachine.swift index cef736063..0dd90f2de 100644 --- a/Sources/AsyncHTTPClient/ConnectionPool/HTTPRequestStateMachine.swift +++ b/Sources/AsyncHTTPClient/ConnectionPool/HTTPRequestStateMachine.swift @@ -376,8 +376,6 @@ struct HTTPRequestStateMachine { .streaming(let expectedBodyLength, let sentBodyBytes, _), .receivingBody(let head, let streamState) ): - assert(head.status.code < 300) - if let expected = expectedBodyLength, expected != sentBodyBytes { let error = HTTPClientError.bodyLengthMismatch self.state = .failed(error) diff --git a/Sources/AsyncHTTPClient/HTTPClientConfiguration+SwiftConfiguration.swift b/Sources/AsyncHTTPClient/HTTPClientConfiguration+SwiftConfiguration.swift index 9430689e9..f56b00a58 100644 --- a/Sources/AsyncHTTPClient/HTTPClientConfiguration+SwiftConfiguration.swift +++ b/Sources/AsyncHTTPClient/HTTPClientConfiguration+SwiftConfiguration.swift @@ -12,7 +12,6 @@ // //===----------------------------------------------------------------------===// -#if compiler(>=6.2) import Configuration import NIOCore import NIOHTTP1 @@ -272,4 +271,3 @@ extension HTTPClient.Authorization { } } } -#endif diff --git a/Tests/AsyncHTTPClientTests/BidirectionalStreamingTests.swift b/Tests/AsyncHTTPClientTests/BidirectionalStreamingTests.swift index 68adda983..0495fc412 100644 --- a/Tests/AsyncHTTPClientTests/BidirectionalStreamingTests.swift +++ b/Tests/AsyncHTTPClientTests/BidirectionalStreamingTests.swift @@ -69,7 +69,7 @@ struct BidirectionalStreamingTests { } } -final class HTTPRequestStreamingChannel: ChannelInboundHandler & AHCTestSendableMetatype { +final class HTTPRequestStreamingChannel: ChannelInboundHandler & SendableMetatype { typealias InboundIn = HTTPServerRequestPart typealias OutboundOut = HTTPServerResponsePart diff --git a/Tests/AsyncHTTPClientTests/HTTPClientTestUtils.swift b/Tests/AsyncHTTPClientTests/HTTPClientTestUtils.swift index 36cc9aec7..54c4bba9a 100644 --- a/Tests/AsyncHTTPClientTests/HTTPClientTestUtils.swift +++ b/Tests/AsyncHTTPClientTests/HTTPClientTestUtils.swift @@ -364,13 +364,7 @@ enum TestTLS { ) } -#if compiler(>=6.2) -typealias AHCTestSendableMetatype = SendableMetatype -#else -typealias AHCTestSendableMetatype = Any -#endif - -internal final class HTTPBin: Sendable +internal final class HTTPBin: Sendable where RequestHandler.InboundIn == HTTPServerRequestPart, RequestHandler.OutboundOut == HTTPServerResponsePart diff --git a/Tests/AsyncHTTPClientTests/HTTPRequestStateMachineTests.swift b/Tests/AsyncHTTPClientTests/HTTPRequestStateMachineTests.swift index b4845005c..ad08c7a44 100644 --- a/Tests/AsyncHTTPClientTests/HTTPRequestStateMachineTests.swift +++ b/Tests/AsyncHTTPClientTests/HTTPRequestStateMachineTests.swift @@ -325,6 +325,42 @@ class HTTPRequestStateMachineTests: XCTestCase { XCTAssertEqual(state.channelRead(.end(nil)), .forwardResponseEnd(.requestDone, [], nil)) } + func testRequestBodyStreamFinishedAfterServerSentHeadWithStatus413() { + var state = HTTPRequestStateMachine(isChannelWritable: true) + let requestHead = HTTPRequestHead(version: .http1_1, method: .POST, uri: "/") + let metadata = RequestFramingMetadata(connectionClose: false, body: .stream) + XCTAssertEqual( + state.startRequest(head: requestHead, metadata: metadata), + .sendRequestHead(requestHead, sendEnd: false) + ) + // Promotes the producer to `.producing`, as the real pipeline does once the head is out. + XCTAssertEqual( + state.headSent(), + .notifyRequestHeadSendSuccessfully(resumeRequestBodyStream: true, startIdleTimer: false) + ) + + // One part is on the wire and the stream is still open. + let part0 = IOData.byteBuffer(ByteBuffer(bytes: 0...3)) + XCTAssertEqual(state.requestStreamPartReceived(part0, promise: nil), .sendBodyPart(part0, nil)) + + // The server rejects the upload without reading the rest of it. The state machine takes + // this in stride and asks us to pause the body stream. + let responseHead = HTTPResponseHead(version: .http1_1, status: .payloadTooLarge) + XCTAssertEqual( + state.channelRead(.head(responseHead)), + .forwardResponseHead(responseHead, pauseRequestBodyStream: true) + ) + + // Pausing is not cancelling, so the producer may still finish. This is the trap: the + // action below is the correct one, and the assert crashes before it can be returned. + XCTAssertEqual( + state.requestStreamFinished(trailers: nil, promise: nil), + .sendRequestEnd(trailers: nil, nil, .none) + ) + + XCTAssertEqual(state.channelRead(.end(nil)), .forwardResponseEnd(.requestDone, [], nil)) + } + func testRequestIsFailedIfRequestBodySizeIsWrongEvenAfterServerRespondedWith200() { var state = HTTPRequestStateMachine(isChannelWritable: true) let requestHead = HTTPRequestHead( diff --git a/Tests/AsyncHTTPClientTests/SwiftConfigurationTests.swift b/Tests/AsyncHTTPClientTests/SwiftConfigurationTests.swift index f2f1f8a98..14c33a665 100644 --- a/Tests/AsyncHTTPClientTests/SwiftConfigurationTests.swift +++ b/Tests/AsyncHTTPClientTests/SwiftConfigurationTests.swift @@ -12,7 +12,6 @@ // //===----------------------------------------------------------------------===// -#if compiler(>=6.2) import Configuration import Foundation import NIOCore @@ -575,4 +574,3 @@ struct HTTPClientConfigurationPropsTests { } } } -#endif