Merge pull request #689 from pushkarnk/task-cancel
diff --git a/Foundation/NSURLSession/NSURLSessionTask.swift b/Foundation/NSURLSession/NSURLSessionTask.swift
index 6f33cc6..5856d5d 100644
--- a/Foundation/NSURLSession/NSURLSessionTask.swift
+++ b/Foundation/NSURLSession/NSURLSessionTask.swift
@@ -194,8 +194,18 @@
* cases, the task may signal other work before it acknowledges the
* cancelation. -cancel may be sent to a task that has been suspended.
*/
- open func cancel() { NSUnimplemented() }
-
+ open func cancel() {
+ workQueue.sync {
+ guard self.state == .running || self.state == .suspended else { return }
+ self.state = .canceling
+ self.workQueue.async {
+ self.internalState = .transferFailed
+ let urlError = URLError(_nsError: NSError(domain: NSURLErrorDomain, code: NSURLErrorCancelled, userInfo: nil))
+ self.completeTask(withError: urlError)
+ }
+ }
+ }
+
/*
* The current state of the task within the session.
*/
@@ -866,7 +876,7 @@
}
func completeTask(withError error: Error) {
self.error = error
-
+
guard case .transferFailed = internalState else {
fatalError("Trying to complete the task, but its transfer isn't complete / failed.")
}
diff --git a/TestFoundation/TestNSURLSession.swift b/TestFoundation/TestNSURLSession.swift
index d86e749..cce1508 100644
--- a/TestFoundation/TestNSURLSession.swift
+++ b/TestFoundation/TestNSURLSession.swift
@@ -32,6 +32,7 @@
("test_finishTaskAndInvalidate", test_finishTasksAndInvalidate),
("test_taskError", test_taskError),
("test_taskCopy", test_taskCopy),
+ ("test_cancelTask", test_cancelTask),
]
}
@@ -297,6 +298,26 @@
XCTAssert(task.isEqual(task.copy()))
}
+
+ func test_cancelTask() {
+ let serverReady = ServerSemaphore()
+ globalDispatchQueue.async {
+ do {
+ try self.runServer(with: serverReady)
+ } catch {
+ XCTAssertTrue(true)
+ return
+ }
+ }
+ serverReady.wait()
+ let url = URL(string: "http://127.0.0.1:\(serverPort)/Peru")!
+ let d = DataTask(with: expectation(description: "Task to be canceled"))
+ d.cancelExpectation = expectation(description: "URLSessionTask wasn't canceled")
+ d.run(with: url)
+ d.cancel()
+ waitForExpectations(timeout: 12)
+ }
+
}
class SessionDelegate: NSObject, URLSessionDelegate {
@@ -314,6 +335,8 @@
var capital = "unknown"
var session: URLSession! = nil
var task: URLSessionDataTask! = nil
+ var cancelExpectation: XCTestExpectation?
+
public var error = false
init(with expectation: XCTestExpectation) {
@@ -335,20 +358,26 @@
task = session.dataTask(with: url)
task.resume()
}
+
+ func cancel() {
+ task.cancel()
+ }
}
extension DataTask : URLSessionDataDelegate {
- public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
- capital = String(data: data, encoding: String.Encoding.utf8)!
- dataTaskExpectation.fulfill()
- }
+ public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
+ capital = String(data: data, encoding: String.Encoding.utf8)!
+ dataTaskExpectation.fulfill()
+ }
}
extension DataTask : URLSessionTaskDelegate {
public func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
guard let e = error as? URLError else { return }
- XCTAssertEqual(e.code, .timedOut, "Unexpected error code")
dataTaskExpectation.fulfill()
+ if let cancellation = cancelExpectation {
+ cancellation.fulfill()
+ }
self.error = true
}
}