From 4dcfa46d35bff127ede56087fe284942fb26b9e9 Mon Sep 17 00:00:00 2001 From: Aryan Shah Date: Tue, 2 Jul 2024 11:01:31 +0100 Subject: [PATCH 1/2] Resolve ambiguity issue of `stream` by removing the default value for length. Change type for length from `Int64?` to enum-backed type. --- Sources/AsyncHTTPClient/HTTPHandler.swift | 60 +++++++++++++------ .../HTTP1ClientChannelHandlerTests.swift | 10 ++-- .../HTTP1ConnectionTests.swift | 2 +- .../HTTP2ClientRequestHandlerTests.swift | 8 +-- .../HTTP2ClientTests.swift | 4 +- .../HTTPClientInternalTests.swift | 10 ++-- .../HTTPClientTests.swift | 57 +++++++++--------- .../NoBytesSentOverBodyLimitTests.swift | 2 +- .../RequestBagTests.swift | 10 ++-- 9 files changed, 95 insertions(+), 68 deletions(-) diff --git a/Sources/AsyncHTTPClient/HTTPHandler.swift b/Sources/AsyncHTTPClient/HTTPHandler.swift index c8a485023..90d7bd774 100644 --- a/Sources/AsyncHTTPClient/HTTPHandler.swift +++ b/Sources/AsyncHTTPClient/HTTPHandler.swift @@ -68,21 +68,43 @@ extension HTTPClient { } } + public struct Length: Hashable, Sendable { + @usableFromInline + let length: RequestBodyLength + + private init(_ length: RequestBodyLength) { + self.length = length + } + + public static let unknown = Length(.unknown) + + public static func known(_ length: Int64) -> Length { + return Length(.known(length)) + } + } + /// Body size. If nil,`Transfer-Encoding` will automatically be set to `chunked`. Otherwise a `Content-Length` /// header is set with the given `length`. @available(*, deprecated, renamed: "contentLength") public var length: Int? { get { - self.contentLength.flatMap { Int($0) } + if case let .known(count) = self.contentLength.length { + return Int(count) + } + return nil } set { - self.contentLength = newValue.flatMap { Int64($0) } + if let newValue = newValue { + self.contentLength = Length.known(Int64(newValue)) + } else { + self.contentLength = Length.unknown + } } } /// Body size. If nil,`Transfer-Encoding` will automatically be set to `chunked`. Otherwise a `Content-Length` /// header is set with the given `contentLength`. - public var contentLength: Int64? + public var contentLength: Length /// Body chunk provider. public var stream: @Sendable (StreamWriter) -> EventLoopFuture @@ -90,8 +112,8 @@ extension HTTPClient { @usableFromInline typealias StreamCallback = @Sendable (StreamWriter) -> EventLoopFuture @inlinable - init(contentLength: Int64?, stream: @escaping StreamCallback) { - self.contentLength = contentLength.flatMap { $0 } + init(contentLength: Length, stream: @escaping StreamCallback) { + self.contentLength = contentLength self.stream = stream } @@ -100,7 +122,7 @@ extension HTTPClient { /// - parameters: /// - buffer: Body `ByteBuffer` representation. public static func byteBuffer(_ buffer: ByteBuffer) -> Body { - return Body(contentLength: Int64(buffer.readableBytes)) { writer in + return Body(contentLength: .known(Int64(buffer.readableBytes))) { writer in writer.write(.byteBuffer(buffer)) } } @@ -114,17 +136,23 @@ extension HTTPClient { @preconcurrency @available(*, deprecated, renamed: "stream(contentLength:bodyStream:)") public static func stream(length: Int? = nil, _ stream: @Sendable @escaping (StreamWriter) -> EventLoopFuture) -> Body { - return Body(contentLength: length.flatMap { Int64($0) }, stream: stream) + let contentLength: Length + if let length = length { + contentLength = .known(Int64(length)) + } else { + contentLength = .unknown + } + return Body(contentLength: contentLength, stream: stream) } /// Create and stream body using ``StreamWriter``. /// /// - parameters: - /// - contentLength: Body size. If nil, `Transfer-Encoding` will automatically be set to `chunked`. Otherwise a `Content-Length` + /// - length: Body size. If nil, `Transfer-Encoding` will automatically be set to `chunked`. Otherwise a `Content-Length` /// header is set with the given `contentLength`. - /// - bodyStream: Body chunk provider. - public static func stream(contentLength: Int64? = nil, bodyStream: @Sendable @escaping (StreamWriter) -> EventLoopFuture) -> Body { - return Body(contentLength: contentLength, stream: bodyStream) + /// - stream: Body chunk provider. + public static func stream(length: Length, _ stream: @Sendable @escaping (StreamWriter) -> EventLoopFuture) -> Body { + return Body(contentLength: length, stream: stream) } /// Create and stream body using a collection of bytes. @@ -134,7 +162,7 @@ extension HTTPClient { @preconcurrency @inlinable public static func bytes(_ bytes: Bytes) -> Body where Bytes: RandomAccessCollection, Bytes: Sendable, Bytes.Element == UInt8 { - return Body(contentLength: Int64(bytes.count)) { writer in + return Body(contentLength: .known(Int64(bytes.count))) { writer in if bytes.count <= bagOfBytesToByteBufferConversionChunkSize { return writer.write(.byteBuffer(ByteBuffer(bytes: bytes))) } else { @@ -148,7 +176,7 @@ extension HTTPClient { /// - parameters: /// - string: Body `String` representation. public static func string(_ string: String) -> Body { - return Body(contentLength: Int64(string.utf8.count)) { writer in + return Body(contentLength: .known(Int64(string.utf8.count))) { writer in if string.utf8.count <= bagOfBytesToByteBufferConversionChunkSize { return writer.write(.byteBuffer(ByteBuffer(string: string))) } else { @@ -881,10 +909,6 @@ extension RequestBodyLength { self = .known(0) return } - guard let length = body.contentLength else { - self = .unknown - return - } - self = .known(length) + self = body.contentLength.length } } diff --git a/Tests/AsyncHTTPClientTests/HTTP1ClientChannelHandlerTests.swift b/Tests/AsyncHTTPClientTests/HTTP1ClientChannelHandlerTests.swift index f4f2d67f8..6968bb500 100644 --- a/Tests/AsyncHTTPClientTests/HTTP1ClientChannelHandlerTests.swift +++ b/Tests/AsyncHTTPClientTests/HTTP1ClientChannelHandlerTests.swift @@ -113,7 +113,7 @@ class HTTP1ClientChannelHandlerTests: XCTestCase { guard let testUtils = maybeTestUtils else { return XCTFail("Expected connection setup works") } var maybeRequest: HTTPClient.Request? - XCTAssertNoThrow(maybeRequest = try HTTPClient.Request(url: "http://localhost/", method: .POST, body: .stream(contentLength: 100) { writer in + XCTAssertNoThrow(maybeRequest = try HTTPClient.Request(url: "http://localhost/", method: .POST, body: .stream(length: .known(100)) { writer in testWriter.start(writer: writer) })) guard let request = maybeRequest else { return XCTFail("Expected to be able to create a request") } @@ -345,7 +345,7 @@ class HTTP1ClientChannelHandlerTests: XCTestCase { guard let testUtils = maybeTestUtils else { return XCTFail("Expected connection setup works") } var maybeRequest: HTTPClient.Request? - XCTAssertNoThrow(maybeRequest = try HTTPClient.Request(url: "http://localhost/", method: .POST, body: .stream(contentLength: 10) { writer in + XCTAssertNoThrow(maybeRequest = try HTTPClient.Request(url: "http://localhost/", method: .POST, body: .stream(length: .known(10)) { writer in // Advance time by more than the idle write timeout (that's 1 millisecond) to trigger the timeout. embedded.embeddedEventLoop.advanceTime(by: .milliseconds(2)) return testWriter.start(writer: writer) @@ -384,7 +384,7 @@ class HTTP1ClientChannelHandlerTests: XCTestCase { guard let testUtils = maybeTestUtils else { return XCTFail("Expected connection setup works") } var maybeRequest: HTTPClient.Request? - XCTAssertNoThrow(maybeRequest = try HTTPClient.Request(url: "http://localhost/", method: .POST, body: .stream(contentLength: 10) { writer in + XCTAssertNoThrow(maybeRequest = try HTTPClient.Request(url: "http://localhost/", method: .POST, body: .stream(length: .known(10)) { writer in embedded.isWritable = false embedded.pipeline.fireChannelWritabilityChanged() // This should not trigger any errors or timeouts, because the timer isn't running @@ -432,7 +432,7 @@ class HTTP1ClientChannelHandlerTests: XCTestCase { guard let testUtils = maybeTestUtils else { return XCTFail("Expected connection setup works") } var maybeRequest: HTTPClient.Request? - XCTAssertNoThrow(maybeRequest = try HTTPClient.Request(url: "http://localhost/", method: .POST, body: .stream(contentLength: 2) { writer in + XCTAssertNoThrow(maybeRequest = try HTTPClient.Request(url: "http://localhost/", method: .POST, body: .stream(length: .known(2)) { writer in return testWriter.start(writer: writer, expectedErrors: [HTTPClientError.cancelled]) })) guard let request = maybeRequest else { return XCTFail("Expected to be able to create a request") } @@ -595,7 +595,7 @@ class HTTP1ClientChannelHandlerTests: XCTestCase { guard let testUtils = maybeTestUtils else { return XCTFail("Expected connection setup works") } var maybeRequest: HTTPClient.Request? - XCTAssertNoThrow(maybeRequest = try HTTPClient.Request(url: "http://localhost/", method: .POST, body: .stream(contentLength: 10) { writer in + XCTAssertNoThrow(maybeRequest = try HTTPClient.Request(url: "http://localhost/", method: .POST, body: .stream(length: .known(10)) { writer in testWriter.start(writer: writer) })) guard let request = maybeRequest else { return XCTFail("Expected to be able to create a request") } diff --git a/Tests/AsyncHTTPClientTests/HTTP1ConnectionTests.swift b/Tests/AsyncHTTPClientTests/HTTP1ConnectionTests.swift index 5ea8bb77c..135e00359 100644 --- a/Tests/AsyncHTTPClientTests/HTTP1ConnectionTests.swift +++ b/Tests/AsyncHTTPClientTests/HTTP1ConnectionTests.swift @@ -116,7 +116,7 @@ class HTTP1ConnectionTests: XCTestCase { XCTAssertNoThrow(maybeRequest = try HTTPClient.Request( url: "http://localhost/hello/swift", method: .POST, - body: .stream(contentLength: 4) { writer -> EventLoopFuture in + body: .stream(length: .known(4)) { writer -> EventLoopFuture in @Sendable func recursive(count: UInt8, promise: EventLoopPromise) { guard count < 4 else { return promise.succeed(()) diff --git a/Tests/AsyncHTTPClientTests/HTTP2ClientRequestHandlerTests.swift b/Tests/AsyncHTTPClientTests/HTTP2ClientRequestHandlerTests.swift index 2428199a4..ecb1120bd 100644 --- a/Tests/AsyncHTTPClientTests/HTTP2ClientRequestHandlerTests.swift +++ b/Tests/AsyncHTTPClientTests/HTTP2ClientRequestHandlerTests.swift @@ -115,7 +115,7 @@ class HTTP2ClientRequestHandlerTests: XCTestCase { let testWriter = TestBackpressureWriter(eventLoop: embedded.eventLoop, parts: 50) var maybeRequest: HTTPClient.Request? - XCTAssertNoThrow(maybeRequest = try HTTPClient.Request(url: "http://localhost/", method: .POST, body: .stream(contentLength: 100) { writer in + XCTAssertNoThrow(maybeRequest = try HTTPClient.Request(url: "http://localhost/", method: .POST, body: .stream(length: .known(100)) { writer in testWriter.start(writer: writer) })) guard let request = maybeRequest else { return XCTFail("Expected to be able to create a request") } @@ -295,7 +295,7 @@ class HTTP2ClientRequestHandlerTests: XCTestCase { let testWriter = TestBackpressureWriter(eventLoop: embedded.eventLoop, parts: 5) var maybeRequest: HTTPClient.Request? - XCTAssertNoThrow(maybeRequest = try HTTPClient.Request(url: "http://localhost/", method: .POST, body: .stream(contentLength: 10) { writer in + XCTAssertNoThrow(maybeRequest = try HTTPClient.Request(url: "http://localhost/", method: .POST, body: .stream(length: .known(10)) { writer in // Advance time by more than the idle write timeout (that's 1 millisecond) to trigger the timeout. embedded.embeddedEventLoop.advanceTime(by: .milliseconds(2)) return testWriter.start(writer: writer) @@ -335,7 +335,7 @@ class HTTP2ClientRequestHandlerTests: XCTestCase { let testWriter = TestBackpressureWriter(eventLoop: embedded.eventLoop, parts: 5) var maybeRequest: HTTPClient.Request? - XCTAssertNoThrow(maybeRequest = try HTTPClient.Request(url: "http://localhost/", method: .POST, body: .stream(contentLength: 10) { writer in + XCTAssertNoThrow(maybeRequest = try HTTPClient.Request(url: "http://localhost/", method: .POST, body: .stream(length: .known(10)) { writer in embedded.isWritable = false embedded.pipeline.fireChannelWritabilityChanged() // This should not trigger any errors or timeouts, because the timer isn't running @@ -385,7 +385,7 @@ class HTTP2ClientRequestHandlerTests: XCTestCase { let testWriter = TestBackpressureWriter(eventLoop: embedded.eventLoop, parts: 5) var maybeRequest: HTTPClient.Request? - XCTAssertNoThrow(maybeRequest = try HTTPClient.Request(url: "http://localhost/", method: .POST, body: .stream(contentLength: 2) { writer in + XCTAssertNoThrow(maybeRequest = try HTTPClient.Request(url: "http://localhost/", method: .POST, body: .stream(length: .known(2)) { writer in return testWriter.start(writer: writer, expectedErrors: [HTTPClientError.cancelled]) })) guard let request = maybeRequest else { return XCTFail("Expected to be able to create a request") } diff --git a/Tests/AsyncHTTPClientTests/HTTP2ClientTests.swift b/Tests/AsyncHTTPClientTests/HTTP2ClientTests.swift index 889cd38b9..00f05699c 100644 --- a/Tests/AsyncHTTPClientTests/HTTP2ClientTests.swift +++ b/Tests/AsyncHTTPClientTests/HTTP2ClientTests.swift @@ -68,7 +68,7 @@ class HTTP2ClientTests: XCTestCase { let client = self.makeDefaultHTTPClient() defer { XCTAssertNoThrow(try client.syncShutdown()) } var response: HTTPClient.Response? - let body = HTTPClient.Body.stream(contentLength: nil) { writer in + let body = HTTPClient.Body.stream(length: .unknown) { writer in writer.write(.byteBuffer(ByteBuffer(integer: UInt64(0)))).flatMap { writer.write(.byteBuffer(ByteBuffer(integer: UInt64(0)))) } @@ -84,7 +84,7 @@ class HTTP2ClientTests: XCTestCase { defer { XCTAssertNoThrow(try bin.shutdown()) } let client = self.makeDefaultHTTPClient() defer { XCTAssertNoThrow(try client.syncShutdown()) } - let body = HTTPClient.Body.stream(contentLength: 12) { writer in + let body = HTTPClient.Body.stream(length: .known(12)) { writer in writer.write(.byteBuffer(ByteBuffer(integer: UInt64(0)))).flatMap { writer.write(.byteBuffer(ByteBuffer(integer: UInt64(0)))) } diff --git a/Tests/AsyncHTTPClientTests/HTTPClientInternalTests.swift b/Tests/AsyncHTTPClientTests/HTTPClientInternalTests.swift index 80446251c..3ef81986b 100644 --- a/Tests/AsyncHTTPClientTests/HTTPClientInternalTests.swift +++ b/Tests/AsyncHTTPClientTests/HTTPClientInternalTests.swift @@ -52,7 +52,7 @@ class HTTPClientInternalTests: XCTestCase { XCTAssertNoThrow(try httpBin.shutdown()) } - let body: HTTPClient.Body = .stream(contentLength: 50) { writer in + let body: HTTPClient.Body = .stream(length: .known(50)) { writer in do { var request = try Request(url: "http://localhost:\(httpBin.port)/events/10/1") request.headers.add(name: "Accept", value: "text/event-stream") @@ -81,13 +81,13 @@ class HTTPClientInternalTests: XCTestCase { XCTAssertNoThrow(try httpBin.shutdown()) } - var body: HTTPClient.Body = .stream(contentLength: 50) { _ in + var body: HTTPClient.Body = .stream(length: .known(50)) { _ in httpClient.eventLoopGroup.next().makeFailedFuture(HTTPClientError.invalidProxyResponse) } XCTAssertThrowsError(try httpClient.post(url: "http://localhost:\(httpBin.port)/post", body: body).wait()) - body = .stream(contentLength: 50) { _ in + body = .stream(length: .known(50)) { _ in do { var request = try Request(url: "http://localhost:\(httpBin.port)/events/10/1") request.headers.add(name: "Accept", value: "text/event-stream") @@ -223,7 +223,7 @@ class HTTPClientInternalTests: XCTestCase { XCTAssertNoThrow(try httpClient.syncShutdown(requiresCleanClose: true)) } - let body: HTTPClient.Body = .stream(contentLength: 8) { writer in + let body: HTTPClient.Body = .stream(length: .known(8)) { writer in let buffer = ByteBuffer(string: "1234") return writer.write(.byteBuffer(buffer)).flatMap { let buffer = ByteBuffer(string: "4321") @@ -366,7 +366,7 @@ class HTTPClientInternalTests: XCTestCase { let el2 = group.next() XCTAssert(el1 !== el2) - let body: HTTPClient.Body = .stream(contentLength: 8) { writer in + let body: HTTPClient.Body = .stream(length: .known(8)) { writer in XCTAssert(el1.inEventLoop) let buffer = ByteBuffer(string: "1234") return writer.write(.byteBuffer(buffer)).flatMap { diff --git a/Tests/AsyncHTTPClientTests/HTTPClientTests.swift b/Tests/AsyncHTTPClientTests/HTTPClientTests.swift index 51bc1f005..8298deb45 100644 --- a/Tests/AsyncHTTPClientTests/HTTPClientTests.swift +++ b/Tests/AsyncHTTPClientTests/HTTPClientTests.swift @@ -621,7 +621,7 @@ final class HTTPClientTests: XCTestCaseHTTPClientTestsBaseClass { let request = try HTTPClient.Request(url: self.defaultHTTPBinURLPrefix + "post", method: .POST, headers: ["transfer-encoding": "chunked"], - body: .stream(bodyStream: { streamWriter in + body: .stream(length: .unknown) { streamWriter in _ = streamWriter.write(.byteBuffer(.init())) let promise = self.clientGroup.next().makePromise(of: Void.self) @@ -630,7 +630,7 @@ final class HTTPClientTests: XCTestCaseHTTPClientTestsBaseClass { } return promise.futureResult - })) + }) XCTAssertThrowsError(try localClient.execute(request: request).wait()) { XCTAssertEqual($0 as? HTTPClientError, .writeTimeout) @@ -802,7 +802,7 @@ final class HTTPClientTests: XCTestCaseHTTPClientTestsBaseClass { } func testUploadStreaming() throws { - let body: HTTPClient.Body = .stream(contentLength: 8) { writer in + let body: HTTPClient.Body = .stream(length: .known(8)) { writer in let buffer = ByteBuffer(string: "1234") return writer.write(.byteBuffer(buffer)).flatMap { let buffer = ByteBuffer(string: "4321") @@ -1953,9 +1953,12 @@ final class HTTPClientTests: XCTestCaseHTTPClientTestsBaseClass { } func testValidationErrorsAreSurfaced() throws { - let request = try HTTPClient.Request(url: self.defaultHTTPBinURLPrefix + "get", method: .TRACE, body: .stream(bodyStream: { _ in + let request = try HTTPClient.Request( + url: self.defaultHTTPBinURLPrefix + "get", + method: .TRACE, + body: .stream(length: .unknown) { _ in self.defaultClient.eventLoopGroup.next().makeSucceededFuture(()) - })) + }) let runningRequest = self.defaultClient.execute(request: request) XCTAssertThrowsError(try runningRequest.wait()) { error in XCTAssertEqual(HTTPClientError.traceRequestWithBody, error as? HTTPClientError) @@ -2048,10 +2051,10 @@ final class HTTPClientTests: XCTestCaseHTTPClientTestsBaseClass { return try? HTTPClient.Request(url: "http://\(localAddress.ipAddress!):\(localAddress.port!)", method: .POST, headers: ["transfer-encoding": "chunked"], - body: .stream(bodyStream: { streamWriter in + body: .stream(length: .unknown) { streamWriter in streamWriterPromise.succeed(streamWriter) return sentOffAllBodyPartsPromise.futureResult - })) + }) } guard let server = makeServer(), let request = makeRequest(server: server) else { @@ -2083,7 +2086,7 @@ final class HTTPClientTests: XCTestCaseHTTPClientTestsBaseClass { } func testUploadStreamingCallinToleratedFromOtsideEL() throws { - let request = try HTTPClient.Request(url: self.defaultHTTPBinURLPrefix + "get", method: .POST, body: .stream(contentLength: 4) { writer in + let request = try HTTPClient.Request(url: self.defaultHTTPBinURLPrefix + "get", method: .POST, body: .stream(length: .known(4)) { writer in let promise = self.defaultClient.eventLoopGroup.next().makePromise(of: Void.self) // We have to toleare callins from any thread DispatchQueue(label: "upload-streaming").async { @@ -2602,9 +2605,9 @@ final class HTTPClientTests: XCTestCaseHTTPClientTestsBaseClass { } var request = try HTTPClient.Request(url: "http://localhost:\(server.serverPort)/") - request.body = .stream(bodyStream: { writer in + request.body = .stream(length: .unknown) { writer in writer.write(.byteBuffer(ByteBuffer(string: "1234"))) - }) + } let future = client.execute(request: request) @@ -2703,7 +2706,7 @@ final class HTTPClientTests: XCTestCaseHTTPClientTestsBaseClass { XCTAssertThrowsError( try self.defaultClient.execute(request: Request(url: url, - body: .stream(contentLength: 10) { streamWriter in + body: .stream(length: .known(10)) { streamWriter in let promise = self.defaultClient.eventLoopGroup.next().makePromise(of: Void.self) DispatchQueue(label: "content-length-test").async { streamWriter.write(.byteBuffer(ByteBuffer(string: "1"))).cascade(to: promise) @@ -2733,7 +2736,7 @@ final class HTTPClientTests: XCTestCaseHTTPClientTestsBaseClass { XCTAssertThrowsError( try self.defaultClient.execute(request: Request(url: url, - body: .stream(contentLength: 1) { streamWriter in + body: .stream(length: .known(1)) { streamWriter in streamWriter.write(.byteBuffer(ByteBuffer(string: tooLong))) })).wait()) { error in XCTAssertEqual(error as! HTTPClientError, HTTPClientError.bodyLengthMismatch) @@ -2777,7 +2780,7 @@ final class HTTPClientTests: XCTestCaseHTTPClientTestsBaseClass { } var request: HTTPClient.Request? - XCTAssertNoThrow(request = try Request(url: url, body: .stream(contentLength: 1, bodyStream: uploader))) + XCTAssertNoThrow(request = try Request(url: url, body: .stream(length: .known(1), uploader))) XCTAssertThrowsError(try self.defaultClient.execute(request: XCTUnwrap(request)).wait()) { XCTAssertEqual($0 as? HTTPClientError, .writeAfterRequestSent) } @@ -2793,7 +2796,7 @@ final class HTTPClientTests: XCTestCaseHTTPClientTestsBaseClass { _ = self.defaultClient.get(url: "http://localhost:\(self.defaultHTTPBin.port)/events/10/1") var request = try HTTPClient.Request(url: "http://localhost:\(self.defaultHTTPBin.port)/wait", method: .POST) - request.body = .stream(bodyStream: { writer in + request.body = .stream(length: .unknown) { writer in // Start writing chunks so tha we will try to write after read timeout is thrown for _ in 1...10 { _ = writer.write(.byteBuffer(ByteBuffer(string: "1234"))) @@ -2805,7 +2808,7 @@ final class HTTPClientTests: XCTestCaseHTTPClientTestsBaseClass { } return promise.futureResult - }) + } // We specify a deadline of 2 ms co that request will be timed out before all chunks are writtent, // we need to verify that second error on write after timeout does not lead to double-release. @@ -2968,7 +2971,7 @@ final class HTTPClientTests: XCTestCaseHTTPClientTestsBaseClass { let delegate = ResponseStreamDelegate(eventLoop: delegateEL) - let body: HTTPClient.Body = .stream(bodyStream: { writer in + let body: HTTPClient.Body = .stream(length: .unknown) { writer in let finalPromise = writeEL.makePromise(of: Void.self) @Sendable func writeLoop(_ writer: HTTPClient.Body.StreamWriter, index: Int) { @@ -3004,7 +3007,7 @@ final class HTTPClientTests: XCTestCaseHTTPClientTestsBaseClass { } return finalPromise.futureResult - }) + } let request = try! HTTPClient.Request(url: "http://localhost:\(httpBin.port)", body: body) let future = httpClient.execute(request: request, delegate: delegate, eventLoop: .delegate(on: delegateEL)) @@ -3068,9 +3071,9 @@ final class HTTPClientTests: XCTestCaseHTTPClientTestsBaseClass { let body = ByteBuffer(bytes: 0..<11) var request = try Request(url: httpBin.baseURL) - request.body = .stream(bodyStream: { writer in + request.body = .stream(length: .unknown) { writer in writer.write(.byteBuffer(body)) - }) + } XCTAssertThrowsError(try self.defaultClient.execute( request: request, delegate: ResponseAccumulator(request: request, maxBodySize: 10) @@ -3086,9 +3089,9 @@ final class HTTPClientTests: XCTestCaseHTTPClientTestsBaseClass { let body = ByteBuffer(bytes: 0..<10) var request = try Request(url: httpBin.baseURL) - request.body = .stream(bodyStream: { writer in + request.body = .stream(length: .unknown) { writer in writer.write(.byteBuffer(body)) - }) + } let response = try self.defaultClient.execute( request: request, delegate: ResponseAccumulator(request: request, maxBodySize: 10) @@ -3113,7 +3116,7 @@ final class HTTPClientTests: XCTestCaseHTTPClientTestsBaseClass { let delegate = ResponseStreamDelegate(eventLoop: delegateEL) - let body: HTTPClient.Body = .stream(bodyStream: { writer in + let body: HTTPClient.Body = .stream(length: .unknown) { writer in let finalPromise = writeEL.makePromise(of: Void.self) @Sendable func writeLoop(_ writer: HTTPClient.Body.StreamWriter, index: Int) { @@ -3143,7 +3146,7 @@ final class HTTPClientTests: XCTestCaseHTTPClientTestsBaseClass { } return finalPromise.futureResult - }) + } let request = try! HTTPClient.Request(url: "http://localhost:\(httpBin.port)", body: body) let future = httpClient.execute(request: request, delegate: delegate, eventLoop: .delegate(on: delegateEL)) @@ -3164,7 +3167,7 @@ final class HTTPClientTests: XCTestCaseHTTPClientTestsBaseClass { let httpClient = HTTPClient(eventLoopGroupProvider: .shared(eventLoopGroup)) defer { XCTAssertNoThrow(try httpClient.syncShutdown()) } - let body: HTTPClient.Body = .stream(bodyStream: { writer in + let body: HTTPClient.Body = .stream(length: .unknown) { writer in let finalPromise = writeEL.makePromise(of: Void.self) @Sendable func writeLoop(_ writer: HTTPClient.Body.StreamWriter, index: Int) { @@ -3194,7 +3197,7 @@ final class HTTPClientTests: XCTestCaseHTTPClientTestsBaseClass { } return finalPromise.futureResult - }) + } let request = try! HTTPClient.Request(url: "http://localhost:\(httpBin.port)", body: body) let future = httpClient.execute(request: request) @@ -3220,7 +3223,7 @@ final class HTTPClientTests: XCTestCaseHTTPClientTestsBaseClass { let httpClient = HTTPClient(eventLoopGroupProvider: .shared(eventLoopGroup)) defer { XCTAssertNoThrow(try httpClient.syncShutdown()) } - let body: HTTPClient.Body = .stream(bodyStream: { writer in + let body: HTTPClient.Body = .stream(length: .unknown) { writer in let finalPromise = writeEL.makePromise(of: Void.self) @Sendable func writeLoop(_ writer: HTTPClient.Body.StreamWriter, index: Int) { @@ -3250,7 +3253,7 @@ final class HTTPClientTests: XCTestCaseHTTPClientTestsBaseClass { } return finalPromise.futureResult - }) + } let headers = HTTPHeaders([("Connection", "close")]) let request = try! HTTPClient.Request(url: "http://localhost:\(httpBin.port)", headers: headers, body: body) diff --git a/Tests/AsyncHTTPClientTests/NoBytesSentOverBodyLimitTests.swift b/Tests/AsyncHTTPClientTests/NoBytesSentOverBodyLimitTests.swift index 756facb3f..9634253ab 100644 --- a/Tests/AsyncHTTPClientTests/NoBytesSentOverBodyLimitTests.swift +++ b/Tests/AsyncHTTPClientTests/NoBytesSentOverBodyLimitTests.swift @@ -40,7 +40,7 @@ final class NoBytesSentOverBodyLimitTests: XCTestCaseHTTPClientTestsBaseClass { let request = try Request( url: "http://localhost:\(server.serverPort)", - body: .stream(contentLength: 1) { streamWriter in + body: .stream(length: .known(1)) { streamWriter in streamWriter.write(.byteBuffer(ByteBuffer(string: tooLong))) } ) diff --git a/Tests/AsyncHTTPClientTests/RequestBagTests.swift b/Tests/AsyncHTTPClientTests/RequestBagTests.swift index fa094c1af..b13477388 100644 --- a/Tests/AsyncHTTPClientTests/RequestBagTests.swift +++ b/Tests/AsyncHTTPClientTests/RequestBagTests.swift @@ -39,7 +39,7 @@ final class RequestBagTests: XCTestCase { let expectedWrites = bytesToSent / 100 + ((bytesToSent % 100 > 0) ? 1 : 0) let writeDonePromise = embeddedEventLoop.makePromise(of: Void.self) - let requestBody: HTTPClient.Body = .stream(contentLength: Int64(bytesToSent)) { writer -> EventLoopFuture in + let requestBody: HTTPClient.Body = .stream(length: .known(Int64(bytesToSent))) { writer -> EventLoopFuture in @Sendable func write(donePromise: EventLoopPromise) { let futureWrite: EventLoopFuture? = testState.withLockedValue { state in XCTAssertTrue(state.streamIsAllowedToWrite) @@ -166,7 +166,7 @@ final class RequestBagTests: XCTestCase { defer { XCTAssertNoThrow(try embeddedEventLoop.syncShutdownGracefully()) } let logger = Logger(label: "test") - let requestBody: HTTPClient.Body = .stream(contentLength: 12) { writer -> EventLoopFuture in + let requestBody: HTTPClient.Body = .stream(length: .known(12)) { writer -> EventLoopFuture in writer.write(.byteBuffer(ByteBuffer(bytes: 0...3))).flatMap { _ -> EventLoopFuture in embeddedEventLoop.makeFailedFuture(TestError()) @@ -549,7 +549,7 @@ final class RequestBagTests: XCTestCase { url: "https://swift.org", method: .POST, headers: ["content-length": "12"], - body: .stream(contentLength: 12) { writer -> EventLoopFuture in + body: .stream(length: .known(12)) { writer -> EventLoopFuture in return writer.write(.byteBuffer(.init(bytes: 0...3))).flatMap { _ in firstWriteSuccess.withLockedValue { $0 = true } @@ -872,11 +872,11 @@ final class RequestBagTests: XCTestCase { let writerPromise = group.any().makePromise(of: HTTPClient.Body.StreamWriter.self) let donePromise = group.any().makePromise(of: Void.self) - request.body = .stream(bodyStream: { [leakDetector] writer in + request.body = .stream(length: .unknown) { [leakDetector] writer in _ = leakDetector writerPromise.succeed(writer) return donePromise.futureResult - }) + } let resultFuture = httpClient.execute(request: request) request.body = nil From f43996af464aac78b2c95465d1c38f9d525ceed9 Mon Sep 17 00:00:00 2001 From: Aryan Shah Date: Tue, 2 Jul 2024 12:58:52 +0100 Subject: [PATCH 2/2] Run formatter --- Sources/AsyncHTTPClient/HTTPHandler.swift | 2 +- Tests/AsyncHTTPClientTests/HTTPClientTests.swift | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Sources/AsyncHTTPClient/HTTPHandler.swift b/Sources/AsyncHTTPClient/HTTPHandler.swift index 90d7bd774..02b5e9ad6 100644 --- a/Sources/AsyncHTTPClient/HTTPHandler.swift +++ b/Sources/AsyncHTTPClient/HTTPHandler.swift @@ -88,7 +88,7 @@ extension HTTPClient { @available(*, deprecated, renamed: "contentLength") public var length: Int? { get { - if case let .known(count) = self.contentLength.length { + if case .known(let count) = self.contentLength.length { return Int(count) } return nil diff --git a/Tests/AsyncHTTPClientTests/HTTPClientTests.swift b/Tests/AsyncHTTPClientTests/HTTPClientTests.swift index 8298deb45..6e8ae6547 100644 --- a/Tests/AsyncHTTPClientTests/HTTPClientTests.swift +++ b/Tests/AsyncHTTPClientTests/HTTPClientTests.swift @@ -1957,8 +1957,9 @@ final class HTTPClientTests: XCTestCaseHTTPClientTestsBaseClass { url: self.defaultHTTPBinURLPrefix + "get", method: .TRACE, body: .stream(length: .unknown) { _ in - self.defaultClient.eventLoopGroup.next().makeSucceededFuture(()) - }) + self.defaultClient.eventLoopGroup.next().makeSucceededFuture(()) + } + ) let runningRequest = self.defaultClient.execute(request: request) XCTAssertThrowsError(try runningRequest.wait()) { error in XCTAssertEqual(HTTPClientError.traceRequestWithBody, error as? HTTPClientError)