diff --git a/Sources/AsyncHTTPClient/FoundationExtensions.swift b/Sources/AsyncHTTPClient/FoundationExtensions.swift index 9ae258052..545da756b 100644 --- a/Sources/AsyncHTTPClient/FoundationExtensions.swift +++ b/Sources/AsyncHTTPClient/FoundationExtensions.swift @@ -54,3 +54,13 @@ extension HTTPClient.Cookie { ) } } + +extension HTTPClient.Body { + /// Create and stream body using `Data`. + /// + /// - parameters: + /// - bytes: Body `Data` representation. + public static func data(_ data: Data) -> HTTPClient.Body { + return self.bytes(data) + } +} diff --git a/Sources/AsyncHTTPClient/HTTPHandler.swift b/Sources/AsyncHTTPClient/HTTPHandler.swift index 3137bd145..44ce2ecf5 100644 --- a/Sources/AsyncHTTPClient/HTTPHandler.swift +++ b/Sources/AsyncHTTPClient/HTTPHandler.swift @@ -49,6 +49,12 @@ extension HTTPClient { /// Body chunk provider. public var stream: (StreamWriter) -> EventLoopFuture + @inlinable + init(length: Int?, stream: @escaping (StreamWriter) -> EventLoopFuture) { + self.length = length + self.stream = stream + } + /// Create and stream body using `ByteBuffer`. /// /// - parameters: @@ -69,13 +75,14 @@ extension HTTPClient { return Body(length: length, stream: stream) } - /// Create and stream body using `Data`. + /// Create and stream body using a collection of bytes. /// /// - parameters: - /// - data: Body `Data` representation. - public static func data(_ data: Data) -> Body { - return Body(length: data.count) { writer in - writer.write(.byteBuffer(ByteBuffer(bytes: data))) + /// - data: Body binary representation. + @inlinable + public static func bytes(_ bytes: Bytes) -> Body where Bytes: RandomAccessCollection, Bytes.Element == UInt8 { + return Body(length: bytes.count) { writer in + writer.write(.byteBuffer(ByteBuffer(bytes: bytes))) } } diff --git a/Tests/AsyncHTTPClientTests/HTTPClientTests+XCTest.swift b/Tests/AsyncHTTPClientTests/HTTPClientTests+XCTest.swift index b873833fa..7eb532cf9 100644 --- a/Tests/AsyncHTTPClientTests/HTTPClientTests+XCTest.swift +++ b/Tests/AsyncHTTPClientTests/HTTPClientTests+XCTest.swift @@ -36,6 +36,8 @@ extension HTTPClientTests { ("testGet", testGet), ("testGetWithDifferentEventLoopBackpressure", testGetWithDifferentEventLoopBackpressure), ("testPost", testPost), + ("testPostWithGenericBody", testPostWithGenericBody), + ("testPostWithFoundationDataBody", testPostWithFoundationDataBody), ("testGetHttps", testGetHttps), ("testGetHttpsWithIP", testGetHttpsWithIP), ("testGetHTTPSWorksOnMTELGWithIP", testGetHTTPSWorksOnMTELGWithIP), diff --git a/Tests/AsyncHTTPClientTests/HTTPClientTests.swift b/Tests/AsyncHTTPClientTests/HTTPClientTests.swift index baeecca33..6bb4dd9b4 100644 --- a/Tests/AsyncHTTPClientTests/HTTPClientTests.swift +++ b/Tests/AsyncHTTPClientTests/HTTPClientTests.swift @@ -296,6 +296,29 @@ class HTTPClientTests: XCTestCase { XCTAssertEqual("1234", data.data) } + func testPostWithGenericBody() throws { + let bodyData = Array("hello, world!").lazy.map { $0.uppercased().first!.asciiValue! } + let erasedData = AnyRandomAccessCollection(bodyData) + + let response = try self.defaultClient.post(url: self.defaultHTTPBinURLPrefix + "post", body: .bytes(erasedData)).wait() + let bytes = response.body.flatMap { $0.getData(at: 0, length: $0.readableBytes) } + let data = try JSONDecoder().decode(RequestInfo.self, from: bytes!) + + XCTAssertEqual(.ok, response.status) + XCTAssertEqual("HELLO, WORLD!", data.data) + } + + func testPostWithFoundationDataBody() throws { + let bodyData = Data("hello, world!".utf8) + + let response = try self.defaultClient.post(url: self.defaultHTTPBinURLPrefix + "post", body: .data(bodyData)).wait() + let bytes = response.body.flatMap { $0.getData(at: 0, length: $0.readableBytes) } + let data = try JSONDecoder().decode(RequestInfo.self, from: bytes!) + + XCTAssertEqual(.ok, response.status) + XCTAssertEqual("hello, world!", data.data) + } + func testGetHttps() throws { let localHTTPBin = HTTPBin(.http1_1(ssl: true)) let localClient = HTTPClient(eventLoopGroupProvider: .shared(self.clientGroup),