You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

567 lines
21 KiB

6 years ago
  1. //
  2. // Response.swift
  3. //
  4. // Copyright (c) 2014-2018 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. /// Evaluates the specified closure when the `DataResponse` is a failure, passing the unwrapped error as a parameter.
  173. ///
  174. /// Use the `mapError` function with a closure that does not throw. For example:
  175. ///
  176. /// let possibleData: DataResponse<Data> = ...
  177. /// let withMyError = possibleData.mapError { MyError.error($0) }
  178. ///
  179. /// - Parameter transform: A closure that takes the error of the instance.
  180. /// - Returns: A `DataResponse` instance containing the result of the transform.
  181. public func mapError<E: Error>(_ transform: (Error) -> E) -> DataResponse {
  182. var response = DataResponse(
  183. request: request,
  184. response: self.response,
  185. data: data,
  186. result: result.mapError(transform),
  187. timeline: timeline
  188. )
  189. response._metrics = _metrics
  190. return response
  191. }
  192. /// Evaluates the specified closure when the `DataResponse` is a failure, passing the unwrapped error as a parameter.
  193. ///
  194. /// Use the `flatMapError` function with a closure that may throw an error. For example:
  195. ///
  196. /// let possibleData: DataResponse<Data> = ...
  197. /// let possibleObject = possibleData.flatMapError {
  198. /// try someFailableFunction(taking: $0)
  199. /// }
  200. ///
  201. /// - Parameter transform: A throwing closure that takes the error of the instance.
  202. ///
  203. /// - Returns: A `DataResponse` instance containing the result of the transform.
  204. public func flatMapError<E: Error>(_ transform: (Error) throws -> E) -> DataResponse {
  205. var response = DataResponse(
  206. request: request,
  207. response: self.response,
  208. data: data,
  209. result: result.flatMapError(transform),
  210. timeline: timeline
  211. )
  212. response._metrics = _metrics
  213. return response
  214. }
  215. }
  216. // MARK: -
  217. /// Used to store all data associated with an non-serialized response of a download request.
  218. public struct DefaultDownloadResponse {
  219. /// The URL request sent to the server.
  220. public let request: URLRequest?
  221. /// The server's response to the URL request.
  222. public let response: HTTPURLResponse?
  223. /// The temporary destination URL of the data returned from the server.
  224. public let temporaryURL: URL?
  225. /// The final destination URL of the data returned from the server if it was moved.
  226. public let destinationURL: URL?
  227. /// The resume data generated if the request was cancelled.
  228. public let resumeData: Data?
  229. /// The error encountered while executing or validating the request.
  230. public let error: Error?
  231. /// The timeline of the complete lifecycle of the request.
  232. public let timeline: Timeline
  233. var _metrics: AnyObject?
  234. /// Creates a `DefaultDownloadResponse` instance from the specified parameters.
  235. ///
  236. /// - Parameters:
  237. /// - request: The URL request sent to the server.
  238. /// - response: The server's response to the URL request.
  239. /// - temporaryURL: The temporary destination URL of the data returned from the server.
  240. /// - destinationURL: The final destination URL of the data returned from the server if it was moved.
  241. /// - resumeData: The resume data generated if the request was cancelled.
  242. /// - error: The error encountered while executing or validating the request.
  243. /// - timeline: The timeline of the complete lifecycle of the request. `Timeline()` by default.
  244. /// - metrics: The task metrics containing the request / response statistics. `nil` by default.
  245. public init(
  246. request: URLRequest?,
  247. response: HTTPURLResponse?,
  248. temporaryURL: URL?,
  249. destinationURL: URL?,
  250. resumeData: Data?,
  251. error: Error?,
  252. timeline: Timeline = Timeline(),
  253. metrics: AnyObject? = nil)
  254. {
  255. self.request = request
  256. self.response = response
  257. self.temporaryURL = temporaryURL
  258. self.destinationURL = destinationURL
  259. self.resumeData = resumeData
  260. self.error = error
  261. self.timeline = timeline
  262. }
  263. }
  264. // MARK: -
  265. /// Used to store all data associated with a serialized response of a download request.
  266. public struct DownloadResponse<Value> {
  267. /// The URL request sent to the server.
  268. public let request: URLRequest?
  269. /// The server's response to the URL request.
  270. public let response: HTTPURLResponse?
  271. /// The temporary destination URL of the data returned from the server.
  272. public let temporaryURL: URL?
  273. /// The final destination URL of the data returned from the server if it was moved.
  274. public let destinationURL: URL?
  275. /// The resume data generated if the request was cancelled.
  276. public let resumeData: Data?
  277. /// The result of response serialization.
  278. public let result: Result<Value>
  279. /// The timeline of the complete lifecycle of the request.
  280. public let timeline: Timeline
  281. /// Returns the associated value of the result if it is a success, `nil` otherwise.
  282. public var value: Value? { return result.value }
  283. /// Returns the associated error value if the result if it is a failure, `nil` otherwise.
  284. public var error: Error? { return result.error }
  285. var _metrics: AnyObject?
  286. /// Creates a `DownloadResponse` instance with the specified parameters derived from response serialization.
  287. ///
  288. /// - parameter request: The URL request sent to the server.
  289. /// - parameter response: The server's response to the URL request.
  290. /// - parameter temporaryURL: The temporary destination URL of the data returned from the server.
  291. /// - parameter destinationURL: The final destination URL of the data returned from the server if it was moved.
  292. /// - parameter resumeData: The resume data generated if the request was cancelled.
  293. /// - parameter result: The result of response serialization.
  294. /// - parameter timeline: The timeline of the complete lifecycle of the `Request`. Defaults to `Timeline()`.
  295. ///
  296. /// - returns: The new `DownloadResponse` instance.
  297. public init(
  298. request: URLRequest?,
  299. response: HTTPURLResponse?,
  300. temporaryURL: URL?,
  301. destinationURL: URL?,
  302. resumeData: Data?,
  303. result: Result<Value>,
  304. timeline: Timeline = Timeline())
  305. {
  306. self.request = request
  307. self.response = response
  308. self.temporaryURL = temporaryURL
  309. self.destinationURL = destinationURL
  310. self.resumeData = resumeData
  311. self.result = result
  312. self.timeline = timeline
  313. }
  314. }
  315. // MARK: -
  316. extension DownloadResponse: CustomStringConvertible, CustomDebugStringConvertible {
  317. /// The textual representation used when written to an output stream, which includes whether the result was a
  318. /// success or failure.
  319. public var description: String {
  320. return result.debugDescription
  321. }
  322. /// The debug textual representation used when written to an output stream, which includes the URL request, the URL
  323. /// response, the temporary and destination URLs, the resume data, the response serialization result and the
  324. /// timeline.
  325. public var debugDescription: String {
  326. var output: [String] = []
  327. output.append(request != nil ? "[Request]: \(request!.httpMethod ?? "GET") \(request!)" : "[Request]: nil")
  328. output.append(response != nil ? "[Response]: \(response!)" : "[Response]: nil")
  329. output.append("[TemporaryURL]: \(temporaryURL?.path ?? "nil")")
  330. output.append("[DestinationURL]: \(destinationURL?.path ?? "nil")")
  331. output.append("[ResumeData]: \(resumeData?.count ?? 0) bytes")
  332. output.append("[Result]: \(result.debugDescription)")
  333. output.append("[Timeline]: \(timeline.debugDescription)")
  334. return output.joined(separator: "\n")
  335. }
  336. }
  337. // MARK: -
  338. extension DownloadResponse {
  339. /// Evaluates the given closure when the result of this `DownloadResponse` is a success, passing the unwrapped
  340. /// result value as a parameter.
  341. ///
  342. /// Use the `map` method with a closure that does not throw. For example:
  343. ///
  344. /// let possibleData: DownloadResponse<Data> = ...
  345. /// let possibleInt = possibleData.map { $0.count }
  346. ///
  347. /// - parameter transform: A closure that takes the success value of the instance's result.
  348. ///
  349. /// - returns: A `DownloadResponse` whose result wraps the value returned by the given closure. If this instance's
  350. /// result is a failure, returns a response wrapping the same failure.
  351. public func map<T>(_ transform: (Value) -> T) -> DownloadResponse<T> {
  352. var response = DownloadResponse<T>(
  353. request: request,
  354. response: self.response,
  355. temporaryURL: temporaryURL,
  356. destinationURL: destinationURL,
  357. resumeData: resumeData,
  358. result: result.map(transform),
  359. timeline: timeline
  360. )
  361. response._metrics = _metrics
  362. return response
  363. }
  364. /// Evaluates the given closure when the result of this `DownloadResponse` is a success, passing the unwrapped
  365. /// result value as a parameter.
  366. ///
  367. /// Use the `flatMap` method with a closure that may throw an error. For example:
  368. ///
  369. /// let possibleData: DownloadResponse<Data> = ...
  370. /// let possibleObject = possibleData.flatMap {
  371. /// try JSONSerialization.jsonObject(with: $0)
  372. /// }
  373. ///
  374. /// - parameter transform: A closure that takes the success value of the instance's result.
  375. ///
  376. /// - returns: A success or failure `DownloadResponse` depending on the result of the given closure. If this
  377. /// instance's result is a failure, returns the same failure.
  378. public func flatMap<T>(_ transform: (Value) throws -> T) -> DownloadResponse<T> {
  379. var response = DownloadResponse<T>(
  380. request: request,
  381. response: self.response,
  382. temporaryURL: temporaryURL,
  383. destinationURL: destinationURL,
  384. resumeData: resumeData,
  385. result: result.flatMap(transform),
  386. timeline: timeline
  387. )
  388. response._metrics = _metrics
  389. return response
  390. }
  391. /// Evaluates the specified closure when the `DownloadResponse` is a failure, passing the unwrapped error as a parameter.
  392. ///
  393. /// Use the `mapError` function with a closure that does not throw. For example:
  394. ///
  395. /// let possibleData: DownloadResponse<Data> = ...
  396. /// let withMyError = possibleData.mapError { MyError.error($0) }
  397. ///
  398. /// - Parameter transform: A closure that takes the error of the instance.
  399. /// - Returns: A `DownloadResponse` instance containing the result of the transform.
  400. public func mapError<E: Error>(_ transform: (Error) -> E) -> DownloadResponse {
  401. var response = DownloadResponse(
  402. request: request,
  403. response: self.response,
  404. temporaryURL: temporaryURL,
  405. destinationURL: destinationURL,
  406. resumeData: resumeData,
  407. result: result.mapError(transform),
  408. timeline: timeline
  409. )
  410. response._metrics = _metrics
  411. return response
  412. }
  413. /// Evaluates the specified closure when the `DownloadResponse` is a failure, passing the unwrapped error as a parameter.
  414. ///
  415. /// Use the `flatMapError` function with a closure that may throw an error. For example:
  416. ///
  417. /// let possibleData: DownloadResponse<Data> = ...
  418. /// let possibleObject = possibleData.flatMapError {
  419. /// try someFailableFunction(taking: $0)
  420. /// }
  421. ///
  422. /// - Parameter transform: A throwing closure that takes the error of the instance.
  423. ///
  424. /// - Returns: A `DownloadResponse` instance containing the result of the transform.
  425. public func flatMapError<E: Error>(_ transform: (Error) throws -> E) -> DownloadResponse {
  426. var response = DownloadResponse(
  427. request: request,
  428. response: self.response,
  429. temporaryURL: temporaryURL,
  430. destinationURL: destinationURL,
  431. resumeData: resumeData,
  432. result: result.flatMapError(transform),
  433. timeline: timeline
  434. )
  435. response._metrics = _metrics
  436. return response
  437. }
  438. }
  439. // MARK: -
  440. protocol Response {
  441. /// The task metrics containing the request / response statistics.
  442. var _metrics: AnyObject? { get set }
  443. mutating func add(_ metrics: AnyObject?)
  444. }
  445. extension Response {
  446. mutating func add(_ metrics: AnyObject?) {
  447. #if !os(watchOS)
  448. guard #available(iOS 10.0, macOS 10.12, tvOS 10.0, *) else { return }
  449. guard let metrics = metrics as? URLSessionTaskMetrics else { return }
  450. _metrics = metrics
  451. #endif
  452. }
  453. }
  454. // MARK: -
  455. @available(iOS 10.0, macOS 10.12, tvOS 10.0, *)
  456. extension DefaultDataResponse: Response {
  457. #if !os(watchOS)
  458. /// The task metrics containing the request / response statistics.
  459. public var metrics: URLSessionTaskMetrics? { return _metrics as? URLSessionTaskMetrics }
  460. #endif
  461. }
  462. @available(iOS 10.0, macOS 10.12, tvOS 10.0, *)
  463. extension DataResponse: Response {
  464. #if !os(watchOS)
  465. /// The task metrics containing the request / response statistics.
  466. public var metrics: URLSessionTaskMetrics? { return _metrics as? URLSessionTaskMetrics }
  467. #endif
  468. }
  469. @available(iOS 10.0, macOS 10.12, tvOS 10.0, *)
  470. extension DefaultDownloadResponse: Response {
  471. #if !os(watchOS)
  472. /// The task metrics containing the request / response statistics.
  473. public var metrics: URLSessionTaskMetrics? { return _metrics as? URLSessionTaskMetrics }
  474. #endif
  475. }
  476. @available(iOS 10.0, macOS 10.12, tvOS 10.0, *)
  477. extension DownloadResponse: Response {
  478. #if !os(watchOS)
  479. /// The task metrics containing the request / response statistics.
  480. public var metrics: URLSessionTaskMetrics? { return _metrics as? URLSessionTaskMetrics }
  481. #endif
  482. }