From 831f9238ae0fb54524ff9b5eed65bb8aeea20640 Mon Sep 17 00:00:00 2001 From: Albert Aleksieiev Date: Tue, 2 Apr 2019 17:18:56 +0300 Subject: [PATCH 1/5] Dev: fix fatalError if there is no task in TaskRegistry --- Foundation/URLSession/TaskRegistry.swift | 4 ++++ Foundation/URLSession/URLSession.swift | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/Foundation/URLSession/TaskRegistry.swift b/Foundation/URLSession/TaskRegistry.swift index b817bcec0a..0098ce7fdd 100644 --- a/Foundation/URLSession/TaskRegistry.swift +++ b/Foundation/URLSession/TaskRegistry.swift @@ -115,4 +115,8 @@ extension URLSession._TaskRegistry { } return b } + + func containsBehaviour(for task: URLSessionTask) -> Bool { + return behaviours[task.taskIdentifier] != nil + } } diff --git a/Foundation/URLSession/URLSession.swift b/Foundation/URLSession/URLSession.swift index 3d503d43c0..f974626043 100644 --- a/Foundation/URLSession/URLSession.swift +++ b/Foundation/URLSession/URLSession.swift @@ -546,6 +546,10 @@ internal extension URLSession { } func behaviour(for task: URLSessionTask) -> _TaskBehaviour { + guard taskRegistry.containsBehaviour(for: task) else { + return .noDelegate + } + switch taskRegistry.behaviour(for: task) { case .dataCompletionHandler(let c): return .dataCompletionHandler(c) case .downloadCompletionHandler(let c): return .downloadCompletionHandler(c) From 9e954e06fef2370616c9a42ff0d418e7001ebb3e Mon Sep 17 00:00:00 2001 From: Albert Aleksieiev Date: Tue, 2 Apr 2019 17:41:29 +0300 Subject: [PATCH 2/5] Dev: avoid using bundle in Android --- Foundation/NSString.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Foundation/NSString.swift b/Foundation/NSString.swift index 57f651c4f2..b1f7f78162 100644 --- a/Foundation/NSString.swift +++ b/Foundation/NSString.swift @@ -27,7 +27,11 @@ func NSLocalizedString(_ key: String, bundle: Bundle = Bundle.main, value: String = "", comment: String) -> String { - return bundle.localizedString(forKey: key, value: value, table: tableName) + #if os(Android) + return key + #else + return bundle.localizedString(forKey: key, value: value, table: tableName) + #endif } #if os(OSX) || os(iOS) From 8e2266b2f90c0fa9b8fc92f042a8128ec61885d2 Mon Sep 17 00:00:00 2001 From: Albert Aleksieiev Date: Fri, 5 Apr 2019 15:43:07 +0300 Subject: [PATCH 3/5] Dev: get rid of `fatalError` in TaskRegistry::remove --- Foundation/URLSession/TaskRegistry.swift | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/Foundation/URLSession/TaskRegistry.swift b/Foundation/URLSession/TaskRegistry.swift index 0098ce7fdd..0e8cb8f676 100644 --- a/Foundation/URLSession/TaskRegistry.swift +++ b/Foundation/URLSession/TaskRegistry.swift @@ -72,14 +72,19 @@ extension URLSession._TaskRegistry { func remove(_ task: URLSessionTask) { let identifier = task.taskIdentifier guard identifier != 0 else { fatalError("Invalid task identifier") } - guard let tasksIdx = tasks.index(forKey: identifier) else { - fatalError("Trying to remove task, but it's not in the registry.") + + if let tasksIdx = tasks.index(forKey: identifier) { + tasks.remove(at: tasksIdx) + } else { + NSLog("Trying to remove task, but it's not in the registry.") } - tasks.remove(at: tasksIdx) - guard let behaviourIdx = behaviours.index(forKey: identifier) else { - fatalError("Trying to remove task's behaviour, but it's not in the registry.") + + if let behaviourIdx = behaviours.index(forKey: identifier) { + behaviours.remove(at: behaviourIdx) + } else { + NSLog("Trying to remove task's behaviour, but it's not in the registry.") } - behaviours.remove(at: behaviourIdx) + guard let allTasksFinished = tasksFinishedCallback else { return } if self.isEmpty { From 27fe1d213a19a354b7d20b4809a026176ec63d17 Mon Sep 17 00:00:00 2001 From: Albert Aleksieiev Date: Fri, 5 Apr 2019 18:11:28 +0300 Subject: [PATCH 4/5] Dev: handle fatalError for HTTPURLProtocol --- Foundation/URLSession/http/HTTPURLProtocol.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Foundation/URLSession/http/HTTPURLProtocol.swift b/Foundation/URLSession/http/HTTPURLProtocol.swift index 8f4dc69bf5..4c218ca400 100644 --- a/Foundation/URLSession/http/HTTPURLProtocol.swift +++ b/Foundation/URLSession/http/HTTPURLProtocol.swift @@ -56,7 +56,7 @@ internal class _HTTPURLProtocol: URLProtocol { suspend() } else { self.internalState = .transferFailed - guard let error = self.task?.error else { fatalError() } + let error = self.task?.error ?? NSError(domain: NSURLErrorDomain, code: URLError.Code.unknown.rawValue) completeTask(withError: error) } } From e6e6f4b03a3d6e2e7e52d25cfac2699c788803cc Mon Sep 17 00:00:00 2001 From: Lukas Stabe Date: Wed, 11 Jul 2018 13:10:23 +0200 Subject: [PATCH 5/5] make sure writes to URLSession.taskRegistry happen on work queue --- Foundation/URLSession/URLSessionTask.swift | 26 +++++++++++++++------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/Foundation/URLSession/URLSessionTask.swift b/Foundation/URLSession/URLSessionTask.swift index 82028da0b6..adccfe97cc 100644 --- a/Foundation/URLSession/URLSessionTask.swift +++ b/Foundation/URLSession/URLSessionTask.swift @@ -702,24 +702,30 @@ extension _ProtocolClient: URLProtocolClient { session.delegateQueue.addOperation { delegate.urlSession(session, task: task, didCompleteWithError: nil) task.state = .completed - task.workQueue.async { + session.workQueue.async { session.taskRegistry.remove(task) } } case .noDelegate: task.state = .completed - session.taskRegistry.remove(task) + session.workQueue.async { + session.taskRegistry.remove(task) + } case .dataCompletionHandler(let completion): session.delegateQueue.addOperation { completion(`protocol`.properties[URLProtocol._PropertyKey.responseData] as? Data ?? Data(), task.response, nil) task.state = .completed - session.taskRegistry.remove(task) + session.workQueue.async { + session.taskRegistry.remove(task) + } } case .downloadCompletionHandler(let completion): session.delegateQueue.addOperation { completion(`protocol`.properties[URLProtocol._PropertyKey.temporaryFileURL] as? URL, task.response, nil) task.state = .completed - session.taskRegistry.remove(task) + session.workQueue.async { + session.taskRegistry.remove(task) + } } } task._protocol = nil @@ -786,18 +792,20 @@ extension _ProtocolClient: URLProtocolClient { session.delegateQueue.addOperation { delegate.urlSession(session, task: task, didCompleteWithError: error as Error) task.state = .completed - task.workQueue.async { + session.workQueue.async { session.taskRegistry.remove(task) } } case .noDelegate: task.state = .completed - session.taskRegistry.remove(task) + session.workQueue.async { + session.taskRegistry.remove(task) + } case .dataCompletionHandler(let completion): session.delegateQueue.addOperation { completion(nil, nil, error) task.state = .completed - task.workQueue.async { + session.workQueue.async { session.taskRegistry.remove(task) } } @@ -805,7 +813,9 @@ extension _ProtocolClient: URLProtocolClient { session.delegateQueue.addOperation { completion(nil, nil, error) task.state = .completed - session.taskRegistry.remove(task) + session.workQueue.async { + session.taskRegistry.remove(task) + } } } task._protocol = nil