Skip to content

Commit b9029ef

Browse files
authored
Add support for custom cancellation error (#683)
1 parent 45626d3 commit b9029ef

File tree

8 files changed

+44
-18
lines changed

8 files changed

+44
-18
lines changed

‎Sources/AsyncHTTPClient/HTTPHandler.swift‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -688,7 +688,7 @@ extension URL{
688688
}
689689

690690
protocolHTTPClientTaskDelegate{
691-
funccancel()
691+
funcfail(_ error:Error)
692692
}
693693

694694
extensionHTTPClient{
@@ -780,12 +780,18 @@ extension HTTPClient{
780780

781781
/// Cancels the request execution.
782782
publicfunc cancel(){
783+
self.fail(reason:HTTPClientError.cancelled)
784+
}
785+
786+
/// Cancels the request execution with a custom `Error`.
787+
/// - Parameter reason: the error that is used to fail the promise
788+
publicfunc fail(reason error:Error){
783789
lettaskDelegate=self.lock.withLock{()->HTTPClientTaskDelegate?in
784790
self._isCancelled =true
785791
returnself._taskDelegate
786792
}
787793

788-
taskDelegate?.cancel()
794+
taskDelegate?.fail(error)
789795
}
790796

791797
func succeed<Delegate:HTTPClientResponseDelegate>(promise:EventLoopPromise<Response>?,

‎Sources/AsyncHTTPClient/RequestBag.swift‎

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@ final class RequestBag<Delegate: HTTPClientResponseDelegate>{
394394
}
395395
}
396396

397-
extensionRequestBag:HTTPSchedulableRequest{
397+
extensionRequestBag:HTTPSchedulableRequest,HTTPClientTaskDelegate{
398398
vartlsConfiguration:TLSConfiguration?{
399399
self.request.tlsConfiguration
400400
}
@@ -511,9 +511,3 @@ extension RequestBag: HTTPExecutableRequest{
511511
}
512512
}
513513
}
514-
515-
extensionRequestBag:HTTPClientTaskDelegate{
516-
func cancel(){
517-
self.fail(HTTPClientError.cancelled)
518-
}
519-
}

‎Tests/AsyncHTTPClientTests/HTTP1ClientChannelHandlerTests.swift‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,7 @@ class HTTP1ClientChannelHandlerTests: XCTestCase{
327327
XCTAssertNoThrow(try embedded.writeInbound(HTTPClientResponsePart.head(responseHead)))
328328

329329
// canceling the request
330-
requestBag.cancel()
330+
requestBag.fail(HTTPClientError.cancelled)
331331
XCTAssertThrowsError(try requestBag.task.futureResult.wait()){
332332
XCTAssertEqual($0 as?HTTPClientError,.cancelled)
333333
}

‎Tests/AsyncHTTPClientTests/HTTP2ClientRequestHandlerTests.swift‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ class HTTP2ClientRequestHandlerTests: XCTestCase{
276276
XCTAssertNoThrow(try embedded.writeInbound(HTTPClientResponsePart.head(responseHead)))
277277

278278
// canceling the request
279-
requestBag.cancel()
279+
requestBag.fail(HTTPClientError.cancelled)
280280
XCTAssertThrowsError(try requestBag.task.futureResult.wait()){
281281
XCTAssertEqual($0 as?HTTPClientError,.cancelled)
282282
}

‎Tests/AsyncHTTPClientTests/HTTPClientTests+XCTest.swift‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ extension HTTPClientTests{
5252
("testStreaming", testStreaming),
5353
("testFileDownload", testFileDownload),
5454
("testFileDownloadError", testFileDownloadError),
55+
("testFileDownloadCustomError", testFileDownloadCustomError),
5556
("testRemoteClose", testRemoteClose),
5657
("testReadTimeout", testReadTimeout),
5758
("testConnectTimeout", testConnectTimeout),

‎Tests/AsyncHTTPClientTests/HTTPClientTests.swift‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,31 @@ final class HTTPClientTests: XCTestCaseHTTPClientTestsBaseClass{
569569
XCTAssertEqual(0, progress.receivedBytes)
570570
}
571571

572+
func testFileDownloadCustomError()throws{
573+
letrequest=tryRequest(url:self.defaultHTTPBinURLPrefix +"get")
574+
structCustomError:Equatable,Error{}
575+
576+
tryTemporaryFileHelpers.withTemporaryFilePath{ path in
577+
letdelegate=tryFileDownloadDelegate(path: path, reportHead:{ task, head in
578+
XCTAssertEqual(head.status,.ok)
579+
task.fail(reason:CustomError())
580+
}, reportProgress:{ _, _ in
581+
XCTFail("should never be called")
582+
})
583+
XCTAssertThrowsError(
584+
tryself.defaultClient.execute(
585+
request: request,
586+
delegate: delegate
587+
)
588+
.wait()
589+
){ error in
590+
XCTAssertEqualTypeAndValue(error,CustomError())
591+
}
592+
593+
XCTAssertFalse(TemporaryFileHelpers.fileExists(path: path))
594+
}
595+
}
596+
572597
func testRemoteClose(){
573598
XCTAssertThrowsError(tryself.defaultClient.get(url:self.defaultHTTPBinURLPrefix +"close").wait()){
574599
XCTAssertEqual($0 as?HTTPClientError,.remoteConnectionClosed)

‎Tests/AsyncHTTPClientTests/HTTPConnectionPoolTests.swift‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ class HTTPConnectionPoolTests: XCTestCase{
334334

335335
pool.executeRequest(requestBag)
336336
XCTAssertNoThrow(try eventLoop.scheduleTask(in:.seconds(1)){}.futureResult.wait())
337-
requestBag.cancel()
337+
requestBag.fail(HTTPClientError.cancelled)
338338

339339
XCTAssertThrowsError(try requestBag.task.futureResult.wait()){
340340
XCTAssertEqual($0 as?HTTPClientError,.cancelled)

‎Tests/AsyncHTTPClientTests/RequestBagTests.swift‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ final class RequestBagTests: XCTestCase{
220220
XCTAssert(bag.eventLoop === embeddedEventLoop)
221221

222222
letexecutor=MockRequestExecutor(eventLoop: embeddedEventLoop)
223-
bag.cancel()
223+
bag.fail(HTTPClientError.cancelled)
224224

225225
bag.willExecuteRequest(executor)
226226
XCTAssertTrue(executor.isCancelled,"The request bag, should call cancel immediately on the executor")
@@ -301,7 +301,7 @@ final class RequestBagTests: XCTestCase{
301301
bag.fail(MyError())
302302
XCTAssertEqual(delegate.hitDidReceiveError,1)
303303

304-
bag.cancel()
304+
bag.fail(HTTPClientError.cancelled)
305305
XCTAssertEqual(delegate.hitDidReceiveError,1)
306306

307307
XCTAssertThrowsError(try bag.task.futureResult.wait()){
@@ -342,7 +342,7 @@ final class RequestBagTests: XCTestCase{
342342
XCTAssertEqual(delegate.hitDidSendRequestHead,1)
343343
XCTAssertEqual(delegate.hitDidSendRequest,1)
344344

345-
bag.cancel()
345+
bag.fail(HTTPClientError.cancelled)
346346
XCTAssertTrue(executor.isCancelled,"The request bag, should call cancel immediately on the executor")
347347

348348
XCTAssertThrowsError(try bag.task.futureResult.wait()){
@@ -376,7 +376,7 @@ final class RequestBagTests: XCTestCase{
376376
bag.requestWasQueued(queuer)
377377

378378
XCTAssertEqual(queuer.hitCancelCount,0)
379-
bag.cancel()
379+
bag.fail(HTTPClientError.cancelled)
380380
XCTAssertEqual(queuer.hitCancelCount,1)
381381

382382
XCTAssertThrowsError(try bag.task.futureResult.wait()){
@@ -445,9 +445,9 @@ final class RequestBagTests: XCTestCase{
445445
letexecutor=MockRequestExecutor(eventLoop: embeddedEventLoop)
446446
executor.runRequest(bag)
447447

448-
// This simulates a race between the user cancelling the task (which invokes `RequestBag.cancel`) and the
448+
// This simulates a race between the user cancelling the task (which invokes `RequestBag.fail(_:)`) and the
449449
// call to `resumeRequestBodyStream` (which comes from the `Channel` event loop and so may have to hop.
450-
bag.cancel()
450+
bag.fail(HTTPClientError.cancelled)
451451
bag.resumeRequestBodyStream()
452452

453453
XCTAssertEqual(executor.isCancelled,true)

0 commit comments

Comments
(0)