Response.swift 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. //
  2. // Response.swift
  3. //
  4. // Copyright (c) 2014-2016 Alamofire Software Foundation (http://alamofire.org/)
  5. //
  6. // Permission is hereby granted, free of charge, to any person obtaining a copy
  7. // of this software and associated documentation files (the "Software"), to deal
  8. // in the Software without restriction, including without limitation the rights
  9. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. // copies of the Software, and to permit persons to whom the Software is
  11. // furnished to do so, subject to the following conditions:
  12. //
  13. // The above copyright notice and this permission notice shall be included in
  14. // all copies or substantial portions of the Software.
  15. //
  16. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. // THE SOFTWARE.
  23. //
  24. import Foundation
  25. /// Used to store all data associated with an non-serialized response of a data or upload request.
  26. public struct DefaultDataResponse {
  27. /// The URL request sent to the server.
  28. public let request: URLRequest?
  29. /// The server's response to the URL request.
  30. public let response: HTTPURLResponse?
  31. /// The data returned by the server.
  32. public let data: Data?
  33. /// The error encountered while executing or validating the request.
  34. public let error: Error?
  35. /// The timeline of the complete lifecycle of the request.
  36. public let timeline: Timeline
  37. var _metrics: AnyObject?
  38. /// Creates a `DefaultDataResponse` instance from the specified parameters.
  39. ///
  40. /// - Parameters:
  41. /// - request: The URL request sent to the server.
  42. /// - response: The server's response to the URL request.
  43. /// - data: The data returned by the server.
  44. /// - error: The error encountered while executing or validating the request.
  45. /// - timeline: The timeline of the complete lifecycle of the request. `Timeline()` by default.
  46. /// - metrics: The task metrics containing the request / response statistics. `nil` by default.
  47. public init(
  48. request: URLRequest?,
  49. response: HTTPURLResponse?,
  50. data: Data?,
  51. error: Error?,
  52. timeline: Timeline = Timeline(),
  53. metrics: AnyObject? = nil)
  54. {
  55. self.request = request
  56. self.response = response
  57. self.data = data
  58. self.error = error
  59. self.timeline = timeline
  60. }
  61. }
  62. // MARK: -
  63. /// Used to store all data associated with a serialized response of a data or upload request.
  64. public struct DataResponse<Value> {
  65. /// The URL request sent to the server.
  66. public let request: URLRequest?
  67. /// The server's response to the URL request.
  68. public let response: HTTPURLResponse?
  69. /// The data returned by the server.
  70. public let data: Data?
  71. /// The result of response serialization.
  72. public let result: Result<Value>
  73. /// The timeline of the complete lifecycle of the request.
  74. public let timeline: Timeline
  75. /// Returns the associated value of the result if it is a success, `nil` otherwise.
  76. public var value: Value? { return result.value }
  77. /// Returns the associated error value if the result if it is a failure, `nil` otherwise.
  78. public var error: Error? { return result.error }
  79. var _metrics: AnyObject?
  80. /// Creates a `DataResponse` instance with the specified parameters derived from response serialization.
  81. ///
  82. /// - parameter request: The URL request sent to the server.
  83. /// - parameter response: The server's response to the URL request.
  84. /// - parameter data: The data returned by the server.
  85. /// - parameter result: The result of response serialization.
  86. /// - parameter timeline: The timeline of the complete lifecycle of the `Request`. Defaults to `Timeline()`.
  87. ///
  88. /// - returns: The new `DataResponse` instance.
  89. public init(
  90. request: URLRequest?,
  91. response: HTTPURLResponse?,
  92. data: Data?,
  93. result: Result<Value>,
  94. timeline: Timeline = Timeline())
  95. {
  96. self.request = request
  97. self.response = response
  98. self.data = data
  99. self.result = result
  100. self.timeline = timeline
  101. }
  102. }
  103. // MARK: -
  104. extension DataResponse: CustomStringConvertible, CustomDebugStringConvertible {
  105. /// The textual representation used when written to an output stream, which includes whether the result was a
  106. /// success or failure.
  107. public var description: String {
  108. return result.debugDescription
  109. }
  110. /// The debug textual representation used when written to an output stream, which includes the URL request, the URL
  111. /// response, the server data, the response serialization result and the timeline.
  112. public var debugDescription: String {
  113. var output: [String] = []
  114. output.append(request != nil ? "[Request]: \(request!.httpMethod ?? "GET") \(request!)" : "[Request]: nil")
  115. output.append(response != nil ? "[Response]: \(response!)" : "[Response]: nil")
  116. output.append("[Data]: \(data?.count ?? 0) bytes")
  117. output.append("[Result]: \(result.debugDescription)")
  118. output.append("[Timeline]: \(timeline.debugDescription)")
  119. return output.joined(separator: "\n")
  120. }
  121. }
  122. // MARK: -
  123. extension DataResponse {
  124. /// Evaluates the specified closure when the result of this `DataResponse` is a success, passing the unwrapped
  125. /// result value as a parameter.
  126. ///
  127. /// Use the `map` method with a closure that does not throw. For example:
  128. ///
  129. /// let possibleData: DataResponse<Data> = ...
  130. /// let possibleInt = possibleData.map { $0.count }
  131. ///
  132. /// - parameter transform: A closure that takes the success value of the instance's result.
  133. ///
  134. /// - returns: A `DataResponse` whose result wraps the value returned by the given closure. If this instance's
  135. /// result is a failure, returns a response wrapping the same failure.
  136. public func map<T>(_ transform: (Value) -> T) -> DataResponse<T> {
  137. var response = DataResponse<T>(
  138. request: request,
  139. response: self.response,
  140. data: data,
  141. result: result.map(transform),
  142. timeline: timeline
  143. )
  144. response._metrics = _metrics
  145. return response
  146. }
  147. /// Evaluates the given closure when the result of this `DataResponse` is a success, passing the unwrapped result
  148. /// value as a parameter.
  149. ///
  150. /// Use the `flatMap` method with a closure that may throw an error. For example:
  151. ///
  152. /// let possibleData: DataResponse<Data> = ...
  153. /// let possibleObject = possibleData.flatMap {
  154. /// try JSONSerialization.jsonObject(with: $0)
  155. /// }
  156. ///
  157. /// - parameter transform: A closure that takes the success value of the instance's result.
  158. ///
  159. /// - returns: A success or failure `DataResponse` depending on the result of the given closure. If this instance's
  160. /// result is a failure, returns the same failure.
  161. public func flatMap<T>(_ transform: (Value) throws -> T) -> DataResponse<T> {
  162. var response = DataResponse<T>(
  163. request: request,
  164. response: self.response,
  165. data: data,
  166. result: result.flatMap(transform),
  167. timeline: timeline
  168. )
  169. response._metrics = _metrics
  170. return response
  171. }
  172. }
  173. // MARK: -
  174. /// Used to store all data associated with an non-serialized response of a download request.
  175. public struct DefaultDownloadResponse {
  176. /// The URL request sent to the server.
  177. public let request: URLRequest?
  178. /// The server's response to the URL request.
  179. public let response: HTTPURLResponse?
  180. /// The temporary destination URL of the data returned from the server.
  181. public let temporaryURL: URL?
  182. /// The final destination URL of the data returned from the server if it was moved.
  183. public let destinationURL: URL?
  184. /// The resume data generated if the request was cancelled.
  185. public let resumeData: Data?
  186. /// The error encountered while executing or validating the request.
  187. public let error: Error?
  188. /// The timeline of the complete lifecycle of the request.
  189. public let timeline: Timeline
  190. var _metrics: AnyObject?
  191. /// Creates a `DefaultDownloadResponse` instance from the specified parameters.
  192. ///
  193. /// - Parameters:
  194. /// - request: The URL request sent to the server.
  195. /// - response: The server's response to the URL request.
  196. /// - temporaryURL: The temporary destination URL of the data returned from the server.
  197. /// - destinationURL: The final destination URL of the data returned from the server if it was moved.
  198. /// - resumeData: The resume data generated if the request was cancelled.
  199. /// - error: The error encountered while executing or validating the request.
  200. /// - timeline: The timeline of the complete lifecycle of the request. `Timeline()` by default.
  201. /// - metrics: The task metrics containing the request / response statistics. `nil` by default.
  202. public init(
  203. request: URLRequest?,
  204. response: HTTPURLResponse?,
  205. temporaryURL: URL?,
  206. destinationURL: URL?,
  207. resumeData: Data?,
  208. error: Error?,
  209. timeline: Timeline = Timeline(),
  210. metrics: AnyObject? = nil)
  211. {
  212. self.request = request
  213. self.response = response
  214. self.temporaryURL = temporaryURL
  215. self.destinationURL = destinationURL
  216. self.resumeData = resumeData
  217. self.error = error
  218. self.timeline = timeline
  219. }
  220. }
  221. // MARK: -
  222. /// Used to store all data associated with a serialized response of a download request.
  223. public struct DownloadResponse<Value> {
  224. /// The URL request sent to the server.
  225. public let request: URLRequest?
  226. /// The server's response to the URL request.
  227. public let response: HTTPURLResponse?
  228. /// The temporary destination URL of the data returned from the server.
  229. public let temporaryURL: URL?
  230. /// The final destination URL of the data returned from the server if it was moved.
  231. public let destinationURL: URL?
  232. /// The resume data generated if the request was cancelled.
  233. public let resumeData: Data?
  234. /// The result of response serialization.
  235. public let result: Result<Value>
  236. /// The timeline of the complete lifecycle of the request.
  237. public let timeline: Timeline
  238. /// Returns the associated value of the result if it is a success, `nil` otherwise.
  239. public var value: Value? { return result.value }
  240. /// Returns the associated error value if the result if it is a failure, `nil` otherwise.
  241. public var error: Error? { return result.error }
  242. var _metrics: AnyObject?
  243. /// Creates a `DownloadResponse` instance with the specified parameters derived from response serialization.
  244. ///
  245. /// - parameter request: The URL request sent to the server.
  246. /// - parameter response: The server's response to the URL request.
  247. /// - parameter temporaryURL: The temporary destination URL of the data returned from the server.
  248. /// - parameter destinationURL: The final destination URL of the data returned from the server if it was moved.
  249. /// - parameter resumeData: The resume data generated if the request was cancelled.
  250. /// - parameter result: The result of response serialization.
  251. /// - parameter timeline: The timeline of the complete lifecycle of the `Request`. Defaults to `Timeline()`.
  252. ///
  253. /// - returns: The new `DownloadResponse` instance.
  254. public init(
  255. request: URLRequest?,
  256. response: HTTPURLResponse?,
  257. temporaryURL: URL?,
  258. destinationURL: URL?,
  259. resumeData: Data?,
  260. result: Result<Value>,
  261. timeline: Timeline = Timeline())
  262. {
  263. self.request = request
  264. self.response = response
  265. self.temporaryURL = temporaryURL
  266. self.destinationURL = destinationURL
  267. self.resumeData = resumeData
  268. self.result = result
  269. self.timeline = timeline
  270. }
  271. }
  272. // MARK: -
  273. extension DownloadResponse: CustomStringConvertible, CustomDebugStringConvertible {
  274. /// The textual representation used when written to an output stream, which includes whether the result was a
  275. /// success or failure.
  276. public var description: String {
  277. return result.debugDescription
  278. }
  279. /// The debug textual representation used when written to an output stream, which includes the URL request, the URL
  280. /// response, the temporary and destination URLs, the resume data, the response serialization result and the
  281. /// timeline.
  282. public var debugDescription: String {
  283. var output: [String] = []
  284. output.append(request != nil ? "[Request]: \(request!.httpMethod ?? "GET") \(request!)" : "[Request]: nil")
  285. output.append(response != nil ? "[Response]: \(response!)" : "[Response]: nil")
  286. output.append("[TemporaryURL]: \(temporaryURL?.path ?? "nil")")
  287. output.append("[DestinationURL]: \(destinationURL?.path ?? "nil")")
  288. output.append("[ResumeData]: \(resumeData?.count ?? 0) bytes")
  289. output.append("[Result]: \(result.debugDescription)")
  290. output.append("[Timeline]: \(timeline.debugDescription)")
  291. return output.joined(separator: "\n")
  292. }
  293. }
  294. // MARK: -
  295. extension DownloadResponse {
  296. /// Evaluates the given closure when the result of this `DownloadResponse` is a success, passing the unwrapped
  297. /// result value as a parameter.
  298. ///
  299. /// Use the `map` method with a closure that does not throw. For example:
  300. ///
  301. /// let possibleData: DownloadResponse<Data> = ...
  302. /// let possibleInt = possibleData.map { $0.count }
  303. ///
  304. /// - parameter transform: A closure that takes the success value of the instance's result.
  305. ///
  306. /// - returns: A `DownloadResponse` whose result wraps the value returned by the given closure. If this instance's
  307. /// result is a failure, returns a response wrapping the same failure.
  308. public func map<T>(_ transform: (Value) -> T) -> DownloadResponse<T> {
  309. var response = DownloadResponse<T>(
  310. request: request,
  311. response: self.response,
  312. temporaryURL: temporaryURL,
  313. destinationURL: destinationURL,
  314. resumeData: resumeData,
  315. result: result.map(transform),
  316. timeline: timeline
  317. )
  318. response._metrics = _metrics
  319. return response
  320. }
  321. /// Evaluates the given closure when the result of this `DownloadResponse` is a success, passing the unwrapped
  322. /// result value as a parameter.
  323. ///
  324. /// Use the `flatMap` method with a closure that may throw an error. For example:
  325. ///
  326. /// let possibleData: DownloadResponse<Data> = ...
  327. /// let possibleObject = possibleData.flatMap {
  328. /// try JSONSerialization.jsonObject(with: $0)
  329. /// }
  330. ///
  331. /// - parameter transform: A closure that takes the success value of the instance's result.
  332. ///
  333. /// - returns: A success or failure `DownloadResponse` depending on the result of the given closure. If this
  334. /// instance's result is a failure, returns the same failure.
  335. public func flatMap<T>(_ transform: (Value) throws -> T) -> DownloadResponse<T> {
  336. var response = DownloadResponse<T>(
  337. request: request,
  338. response: self.response,
  339. temporaryURL: temporaryURL,
  340. destinationURL: destinationURL,
  341. resumeData: resumeData,
  342. result: result.flatMap(transform),
  343. timeline: timeline
  344. )
  345. response._metrics = _metrics
  346. return response
  347. }
  348. }
  349. // MARK: -
  350. protocol Response {
  351. /// The task metrics containing the request / response statistics.
  352. var _metrics: AnyObject? { get set }
  353. mutating func add(_ metrics: AnyObject?)
  354. }
  355. extension Response {
  356. mutating func add(_ metrics: AnyObject?) {
  357. #if !os(watchOS)
  358. guard #available(iOS 10.0, macOS 10.12, tvOS 10.0, *) else { return }
  359. guard let metrics = metrics as? URLSessionTaskMetrics else { return }
  360. _metrics = metrics
  361. #endif
  362. }
  363. }
  364. // MARK: -
  365. @available(iOS 10.0, macOS 10.12, tvOS 10.0, *)
  366. extension DefaultDataResponse: Response {
  367. #if !os(watchOS)
  368. /// The task metrics containing the request / response statistics.
  369. public var metrics: URLSessionTaskMetrics? { return _metrics as? URLSessionTaskMetrics }
  370. #endif
  371. }
  372. @available(iOS 10.0, macOS 10.12, tvOS 10.0, *)
  373. extension DataResponse: Response {
  374. #if !os(watchOS)
  375. /// The task metrics containing the request / response statistics.
  376. public var metrics: URLSessionTaskMetrics? { return _metrics as? URLSessionTaskMetrics }
  377. #endif
  378. }
  379. @available(iOS 10.0, macOS 10.12, tvOS 10.0, *)
  380. extension DefaultDownloadResponse: Response {
  381. #if !os(watchOS)
  382. /// The task metrics containing the request / response statistics.
  383. public var metrics: URLSessionTaskMetrics? { return _metrics as? URLSessionTaskMetrics }
  384. #endif
  385. }
  386. @available(iOS 10.0, macOS 10.12, tvOS 10.0, *)
  387. extension DownloadResponse: Response {
  388. #if !os(watchOS)
  389. /// The task metrics containing the request / response statistics.
  390. public var metrics: URLSessionTaskMetrics? { return _metrics as? URLSessionTaskMetrics }
  391. #endif
  392. }