diff --git a/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientRequest+Prepared.swift b/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientRequest+Prepared.swift index d4eeae03e..c39452897 100644 --- a/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientRequest+Prepared.swift +++ b/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientRequest+Prepared.swift @@ -24,7 +24,7 @@ extension HTTPClientRequest { enum Body { case asyncSequence( length: RequestBodyLength, - nextBodyPart: (ByteBufferAllocator) async throws -> ByteBuffer? + makeAsyncIterator: @Sendable () -> ((ByteBufferAllocator) async throws -> ByteBuffer?) ) case sequence( length: RequestBodyLength, @@ -80,7 +80,7 @@ extension HTTPClientRequest.Prepared.Body { init(_ body: HTTPClientRequest.Body) { switch body.mode { case .asyncSequence(let length, let makeAsyncIterator): - self = .asyncSequence(length: length, nextBodyPart: makeAsyncIterator()) + self = .asyncSequence(length: length, makeAsyncIterator: makeAsyncIterator) case .sequence(let length, let canBeConsumedMultipleTimes, let makeCompleteBody): self = .sequence( length: length, diff --git a/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientRequest.swift b/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientRequest.swift index f07a2ed41..dca7de0ef 100644 --- a/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientRequest.swift +++ b/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientRequest.swift @@ -421,3 +421,9 @@ extension HTTPClientRequest.Body { } } } + +@available(*, unavailable) +extension HTTPClientRequest.Body.AsyncIterator: Sendable {} + +@available(*, unavailable) +extension HTTPClientRequest.Body.AsyncIterator.Storage: Sendable {} diff --git a/Sources/AsyncHTTPClient/AsyncAwait/Transaction.swift b/Sources/AsyncHTTPClient/AsyncAwait/Transaction.swift index b3d2b97c0..6bf8b38b7 100644 --- a/Sources/AsyncHTTPClient/AsyncAwait/Transaction.swift +++ b/Sources/AsyncHTTPClient/AsyncAwait/Transaction.swift @@ -77,9 +77,11 @@ final class Transaction: private func continueRequestBodyStream( _ allocator: ByteBufferAllocator, - next: @escaping ((ByteBufferAllocator) async throws -> ByteBuffer?) + makeAsyncIterator: @Sendable @escaping () -> ((ByteBufferAllocator) async throws -> ByteBuffer?) ) { Task { + let next = makeAsyncIterator() + do { while let part = try await next(allocator) { do { @@ -199,9 +201,9 @@ extension Transaction: HTTPExecutableRequest { case .startStream(let allocator): switch self.request.body { - case .asyncSequence(_, let next): + case .asyncSequence(_, let makeAsyncIterator): // it is safe to call this async here. it dispatches... - self.continueRequestBodyStream(allocator, next: next) + self.continueRequestBodyStream(allocator, makeAsyncIterator: makeAsyncIterator) case .byteBuffer(let byteBuffer): self.writeOnceAndOneTimeOnly(byteBuffer: byteBuffer) diff --git a/Tests/AsyncHTTPClientTests/HTTPClientRequestTests.swift b/Tests/AsyncHTTPClientTests/HTTPClientRequestTests.swift index a2cc3b108..c8c2e3b87 100644 --- a/Tests/AsyncHTTPClientTests/HTTPClientRequestTests.swift +++ b/Tests/AsyncHTTPClientTests/HTTPClientRequestTests.swift @@ -766,8 +766,9 @@ extension Optional where Wrapped == HTTPClientRequest.Prepared.Body { throw LengthMismatch(announcedLength: announcedLength, actualLength: Int64(buffer.readableBytes)) } return buffer - case .asyncSequence(length: let announcedLength, let generate): + case .asyncSequence(length: let announcedLength, let makeAsyncIterator): var accumulatedBuffer = ByteBuffer() + let generate = makeAsyncIterator() while var buffer = try await generate(ByteBufferAllocator()) { accumulatedBuffer.writeBuffer(&buffer) }