From 5d6f4170186f2f464bf58afd7f0e0c3691927d2a Mon Sep 17 00:00:00 2001 From: Gus Cairo Date: Thu, 21 Mar 2024 15:18:14 +0000 Subject: [PATCH 1/3] Fix write timeout not being initialised --- Sources/AsyncHTTPClient/HTTPClient.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Sources/AsyncHTTPClient/HTTPClient.swift b/Sources/AsyncHTTPClient/HTTPClient.swift index d6d02c94f..683532933 100644 --- a/Sources/AsyncHTTPClient/HTTPClient.swift +++ b/Sources/AsyncHTTPClient/HTTPClient.swift @@ -961,6 +961,7 @@ extension HTTPClient.Configuration { ) { self.connect = connect self.read = read + self.write = write } } From 9220e7bc494c47e83d840524d68652cc0d663a69 Mon Sep 17 00:00:00 2001 From: Gus Cairo Date: Thu, 21 Mar 2024 15:18:23 +0000 Subject: [PATCH 2/3] Add write timeout test --- .../HTTPClientTests.swift | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/Tests/AsyncHTTPClientTests/HTTPClientTests.swift b/Tests/AsyncHTTPClientTests/HTTPClientTests.swift index 075530f4e..feef86c1a 100644 --- a/Tests/AsyncHTTPClientTests/HTTPClientTests.swift +++ b/Tests/AsyncHTTPClientTests/HTTPClientTests.swift @@ -28,6 +28,7 @@ import NIOSSL import NIOTestUtils import NIOTransportServices import XCTest +import NIOEmbedded final class HTTPClientTests: XCTestCaseHTTPClientTestsBaseClass { func testRequestURI() throws { @@ -606,6 +607,35 @@ final class HTTPClientTests: XCTestCaseHTTPClientTestsBaseClass { XCTAssertEqual($0 as? HTTPClientError, .readTimeout) } } + + func testWriteTimeout() throws { + let localClient = HTTPClient(eventLoopGroupProvider: .shared(self.clientGroup), + configuration: HTTPClient.Configuration(timeout: HTTPClient.Configuration.Timeout(write: .nanoseconds(10)))) + + defer { + XCTAssertNoThrow(try localClient.syncShutdown()) + } + + // Create a request that writes a chunk, then waits longer than the configured write timeout, + // and then writes again. This should trigger a write timeout error. + let request = try HTTPClient.Request(url: self.defaultHTTPBinURLPrefix + "post", + method: .POST, + headers: ["transfer-encoding": "chunked"], + body: .stream { streamWriter in + _ = streamWriter.write(.byteBuffer(.init())) + + let promise = self.clientGroup.next().makePromise(of: Void.self) + self.clientGroup.next().scheduleTask(in: .milliseconds(3)) { + streamWriter.write(.byteBuffer(.init())).cascade(to: promise) + } + + return promise.futureResult + }) + + XCTAssertThrowsError(try localClient.execute(request: request).wait()) { + XCTAssertEqual($0 as? HTTPClientError, .writeTimeout) + } + } func testConnectTimeout() throws { #if os(Linux) From 6b718e6f356d396bf26f15a8aafe0cc3b9a3feff Mon Sep 17 00:00:00 2001 From: Gus Cairo Date: Thu, 21 Mar 2024 15:20:22 +0000 Subject: [PATCH 3/3] Formatting --- .../HTTPClientTests.swift | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/Tests/AsyncHTTPClientTests/HTTPClientTests.swift b/Tests/AsyncHTTPClientTests/HTTPClientTests.swift index feef86c1a..cdf9aa219 100644 --- a/Tests/AsyncHTTPClientTests/HTTPClientTests.swift +++ b/Tests/AsyncHTTPClientTests/HTTPClientTests.swift @@ -20,6 +20,7 @@ import Network import Logging import NIOConcurrencyHelpers import NIOCore +import NIOEmbedded import NIOFoundationCompat import NIOHTTP1 import NIOHTTPCompression @@ -28,7 +29,6 @@ import NIOSSL import NIOTestUtils import NIOTransportServices import XCTest -import NIOEmbedded final class HTTPClientTests: XCTestCaseHTTPClientTestsBaseClass { func testRequestURI() throws { @@ -607,31 +607,31 @@ final class HTTPClientTests: XCTestCaseHTTPClientTestsBaseClass { XCTAssertEqual($0 as? HTTPClientError, .readTimeout) } } - + func testWriteTimeout() throws { let localClient = HTTPClient(eventLoopGroupProvider: .shared(self.clientGroup), configuration: HTTPClient.Configuration(timeout: HTTPClient.Configuration.Timeout(write: .nanoseconds(10)))) - + defer { XCTAssertNoThrow(try localClient.syncShutdown()) } - + // Create a request that writes a chunk, then waits longer than the configured write timeout, // and then writes again. This should trigger a write timeout error. let request = try HTTPClient.Request(url: self.defaultHTTPBinURLPrefix + "post", method: .POST, headers: ["transfer-encoding": "chunked"], body: .stream { streamWriter in - _ = streamWriter.write(.byteBuffer(.init())) - - let promise = self.clientGroup.next().makePromise(of: Void.self) - self.clientGroup.next().scheduleTask(in: .milliseconds(3)) { - streamWriter.write(.byteBuffer(.init())).cascade(to: promise) - } - - return promise.futureResult - }) - + _ = streamWriter.write(.byteBuffer(.init())) + + let promise = self.clientGroup.next().makePromise(of: Void.self) + self.clientGroup.next().scheduleTask(in: .milliseconds(3)) { + streamWriter.write(.byteBuffer(.init())).cascade(to: promise) + } + + return promise.futureResult + }) + XCTAssertThrowsError(try localClient.execute(request: request).wait()) { XCTAssertEqual($0 as? HTTPClientError, .writeTimeout) } @@ -1260,8 +1260,8 @@ final class HTTPClientTests: XCTestCaseHTTPClientTestsBaseClass { /// openssl req -x509 -newkey rsa:4096 -keyout self_signed_key.pem -out self_signed_cert.pem -sha256 -days 99999 -nodes -subj '/CN=localhost' let certPath = Bundle.module.path(forResource: "self_signed_cert", ofType: "pem")! let keyPath = Bundle.module.path(forResource: "self_signed_key", ofType: "pem")! - let configuration = TLSConfiguration.makeServerConfiguration( - certificateChain: try NIOSSLCertificate.fromPEMFile(certPath).map { .certificate($0) }, + let configuration = try TLSConfiguration.makeServerConfiguration( + certificateChain: NIOSSLCertificate.fromPEMFile(certPath).map { .certificate($0) }, privateKey: .file(keyPath) ) let sslContext = try NIOSSLContext(configuration: configuration) @@ -1300,8 +1300,8 @@ final class HTTPClientTests: XCTestCaseHTTPClientTestsBaseClass { /// openssl req -x509 -newkey rsa:4096 -keyout self_signed_key.pem -out self_signed_cert.pem -sha256 -days 99999 -nodes -subj '/CN=localhost' let certPath = Bundle.module.path(forResource: "self_signed_cert", ofType: "pem")! let keyPath = Bundle.module.path(forResource: "self_signed_key", ofType: "pem")! - let configuration = TLSConfiguration.makeServerConfiguration( - certificateChain: try NIOSSLCertificate.fromPEMFile(certPath).map { .certificate($0) }, + let configuration = try TLSConfiguration.makeServerConfiguration( + certificateChain: NIOSSLCertificate.fromPEMFile(certPath).map { .certificate($0) }, privateKey: .file(keyPath) ) let sslContext = try NIOSSLContext(configuration: configuration) @@ -2758,7 +2758,7 @@ final class HTTPClientTests: XCTestCaseHTTPClientTestsBaseClass { func uploader(_ streamWriter: HTTPClient.Body.StreamWriter) -> EventLoopFuture { let done = streamWriter.write(.byteBuffer(ByteBuffer(string: "X"))) - done.recover { error -> Void in + done.recover { error in XCTFail("unexpected error \(error)") }.whenSuccess { // This is executed when we have already sent the end of the request.