Skip to content

Commit beb2637

Browse files
authored
Clean up Task error handling. (#839)
Motivation We have some Task error handling functions that are generic for no apparent reason. They're also typically called from contexts where they also report the error to the delegate, but one of the call sites doesn't do that. So add a test for that as well. Modifications - Rewrite Task.fail(with:delegate:) to be non-generic. - Add a call to the delegate error handler on the path that is missing it. - Add a test for that call Results Cleaner, easier to follow code
1 parent 7e6f9cf commit beb2637

File tree

4 files changed

+41
-6
lines changed

4 files changed

+41
-6
lines changed

Sources/AsyncHTTPClient/HTTPClient.swift

+2-1
Original file line numberDiff line numberDiff line change
@@ -795,7 +795,8 @@ public class HTTPClient {
795795

796796
self.poolManager.executeRequest(requestBag)
797797
} catch {
798-
task.fail(with: error, delegateType: Delegate.self)
798+
delegate.didReceiveError(task: task, error)
799+
task.failInternal(with: error)
799800
}
800801

801802
return task

Sources/AsyncHTTPClient/HTTPHandler.swift

+3-3
Original file line numberDiff line numberDiff line change
@@ -1024,9 +1024,9 @@ extension HTTPClient {
10241024
taskDelegate?.fail(error)
10251025
}
10261026

1027-
func fail<Delegate: HTTPClientResponseDelegate>(
1028-
with error: Error,
1029-
delegateType: Delegate.Type
1027+
/// Called internally only, used to fail a task from within the state machine functionality.
1028+
func failInternal(
1029+
with error: Error
10301030
) {
10311031
self.promise.fail(error)
10321032
}

Sources/AsyncHTTPClient/RequestBag.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ final class RequestBag<Delegate: HTTPClientResponseDelegate & Sendable>: Sendabl
120120
executor.cancelRequest(self)
121121
case .failTaskAndCancelExecutor(let error, let executor):
122122
self.delegate.didReceiveError(task: self.task, error)
123-
self.task.fail(with: error, delegateType: Delegate.self)
123+
self.task.failInternal(with: error)
124124
executor.cancelRequest(self)
125125
case .none:
126126
break
@@ -181,7 +181,7 @@ final class RequestBag<Delegate: HTTPClientResponseDelegate & Sendable>: Sendabl
181181
switch action {
182182
case .failTask(let error):
183183
self.delegate.didReceiveError(task: self.task, error)
184-
self.task.fail(with: error, delegateType: Delegate.self)
184+
self.task.failInternal(with: error)
185185
return self.task.eventLoop.makeFailedFuture(error)
186186

187187
case .failFuture(let error):

Tests/AsyncHTTPClientTests/HTTPClientTests.swift

+34
Original file line numberDiff line numberDiff line change
@@ -3357,6 +3357,40 @@ final class HTTPClientTests: XCTestCaseHTTPClientTestsBaseClass {
33573357
XCTAssertNoThrow(try future.wait())
33583358
}
33593359

3360+
func testDelegateGetsErrorsFromCreatingRequestBag() throws {
3361+
// We want to test that we propagate errors to the delegate from failures to construct the
3362+
// request bag. Those errors only come from invalid headers.
3363+
final class TestDelegate: HTTPClientResponseDelegate, Sendable {
3364+
typealias Response = Void
3365+
let error: NIOLockedValueBox<Error?> = .init(nil)
3366+
func didFinishRequest(task: HTTPClient.Task<Void>) throws {}
3367+
func didReceiveError(task: HTTPClient.Task<Response>, _ error: Error) {
3368+
self.error.withLockedValue { $0 = error }
3369+
}
3370+
}
3371+
3372+
let httpClient = HTTPClient(
3373+
eventLoopGroupProvider: .shared(self.clientGroup)
3374+
)
3375+
3376+
defer {
3377+
XCTAssertNoThrow(try httpClient.syncShutdown())
3378+
}
3379+
3380+
// 198.51.100.254 is reserved for documentation only
3381+
var request = try HTTPClient.Request(url: "http://198.51.100.254:65535/get")
3382+
request.headers.replaceOrAdd(name: "Not-ASCII", value: "not-fine\n")
3383+
let delegate = TestDelegate()
3384+
3385+
XCTAssertThrowsError(try httpClient.execute(request: request, delegate: delegate).wait()) {
3386+
XCTAssertEqualTypeAndValue($0, HTTPClientError.invalidHeaderFieldValues(["not-fine\n"]))
3387+
XCTAssertEqualTypeAndValue(
3388+
delegate.error.withLockedValue { $0 },
3389+
HTTPClientError.invalidHeaderFieldValues(["not-fine\n"])
3390+
)
3391+
}
3392+
}
3393+
33603394
func testContentLengthTooLongFails() throws {
33613395
let url = self.defaultHTTPBinURLPrefix + "post"
33623396
XCTAssertThrowsError(

0 commit comments

Comments
 (0)