diff --git a/Modules/RSWeb/Sources/RSWeb/Downloader.swift b/Modules/RSWeb/Sources/RSWeb/Downloader.swift index f82638246..b8362e07e 100755 --- a/Modules/RSWeb/Sources/RSWeb/Downloader.swift +++ b/Modules/RSWeb/Sources/RSWeb/Downloader.swift @@ -23,7 +23,6 @@ public typealias DownloadCallback = @MainActor (Data?, URLResponse?, Error?) -> private static let debugLoggingEnabled = true private init() { - let sessionConfiguration = URLSessionConfiguration.ephemeral sessionConfiguration.requestCachePolicy = .reloadIgnoringLocalCacheData sessionConfiguration.httpShouldSetCookies = false @@ -54,50 +53,65 @@ public typealias DownloadCallback = @MainActor (Data?, URLResponse?, Error?) -> return } - if callbacks[url] == nil { - if Self.debugLoggingEnabled { - Self.logger.debug("Downloader: downloading \(url)") - } - callbacks[url] = [completion] - } else { - // A download is already be in progress for this URL. Don’t start a separate download. - // Add the callback to the callbacks array for this URL. - if Self.debugLoggingEnabled { - Self.logger.debug("Downloader: download in progress for \(url) — adding callback") - } - callbacks[url]?.append(completion) - return - } + addCallback(url: url, callback: completion) var urlRequestToUse = urlRequest urlRequestToUse.addSpecialCaseUserAgentIfNeeded() let task = urlSession.dataTask(with: urlRequestToUse) { (data, response, error) in Task { @MainActor in - let callbacksForURL = self.callbacks[url] - assert(callbacksForURL != nil) - - if let callbacksForURL { - if Self.debugLoggingEnabled { - let count = callbacksForURL.count - if count == 1 { - Self.logger.debug("Downloader: calling 1 callback for URL \(url)") - } else { - Self.logger.debug("Downloader: calling \(callbacksForURL.count) callbacks for URL \(url)") - } - } - - for completion in callbacksForURL { - completion(data, response, error) - } - } else { - assertionFailure("Downloader: downloaded URL \(url) but no callbacks found") - Self.logger.fault("Downloader: downloaded URL \(url) but no callbacks found") - } - - self.callbacks[url] = nil + self.callAndReleaseCallbacks(url, data, response, error) } } task.resume() } } + +private extension Downloader { + + func addCallback(url: URL, callback: @escaping DownloadCallback) { + assert(Thread.isMainThread) + + if callbacks[url] == nil { + if Self.debugLoggingEnabled { + Self.logger.debug("Downloader: downloading \(url)") + } + callbacks[url] = [callback] + } else { + // A download is already be in progress for this URL. Don’t start a separate download. + // Add the callback to the callbacks array for this URL. + if Self.debugLoggingEnabled { + Self.logger.debug("Downloader: download in progress for \(url) — adding callback") + } + callbacks[url]?.append(callback) + return + } + } + + func callAndReleaseCallbacks(_ url: URL, _ data: Data? = nil, _ response: URLResponse? = nil, _ error: Error? = nil) { + assert(Thread.isMainThread) + + defer { + callbacks[url] = nil + } + + guard let callbacksForURL = callbacks[url] else { + assertionFailure("Downloader: downloaded URL \(url) but no callbacks found") + Self.logger.fault("Downloader: downloaded URL \(url) but no callbacks found") + return + } + + if Self.debugLoggingEnabled { + let count = callbacksForURL.count + if count == 1 { + Self.logger.debug("Downloader: calling 1 callback for URL \(url)") + } else { + Self.logger.debug("Downloader: calling \(count) callbacks for URL \(url)") + } + } + + for callback in callbacksForURL { + callback(data, response, error) + } + } +}