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 } } diff --git a/Tests/AsyncHTTPClientTests/HTTPClientTests.swift b/Tests/AsyncHTTPClientTests/HTTPClientTests.swift index 075530f4e..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 @@ -607,6 +608,35 @@ final class HTTPClientTests: XCTestCaseHTTPClientTestsBaseClass { } } + 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) // 198.51.100.254 is reserved for documentation only and therefore should not accept any TCP connection @@ -1230,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) @@ -1270,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) @@ -2728,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.