ImageDownloaderDelegate.swift 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. //
  2. // ImageDownloaderDelegate.swift
  3. // Kingfisher
  4. //
  5. // Created by Wei Wang on 2018/10/11.
  6. //
  7. // Copyright (c) 2019 Wei Wang <onevcat@gmail.com>
  8. //
  9. // Permission is hereby granted, free of charge, to any person obtaining a copy
  10. // of this software and associated documentation files (the "Software"), to deal
  11. // in the Software without restriction, including without limitation the rights
  12. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. // copies of the Software, and to permit persons to whom the Software is
  14. // furnished to do so, subject to the following conditions:
  15. //
  16. // The above copyright notice and this permission notice shall be included in
  17. // all copies or substantial portions of the Software.
  18. //
  19. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25. // THE SOFTWARE.
  26. import Foundation
  27. #if os(macOS)
  28. import AppKit
  29. #else
  30. import UIKit
  31. #endif
  32. /// Protocol of `ImageDownloader`. This protocol provides a set of methods which are related to image downloader
  33. /// working stages and rules.
  34. public protocol ImageDownloaderDelegate: AnyObject {
  35. /// Called when the `ImageDownloader` object will start downloading an image from a specified URL.
  36. ///
  37. /// - Parameters:
  38. /// - downloader: The `ImageDownloader` object which is used for the downloading operation.
  39. /// - url: URL of the starting request.
  40. /// - request: The request object for the download process.
  41. ///
  42. func imageDownloader(_ downloader: ImageDownloader, willDownloadImageForURL url: URL, with request: URLRequest?)
  43. /// Called when the `ImageDownloader` completes a downloading request with success or failure.
  44. ///
  45. /// - Parameters:
  46. /// - downloader: The `ImageDownloader` object which is used for the downloading operation.
  47. /// - url: URL of the original request URL.
  48. /// - response: The response object of the downloading process.
  49. /// - error: The error in case of failure.
  50. ///
  51. func imageDownloader(
  52. _ downloader: ImageDownloader,
  53. didFinishDownloadingImageForURL url: URL,
  54. with response: URLResponse?,
  55. error: Error?)
  56. /// Called when the `ImageDownloader` object successfully downloaded image data from specified URL. This is
  57. /// your last chance to verify or modify the downloaded data before Kingfisher tries to perform addition
  58. /// processing on the image data.
  59. ///
  60. /// - Parameters:
  61. /// - downloader: The `ImageDownloader` object which is used for the downloading operation.
  62. /// - data: The original downloaded data.
  63. /// - dataTask: The data task contains request and response information of the download.
  64. /// - Note:
  65. /// This can be used to pre-process raw image data before creation of `Image` instance (i.e.
  66. /// decrypting or verification). If `nil` returned, the processing is interrupted and a `KingfisherError` with
  67. /// `ResponseErrorReason.dataModifyingFailed` will be raised. You could use this fact to stop the image
  68. /// processing flow if you find the data is corrupted or malformed.
  69. ///
  70. /// If this method is implemented, `imageDownloader(_:didDownload:for:)` will not be called anymore.
  71. func imageDownloader(_ downloader: ImageDownloader, didDownload data: Data, with dataTask: SessionDataTask) -> Data?
  72. /// Called when the `ImageDownloader` object successfully downloaded image data from specified URL. This is
  73. /// your last chance to verify or modify the downloaded data before Kingfisher tries to perform addition
  74. /// processing on the image data.
  75. ///
  76. /// - Parameters:
  77. /// - downloader: The `ImageDownloader` object which is used for the downloading operation.
  78. /// - data: The original downloaded data.
  79. /// - url: The URL of the original request URL.
  80. /// - Returns: The data from which Kingfisher should use to create an image. You need to provide valid data
  81. /// which content is one of the supported image file format. Kingfisher will perform process on this
  82. /// data and try to convert it to an image object.
  83. /// - Note:
  84. /// This can be used to pre-process raw image data before creation of `Image` instance (i.e.
  85. /// decrypting or verification). If `nil` returned, the processing is interrupted and a `KingfisherError` with
  86. /// `ResponseErrorReason.dataModifyingFailed` will be raised. You could use this fact to stop the image
  87. /// processing flow if you find the data is corrupted or malformed.
  88. ///
  89. /// If `imageDownloader(_:didDownload:with:)` is implemented, this method will not be called anymore.
  90. func imageDownloader(_ downloader: ImageDownloader, didDownload data: Data, for url: URL) -> Data?
  91. /// Called when the `ImageDownloader` object successfully downloads and processes an image from specified URL.
  92. ///
  93. /// - Parameters:
  94. /// - downloader: The `ImageDownloader` object which is used for the downloading operation.
  95. /// - image: The downloaded and processed image.
  96. /// - url: URL of the original request URL.
  97. /// - response: The original response object of the downloading process.
  98. ///
  99. func imageDownloader(
  100. _ downloader: ImageDownloader,
  101. didDownload image: KFCrossPlatformImage,
  102. for url: URL,
  103. with response: URLResponse?)
  104. /// Checks if a received HTTP status code is valid or not.
  105. /// By default, a status code in range 200..<400 is considered as valid.
  106. /// If an invalid code is received, the downloader will raise an `KingfisherError` with
  107. /// `ResponseErrorReason.invalidHTTPStatusCode` as its reason.
  108. ///
  109. /// - Parameters:
  110. /// - code: The received HTTP status code.
  111. /// - downloader: The `ImageDownloader` object asks for validate status code.
  112. /// - Returns: Returns a value to indicate whether this HTTP status code is valid or not.
  113. /// - Note: If the default 200 to 400 valid code does not suit your need,
  114. /// you can implement this method to change that behavior.
  115. func isValidStatusCode(_ code: Int, for downloader: ImageDownloader) -> Bool
  116. /// Called when the task has received a valid HTTP response after it passes other checks such as the status code.
  117. /// You can perform additional checks or verification on the response to determine if the download should be allowed.
  118. ///
  119. /// For example, it is useful if you want to verify some header values in the response before actually starting the
  120. /// download.
  121. ///
  122. /// If implemented, it is your responsibility to call the `completionHandler` with a proper response disposition,
  123. /// such as `.allow` to start the actual downloading or `.cancel` to cancel the task. If `.cancel` is used as the
  124. /// disposition, the downloader will raise an `KingfisherError` with
  125. /// `ResponseErrorReason.cancelledByDelegate` as its reason. If not implemented, any response which passes other
  126. /// checked will be allowed and the download starts.
  127. ///
  128. /// - Parameters:
  129. /// - downloader: The `ImageDownloader` object which is used for the downloading operation.
  130. /// - response: The original response object of the downloading process.
  131. /// - completionHandler: A completion handler that receives the disposition for the download task. You must call
  132. /// this handler with either `.allow` or `.cancel`.
  133. func imageDownloader(
  134. _ downloader: ImageDownloader,
  135. didReceive response: URLResponse,
  136. completionHandler: @escaping (URLSession.ResponseDisposition) -> Void)
  137. }
  138. // Default implementation for `ImageDownloaderDelegate`.
  139. extension ImageDownloaderDelegate {
  140. public func imageDownloader(
  141. _ downloader: ImageDownloader,
  142. willDownloadImageForURL url: URL,
  143. with request: URLRequest?) {}
  144. public func imageDownloader(
  145. _ downloader: ImageDownloader,
  146. didFinishDownloadingImageForURL url: URL,
  147. with response: URLResponse?,
  148. error: Error?) {}
  149. public func imageDownloader(
  150. _ downloader: ImageDownloader,
  151. didDownload image: KFCrossPlatformImage,
  152. for url: URL,
  153. with response: URLResponse?) {}
  154. public func isValidStatusCode(_ code: Int, for downloader: ImageDownloader) -> Bool {
  155. return (200..<400).contains(code)
  156. }
  157. public func imageDownloader(_ downloader: ImageDownloader, didDownload data: Data, with task: SessionDataTask) -> Data? {
  158. guard let url = task.originalURL else {
  159. return data
  160. }
  161. return imageDownloader(downloader, didDownload: data, for: url)
  162. }
  163. public func imageDownloader(_ downloader: ImageDownloader, didDownload data: Data, for url: URL) -> Data? {
  164. return data
  165. }
  166. public func imageDownloader(
  167. _ downloader: ImageDownloader,
  168. didReceive response: URLResponse,
  169. completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) {
  170. completionHandler(.allow)
  171. }
  172. }