ResponseSerialization.swift 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570
  1. //
  2. // ResponseSerialization.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. // MARK: Protocols
  26. /// The type to which all data response serializers must conform in order to serialize a response.
  27. public protocol DataResponseSerializerProtocol {
  28. /// The type of serialized object to be created by this serializer.
  29. associatedtype SerializedObject
  30. /// The function used to serialize the response data in response handlers.
  31. func serialize(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) throws -> SerializedObject
  32. }
  33. /// The type to which all download response serializers must conform in order to serialize a response.
  34. public protocol DownloadResponseSerializerProtocol {
  35. /// The type of serialized object to be created by this `DownloadResponseSerializerType`.
  36. associatedtype SerializedObject
  37. /// The function used to serialize the downloaded data in response handlers.
  38. func serializeDownload(request: URLRequest?, response: HTTPURLResponse?, fileURL: URL?, error: Error?) throws -> SerializedObject
  39. }
  40. /// A serializer that can handle both data and download responses.
  41. public protocol ResponseSerializer: DataResponseSerializerProtocol & DownloadResponseSerializerProtocol { }
  42. /// By default, any serializer declared to conform to both types will get file serialization for free, as it just feeds
  43. /// the data read from disk into the data response serializer.
  44. public extension DownloadResponseSerializerProtocol where Self: DataResponseSerializerProtocol {
  45. public func serializeDownload(request: URLRequest?, response: HTTPURLResponse?, fileURL: URL?, error: Error?) throws -> Self.SerializedObject {
  46. guard error == nil else { throw error! }
  47. guard let fileURL = fileURL else {
  48. throw AFError.responseSerializationFailed(reason: .inputFileNil)
  49. }
  50. let data: Data
  51. do {
  52. data = try Data(contentsOf: fileURL)
  53. } catch {
  54. throw AFError.responseSerializationFailed(reason: .inputFileReadFailed(at: fileURL))
  55. }
  56. do {
  57. return try serialize(request: request, response: response, data: data, error: error)
  58. } catch {
  59. throw error
  60. }
  61. }
  62. }
  63. // MARK: - AnyResponseSerializer
  64. /// A generic `ResponseSerializer` conforming type.
  65. public final class AnyResponseSerializer<Value>: ResponseSerializer {
  66. /// A closure which can be used to serialize data responses.
  67. public typealias DataSerializer = (_ request: URLRequest?, _ response: HTTPURLResponse?, _ data: Data?, _ error: Error?) throws -> Value
  68. /// A closure which can be used to serialize download reponses.
  69. public typealias DownloadSerializer = (_ request: URLRequest?, _ response: HTTPURLResponse?, _ fileURL: URL?, _ error: Error?) throws -> Value
  70. let dataSerializer: DataSerializer
  71. let downloadSerializer: DownloadSerializer?
  72. /// Initialze the instance with both a `DataSerializer` closure and a `DownloadSerializer` closure.
  73. ///
  74. /// - Parameters:
  75. /// - dataSerializer: A `DataSerializer` closure.
  76. /// - downloadSerializer: A `DownloadSerializer` closure.
  77. public init(dataSerializer: @escaping DataSerializer, downloadSerializer: @escaping DownloadSerializer) {
  78. self.dataSerializer = dataSerializer
  79. self.downloadSerializer = downloadSerializer
  80. }
  81. /// Initialze the instance with a `DataSerializer` closure. Download serialization will fallback to a default
  82. /// implementation.
  83. ///
  84. /// - Parameters:
  85. /// - dataSerializer: A `DataSerializer` closure.
  86. public init(dataSerializer: @escaping DataSerializer) {
  87. self.dataSerializer = dataSerializer
  88. self.downloadSerializer = nil
  89. }
  90. public func serialize(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) throws -> Value {
  91. return try dataSerializer(request, response, data, error)
  92. }
  93. public func serializeDownload(request: URLRequest?, response: HTTPURLResponse?, fileURL: URL?, error: Error?) throws -> Value {
  94. return try downloadSerializer?(request, response, fileURL, error) ?? { (request, response, fileURL, error) in
  95. guard error == nil else { throw error! }
  96. guard let fileURL = fileURL else {
  97. throw AFError.responseSerializationFailed(reason: .inputFileNil)
  98. }
  99. let data: Data
  100. do {
  101. data = try Data(contentsOf: fileURL)
  102. } catch {
  103. throw AFError.responseSerializationFailed(reason: .inputFileReadFailed(at: fileURL))
  104. }
  105. do {
  106. return try serialize(request: request, response: response, data: data, error: error)
  107. } catch {
  108. throw error
  109. }
  110. }(request, response, fileURL, error)
  111. }
  112. }
  113. // MARK: - Default
  114. extension DataRequest {
  115. /// Adds a handler to be called once the request has finished.
  116. ///
  117. /// - Parameters:
  118. /// - queue: The queue on which the completion handler is dispatched. Defaults to `nil`, which means
  119. /// the handler is called on `.main`.
  120. /// - completionHandler: The code to be executed once the request has finished.
  121. /// - Returns: The request.
  122. @discardableResult
  123. public func response(queue: DispatchQueue? = nil, completionHandler: @escaping (DataResponse<Data?>) -> Void) -> Self {
  124. internalQueue.addOperation {
  125. // TODO: Use internal serialization queue?
  126. let result = Result(value: self.data, error: self.error)
  127. let response = DataResponse(request: self.request,
  128. response: self.response,
  129. data: self.data,
  130. metrics: self.metrics,
  131. serializationDuration: 0,
  132. result: result)
  133. self.eventMonitor?.request(self, didParseResponse: response)
  134. (queue ?? .main).async { completionHandler(response) }
  135. }
  136. return self
  137. }
  138. /// Adds a handler to be called once the request has finished.
  139. ///
  140. /// - Parameters:
  141. /// - queue: The queue on which the completion handler is dispatched. Defaults to `nil`, which means
  142. /// the handler is called on `.main`.
  143. /// - responseSerializer: The response serializer responsible for serializing the request, response, and data.
  144. /// - completionHandler: The code to be executed once the request has finished.
  145. /// - Returns: The request.
  146. @discardableResult
  147. public func response<Serializer: DataResponseSerializerProtocol>(
  148. queue: DispatchQueue? = nil,
  149. responseSerializer: Serializer,
  150. completionHandler: @escaping (DataResponse<Serializer.SerializedObject>) -> Void)
  151. -> Self
  152. {
  153. internalQueue.addOperation {
  154. // TODO: Use internal serialization queue?
  155. let start = CFAbsoluteTimeGetCurrent()
  156. let result = Result { try responseSerializer.serialize(request: self.request,
  157. response: self.response,
  158. data: self.data,
  159. error: self.error) }
  160. let end = CFAbsoluteTimeGetCurrent()
  161. let response = DataResponse(request: self.request,
  162. response: self.response,
  163. data: self.data,
  164. metrics: self.metrics,
  165. serializationDuration: (end - start),
  166. result: result)
  167. self.eventMonitor?.request(self, didParseResponse: response)
  168. (queue ?? .main).async { completionHandler(response) }
  169. }
  170. return self
  171. }
  172. }
  173. extension DownloadRequest {
  174. /// Adds a handler to be called once the request has finished.
  175. ///
  176. /// - Parameters:
  177. /// - queue: The queue on which the completion handler is dispatched. Defaults to `nil`, which means
  178. /// the handler is called on `.main`.
  179. /// - completionHandler: The code to be executed once the request has finished.
  180. /// - Returns: The request.
  181. @discardableResult
  182. public func response(
  183. queue: DispatchQueue? = nil,
  184. completionHandler: @escaping (DownloadResponse<URL?>) -> Void)
  185. -> Self
  186. {
  187. internalQueue.addOperation {
  188. let result = Result(value: self.temporaryURL ?? self.destinationURL , error: self.error)
  189. let response = DownloadResponse(request: self.request,
  190. response: self.response,
  191. temporaryURL: self.temporaryURL,
  192. destinationURL: self.destinationURL,
  193. resumeData: self.resumeData,
  194. metrics: self.metrics,
  195. serializationDuration: 0,
  196. result: result)
  197. (queue ?? .main).async { completionHandler(response) }
  198. }
  199. return self
  200. }
  201. /// Adds a handler to be called once the request has finished.
  202. ///
  203. /// - Parameters:
  204. /// - queue: The queue on which the completion handler is dispatched. Defaults to `nil`, which means
  205. /// the handler is called on `.main`.
  206. /// - responseSerializer: The response serializer responsible for serializing the request, response, and data
  207. /// contained in the destination url.
  208. /// - completionHandler: The code to be executed once the request has finished.
  209. /// - Returns: The request.
  210. @discardableResult
  211. public func response<T: DownloadResponseSerializerProtocol>(
  212. queue: DispatchQueue? = nil,
  213. responseSerializer: T,
  214. completionHandler: @escaping (DownloadResponse<T.SerializedObject>) -> Void)
  215. -> Self
  216. {
  217. internalQueue.addOperation {
  218. // TODO: Use internal serialization queue?
  219. let start = CFAbsoluteTimeGetCurrent()
  220. let result = Result { try responseSerializer.serializeDownload(request: self.request,
  221. response: self.response,
  222. fileURL: self.fileURL,
  223. error: self.error) }
  224. let end = CFAbsoluteTimeGetCurrent()
  225. let response = DownloadResponse(request: self.request,
  226. response: self.response,
  227. temporaryURL: self.temporaryURL,
  228. destinationURL: self.destinationURL,
  229. resumeData: self.resumeData,
  230. metrics: self.metrics,
  231. serializationDuration: (end - start),
  232. result: result)
  233. (queue ?? .main).async { completionHandler(response) }
  234. }
  235. return self
  236. }
  237. }
  238. // MARK: - Data
  239. extension DataRequest {
  240. /// Adds a handler to be called once the request has finished.
  241. ///
  242. /// - Parameters:
  243. /// - queue: The queue on which the completion handler is dispatched. Defaults to `nil`, which means
  244. /// the handler is called on `.main`.
  245. /// - completionHandler: The code to be executed once the request has finished.
  246. /// - Returns: The request.
  247. @discardableResult
  248. public func responseData(
  249. queue: DispatchQueue? = nil,
  250. completionHandler: @escaping (DataResponse<Data>) -> Void)
  251. -> Self
  252. {
  253. return response(queue: queue,
  254. responseSerializer: DataResponseSerializer(),
  255. completionHandler: completionHandler)
  256. }
  257. }
  258. /// A `ResponseSerializer` that performs minimal reponse checking and returns any response data as-is. By default, a
  259. /// request returning `nil` or no data is considered an error. However, if the response is has a status code valid for
  260. /// empty responses (`204`, `205`), then an empty `Data` value is returned.
  261. public final class DataResponseSerializer: ResponseSerializer {
  262. public init() { }
  263. public func serialize(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) throws -> Data {
  264. guard error == nil else { throw error! }
  265. if let response = response, emptyDataStatusCodes.contains(response.statusCode) { return Data() }
  266. guard let validData = data else {
  267. throw AFError.responseSerializationFailed(reason: .inputDataNil)
  268. }
  269. return validData
  270. }
  271. }
  272. extension DownloadRequest {
  273. /// Adds a handler to be called once the request has finished.
  274. ///
  275. /// - Parameters:
  276. /// - queue: The queue on which the completion handler is dispatched. Defaults to `nil`, which means
  277. /// the handler is called on `.main`.
  278. /// - completionHandler: The code to be executed once the request has finished.
  279. /// - Returns: The request.
  280. @discardableResult
  281. public func responseData(
  282. queue: DispatchQueue? = nil,
  283. completionHandler: @escaping (DownloadResponse<Data>) -> Void)
  284. -> Self
  285. {
  286. return response(
  287. queue: queue,
  288. responseSerializer: DataResponseSerializer(),
  289. completionHandler: completionHandler
  290. )
  291. }
  292. }
  293. // MARK: - String
  294. /// A `ResponseSerializer` that decodes the response data as a `String`. By default, a request returning `nil` or no
  295. /// data is considered an error. However, if the response is has a status code valid for empty responses (`204`, `205`),
  296. /// then an empty `String` is returned.
  297. public final class StringResponseSerializer: ResponseSerializer {
  298. let encoding: String.Encoding?
  299. /// Creates an instance with the given `String.Encoding`.
  300. ///
  301. /// - Parameter encoding: A string encoding. Defaults to `nil`, in which case the encoding will be determined from
  302. /// the server response, falling back to the default HTTP character set, `ISO-8859-1`.
  303. public init(encoding: String.Encoding? = nil) {
  304. self.encoding = encoding
  305. }
  306. public func serialize(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) throws -> String {
  307. guard error == nil else { throw error! }
  308. if let response = response, emptyDataStatusCodes.contains(response.statusCode) { return "" }
  309. guard let validData = data else {
  310. throw AFError.responseSerializationFailed(reason: .inputDataNil)
  311. }
  312. var convertedEncoding = encoding
  313. if let encodingName = response?.textEncodingName as CFString?, convertedEncoding == nil {
  314. let ianaCharSet = CFStringConvertIANACharSetNameToEncoding(encodingName)
  315. let nsStringEncoding = CFStringConvertEncodingToNSStringEncoding(ianaCharSet)
  316. convertedEncoding = String.Encoding(rawValue: nsStringEncoding)
  317. }
  318. let actualEncoding = convertedEncoding ?? .isoLatin1
  319. guard let string = String(data: validData, encoding: actualEncoding) else {
  320. throw AFError.responseSerializationFailed(reason: .stringSerializationFailed(encoding: actualEncoding))
  321. }
  322. return string
  323. }
  324. }
  325. extension DataRequest {
  326. /// Adds a handler to be called once the request has finished.
  327. ///
  328. /// - Parameters:
  329. /// - queue: The queue on which the completion handler is dispatched. Defaults to `nil`, which means
  330. /// the handler is called on `.main`.
  331. /// - encoding: The string encoding. Defaults to `nil`, in which case the encoding will be determined from
  332. /// the server response, falling back to the default HTTP character set, `ISO-8859-1`.
  333. /// - completionHandler: A closure to be executed once the request has finished.
  334. /// - Returns: The request.
  335. @discardableResult
  336. public func responseString(queue: DispatchQueue? = nil,
  337. encoding: String.Encoding? = nil,
  338. completionHandler: @escaping (DataResponse<String>) -> Void) -> Self {
  339. return response(queue: queue,
  340. responseSerializer: StringResponseSerializer(encoding: encoding),
  341. completionHandler: completionHandler)
  342. }
  343. }
  344. extension DownloadRequest {
  345. /// Adds a handler to be called once the request has finished.
  346. ///
  347. /// - Parameters:
  348. /// - queue: The queue on which the completion handler is dispatched. Defaults to `nil`, which means
  349. /// the handler is called on `.main`.
  350. /// - encoding: The string encoding. Defaults to `nil`, in which case the encoding will be determined from
  351. /// the server response, falling back to the default HTTP character set, `ISO-8859-1`.
  352. /// - completionHandler: A closure to be executed once the request has finished.
  353. /// - Returns: The request.
  354. @discardableResult
  355. public func responseString(
  356. queue: DispatchQueue? = nil,
  357. encoding: String.Encoding? = nil,
  358. completionHandler: @escaping (DownloadResponse<String>) -> Void)
  359. -> Self
  360. {
  361. return response(
  362. queue: queue,
  363. responseSerializer: StringResponseSerializer(encoding: encoding),
  364. completionHandler: completionHandler
  365. )
  366. }
  367. }
  368. // MARK: - JSON
  369. /// A `ResponseSerializer` that decodes the response data using `JSONSerialization`. By default, a request returning
  370. /// `nil` or no data is considered an error. However, if the response is has a status code valid for empty responses
  371. /// (`204`, `205`), then an `NSNull` value is returned.
  372. public final class JSONResponseSerializer: ResponseSerializer {
  373. let options: JSONSerialization.ReadingOptions
  374. /// Creates an instance with the given `JSONSerilization.ReadingOptions`.
  375. ///
  376. /// - Parameter options: The options to use. Defaults to `.allowFragments`.
  377. public init(options: JSONSerialization.ReadingOptions = .allowFragments) {
  378. self.options = options
  379. }
  380. public func serialize(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) throws -> Any {
  381. guard error == nil else { throw error! }
  382. guard let validData = data, validData.count > 0 else {
  383. if let response = response, emptyDataStatusCodes.contains(response.statusCode) {
  384. return NSNull()
  385. }
  386. throw AFError.responseSerializationFailed(reason: .inputDataNilOrZeroLength)
  387. }
  388. do {
  389. return try JSONSerialization.jsonObject(with: validData, options: options)
  390. } catch {
  391. throw AFError.responseSerializationFailed(reason: .jsonSerializationFailed(error: error))
  392. }
  393. }
  394. }
  395. extension DataRequest {
  396. /// Adds a handler to be called once the request has finished.
  397. ///
  398. /// - Parameters:
  399. /// - queue: The queue on which the completion handler is dispatched. Defaults to `nil`, which means
  400. /// the handler is called on `.main`.
  401. /// - options: The JSON serialization reading options. Defaults to `.allowFragments`.
  402. /// - completionHandler: A closure to be executed once the request has finished.
  403. /// - Returns: The request.
  404. @discardableResult
  405. public func responseJSON(queue: DispatchQueue? = nil,
  406. options: JSONSerialization.ReadingOptions = .allowFragments,
  407. completionHandler: @escaping (DataResponse<Any>) -> Void) -> Self {
  408. return response(queue: queue,
  409. responseSerializer: JSONResponseSerializer(options: options),
  410. completionHandler: completionHandler)
  411. }
  412. }
  413. extension DownloadRequest {
  414. /// Adds a handler to be called once the request has finished.
  415. ///
  416. /// - Parameters:
  417. /// - queue: The queue on which the completion handler is dispatched. Defaults to `nil`, which means
  418. /// the handler is called on `.main`.
  419. /// - options: The JSON serialization reading options. Defaults to `.allowFragments`.
  420. /// - completionHandler: A closure to be executed once the request has finished.
  421. /// - Returns: The request.
  422. @discardableResult
  423. public func responseJSON(
  424. queue: DispatchQueue? = nil,
  425. options: JSONSerialization.ReadingOptions = .allowFragments,
  426. completionHandler: @escaping (DownloadResponse<Any>) -> Void)
  427. -> Self
  428. {
  429. return response(queue: queue,
  430. responseSerializer: JSONResponseSerializer(options: options),
  431. completionHandler: completionHandler)
  432. }
  433. }
  434. // MARK: - Empty
  435. /// A type representing an empty response. Use `Empty.response` to get the instance.
  436. public struct Empty: Decodable {
  437. public static let response = Empty()
  438. }
  439. // MARK: - JSON Decodable
  440. /// A `ResponseSerializer` that decodes the response data as a generic value using a `JSONDecoder`. By default, a
  441. /// request returning `nil` or no data is considered an error. However, if the response is has a status code valid for
  442. /// empty responses (`204`, `205`), then the `Empty.response` value is returned.
  443. public final class JSONDecodableResponseSerializer<T: Decodable>: ResponseSerializer {
  444. let decoder: JSONDecoder
  445. /// Creates an instance with the given `JSONDecoder` instance.
  446. ///
  447. /// - Parameter decoder: A decoder. Defaults to a `JSONDecoder` with default settings.
  448. public init(decoder: JSONDecoder = JSONDecoder()) {
  449. self.decoder = decoder
  450. }
  451. public func serialize(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) throws -> T {
  452. guard error == nil else { throw error! }
  453. guard let validData = data, validData.count > 0 else {
  454. if let response = response, emptyDataStatusCodes.contains(response.statusCode) {
  455. guard let emptyResponse = Empty.response as? T else {
  456. throw AFError.responseSerializationFailed(reason: .invalidEmptyResponse(type: "\(T.self)"))
  457. }
  458. return emptyResponse
  459. }
  460. throw AFError.responseSerializationFailed(reason: .inputDataNilOrZeroLength)
  461. }
  462. do {
  463. return try decoder.decode(T.self, from: validData)
  464. } catch {
  465. throw error
  466. }
  467. }
  468. }
  469. extension DataRequest {
  470. /// Adds a handler to be called once the request has finished.
  471. ///
  472. /// - Parameters:
  473. /// - queue: The queue on which the completion handler is dispatched. Defaults to `nil`, which means
  474. /// the handler is called on `.main`.
  475. /// - decoder: The decoder to use to decode the response. Defaults to a `JSONDecoder` with default
  476. /// settings.
  477. /// - completionHandler: A closure to be executed once the request has finished.
  478. /// - Returns: The request.
  479. @discardableResult
  480. public func responseJSONDecodable<T: Decodable>(queue: DispatchQueue? = nil,
  481. decoder: JSONDecoder = JSONDecoder(),
  482. completionHandler: @escaping (DataResponse<T>) -> Void) -> Self {
  483. return response(queue: queue,
  484. responseSerializer: JSONDecodableResponseSerializer(decoder: decoder),
  485. completionHandler: completionHandler)
  486. }
  487. }
  488. /// A set of HTTP response status code that do not contain response data.
  489. private let emptyDataStatusCodes: Set<Int> = [204, 205]