diff --git a/Account/Sources/Account/LocalAccount/LocalAccountRefresher.swift b/Account/Sources/Account/LocalAccount/LocalAccountRefresher.swift index 95446be79..fe39de0aa 100644 --- a/Account/Sources/Account/LocalAccount/LocalAccountRefresher.swift +++ b/Account/Sources/Account/LocalAccount/LocalAccountRefresher.swift @@ -72,14 +72,29 @@ final class LocalAccountRefresher { extension LocalAccountRefresher: DownloadSessionDelegate { + func downloadSession(_ downloadSession: DownloadSession, conditionalGetInfoFor url: URL) -> HTTPConditionalGetInfo? { + + guard let feed = urlToFeedDictionary[url.absoluteString] else { + return nil + } + return feed.conditionalGetInfo + } + func downloadSession(_ downloadSession: DownloadSession, downloadDidComplete url: URL, response: URLResponse?, data: Data, error: NSError?) { + guard !isSuspended else { + return + } guard let feed = urlToFeedDictionary[url.absoluteString] else { return } - guard !data.isEmpty, !isSuspended else { - return - } + + let conditionalGetInfo: HTTPConditionalGetInfo? = { + if let httpResponse = response as? HTTPURLResponse { + return HTTPConditionalGetInfo(urlResponse: httpResponse) + } + return nil + }() if let error { os_log(.debug, "Error downloading \(url) - \(error)") @@ -88,6 +103,10 @@ extension LocalAccountRefresher: DownloadSessionDelegate { let dataHash = data.md5String if dataHash == feed.contentHash { + // It’s possible that the conditional get info has changed even if the + // content hasn’t changed. + // https://inessential.com/2024/08/03/netnewswire_and_conditional_get_issues.html + feed.conditionalGetInfo = conditionalGetInfo return } @@ -101,6 +120,7 @@ extension LocalAccountRefresher: DownloadSessionDelegate { account.update(feed, with: parsedFeed) { result in if case .success(let articleChanges) = result { feed.contentHash = dataHash + feed.conditionalGetInfo = conditionalGetInfo self.delegate?.localAccountRefresher(self, articleChanges: articleChanges) } } diff --git a/RSWeb/Sources/RSWeb/DownloadSession.swift b/RSWeb/Sources/RSWeb/DownloadSession.swift index fb9c0b868..cf9d14db5 100755 --- a/RSWeb/Sources/RSWeb/DownloadSession.swift +++ b/RSWeb/Sources/RSWeb/DownloadSession.swift @@ -13,6 +13,7 @@ import Foundation public protocol DownloadSessionDelegate { + func downloadSession(_ downloadSession: DownloadSession, conditionalGetInfoFor: URL) -> HTTPConditionalGetInfo? func downloadSession(_ downloadSession: DownloadSession, downloadDidComplete: URL, response: URLResponse?, data: Data, error: NSError?) func downloadSession(_ downloadSession: DownloadSession, shouldContinueAfterReceivingData: Data, url: URL) -> Bool func downloadSessionDidComplete(_ downloadSession: DownloadSession) @@ -44,13 +45,14 @@ public protocol DownloadSessionDelegate { super.init() - let sessionConfiguration = URLSessionConfiguration.default - sessionConfiguration.requestCachePolicy = .useProtocolCachePolicy + let sessionConfiguration = URLSessionConfiguration.ephemeral + sessionConfiguration.requestCachePolicy = .reloadIgnoringLocalCacheData sessionConfiguration.timeoutIntervalForRequest = 15.0 sessionConfiguration.httpShouldSetCookies = false sessionConfiguration.httpCookieAcceptPolicy = .never sessionConfiguration.httpMaximumConnectionsPerHost = 1 sessionConfiguration.httpCookieStorage = nil + sessionConfiguration.urlCache = nil if let userAgentHeaders = UserAgent.headers() { sessionConfiguration.httpAdditionalHeaders = userAgentHeaders @@ -186,6 +188,11 @@ private extension DownloadSession { return } + var urlRequest = URLRequest(url: urlToUse) + if let conditionalGetInfo = delegate.downloadSession(self, conditionalGetInfoFor: url) { + conditionalGetInfo.addRequestHeadersToURLRequest(&urlRequest) + } + let task = urlSession.dataTask(with: urlToUse) let info = DownloadInfo(url)