ResponseSerialization.swift 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672
  1. //
  2. // ResponseSerialization.swift
  3. //
  4. // Copyright (c) 2014-2017 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 typealias 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 -> 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. let data = try Data(contentsOf: fileURL)
  58. return try serialize(request: request, response: response, data: data, error: error)
  59. } catch {
  60. throw error
  61. }
  62. }
  63. }
  64. // MARK: - AnyResponseSerializer
  65. /// A generic `ResponseSerializer` conforming type.
  66. public final class AnyResponseSerializer<Value>: ResponseSerializer {
  67. /// A closure which can be used to serialize data responses.
  68. public typealias DataSerializer = (_ request: URLRequest?, _ response: HTTPURLResponse?, _ data: Data?, _ error: Error?) throws -> Value
  69. /// A closure which can be used to serialize download reponses.
  70. public typealias DownloadSerializer = (_ request: URLRequest?, _ response: HTTPURLResponse?, _ fileURL: URL?, _ error: Error?) throws -> Value
  71. let dataSerializer: DataSerializer
  72. let downloadSerializer: DownloadSerializer?
  73. /// Initialze the instance with both a `DataSerializer` closure and a `DownloadSerializer` closure.
  74. ///
  75. /// - Parameters:
  76. /// - dataSerializer: A `DataSerializer` closure.
  77. /// - downloadSerializer: A `DownloadSerializer` closure.
  78. public init(dataSerializer: @escaping DataSerializer, downloadSerializer: @escaping DownloadSerializer) {
  79. self.dataSerializer = dataSerializer
  80. self.downloadSerializer = downloadSerializer
  81. }
  82. /// Initialze the instance with a `DataSerializer` closure. Download serialization will fallback to a default
  83. /// implementation.
  84. ///
  85. /// - Parameters:
  86. /// - dataSerializer: A `DataSerializer` closure.
  87. public init(dataSerializer: @escaping DataSerializer) {
  88. self.dataSerializer = dataSerializer
  89. self.downloadSerializer = nil
  90. }
  91. public func serialize(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) throws -> Value {
  92. return try dataSerializer(request, response, data, error)
  93. }
  94. public func serializeDownload(request: URLRequest?, response: HTTPURLResponse?, fileURL: URL?, error: Error?) throws -> Value {
  95. return try downloadSerializer?(request, response, fileURL, error) ?? { (request, response, fileURL, error) in
  96. guard error == nil else { throw error! }
  97. guard let fileURL = fileURL else {
  98. throw AFError.responseSerializationFailed(reason: .inputFileNil)
  99. }
  100. let data: Data
  101. do {
  102. data = try Data(contentsOf: fileURL)
  103. } catch {
  104. throw AFError.responseSerializationFailed(reason: .inputFileReadFailed(at: fileURL))
  105. }
  106. do {
  107. let data = try Data(contentsOf: fileURL)
  108. return try serialize(request: request, response: response, data: data, error: error)
  109. } catch {
  110. throw error
  111. }
  112. }(request, response, fileURL, error)
  113. }
  114. }
  115. // MARK: - Timeline
  116. extension Request {
  117. var timeline: Timeline {
  118. let requestStartTime = self.startTime ?? CFAbsoluteTimeGetCurrent()
  119. let requestCompletedTime = self.endTime ?? CFAbsoluteTimeGetCurrent()
  120. let initialResponseTime = self.delegate.initialResponseTime ?? requestCompletedTime
  121. return Timeline(
  122. requestStartTime: requestStartTime,
  123. initialResponseTime: initialResponseTime,
  124. requestCompletedTime: requestCompletedTime,
  125. serializationCompletedTime: CFAbsoluteTimeGetCurrent()
  126. )
  127. }
  128. }
  129. // MARK: - Default
  130. extension DataRequest {
  131. /// Adds a handler to be called once the request has finished.
  132. ///
  133. /// - Parameters:
  134. /// - queue: The queue on which the completion handler is dispatched. Defaults to `nil`, which means
  135. /// the handler is called on `.main`.
  136. /// - completionHandler: The code to be executed once the request has finished.
  137. /// - Returns: The request.
  138. @discardableResult
  139. public func response(queue: DispatchQueue? = nil, completionHandler: @escaping (DefaultDataResponse) -> Void) -> Self {
  140. delegate.queue.addOperation {
  141. (queue ?? DispatchQueue.main).async {
  142. var dataResponse = DefaultDataResponse(
  143. request: self.request,
  144. response: self.response,
  145. data: self.delegate.data,
  146. error: self.delegate.error,
  147. timeline: self.timeline
  148. )
  149. dataResponse.add(self.delegate.metrics)
  150. completionHandler(dataResponse)
  151. }
  152. }
  153. return self
  154. }
  155. /// Adds a handler to be called once the request has finished.
  156. ///
  157. /// - Parameters:
  158. /// - queue: The queue on which the completion handler is dispatched. Defaults to `nil`, which means
  159. /// the handler is called on `.main`.
  160. /// - responseSerializer: The response serializer responsible for serializing the request, response, and data.
  161. /// - completionHandler: The code to be executed once the request has finished.
  162. /// - Returns: The request.
  163. @discardableResult
  164. public func response<T: DataResponseSerializerProtocol>(
  165. queue: DispatchQueue? = nil,
  166. responseSerializer: T,
  167. completionHandler: @escaping (DataResponse<T.SerializedObject>) -> Void)
  168. -> Self
  169. {
  170. delegate.queue.addOperation {
  171. let result = Result { try responseSerializer.serialize(request: self.request,
  172. response: self.response,
  173. data: self.delegate.data,
  174. error: self.delegate.error) }
  175. var dataResponse = DataResponse<T.SerializedObject>(
  176. request: self.request,
  177. response: self.response,
  178. data: self.delegate.data,
  179. result: result,
  180. timeline: self.timeline
  181. )
  182. dataResponse.add(self.delegate.metrics)
  183. (queue ?? .main).async { completionHandler(dataResponse) }
  184. }
  185. return self
  186. }
  187. }
  188. extension DownloadRequest {
  189. /// Adds a handler to be called once the request has finished.
  190. ///
  191. /// - Parameters:
  192. /// - queue: The queue on which the completion handler is dispatched. Defaults to `nil`, which means
  193. /// the handler is called on `.main`.
  194. /// - completionHandler: The code to be executed once the request has finished.
  195. /// - Returns: The request.
  196. @discardableResult
  197. public func response(
  198. queue: DispatchQueue? = nil,
  199. completionHandler: @escaping (DefaultDownloadResponse) -> Void)
  200. -> Self
  201. {
  202. delegate.queue.addOperation {
  203. (queue ?? .main).async {
  204. var downloadResponse = DefaultDownloadResponse(
  205. request: self.request,
  206. response: self.response,
  207. temporaryURL: self.downloadDelegate.temporaryURL,
  208. destinationURL: self.downloadDelegate.destinationURL,
  209. resumeData: self.downloadDelegate.resumeData,
  210. error: self.downloadDelegate.error,
  211. timeline: self.timeline
  212. )
  213. downloadResponse.add(self.delegate.metrics)
  214. completionHandler(downloadResponse)
  215. }
  216. }
  217. return self
  218. }
  219. /// Adds a handler to be called once the request has finished.
  220. ///
  221. /// - Parameters:
  222. /// - queue: The queue on which the completion handler is dispatched. Defaults to `nil`, which means
  223. /// the handler is called on `.main`.
  224. /// - responseSerializer: The response serializer responsible for serializing the request, response, and data
  225. /// contained in the destination url.
  226. /// - completionHandler: The code to be executed once the request has finished.
  227. /// - Returns: The request.
  228. @discardableResult
  229. public func response<T: DownloadResponseSerializerProtocol>(
  230. queue: DispatchQueue? = nil,
  231. responseSerializer: T,
  232. completionHandler: @escaping (DownloadResponse<T.SerializedObject>) -> Void)
  233. -> Self
  234. {
  235. delegate.queue.addOperation {
  236. let result = Result { try responseSerializer.serializeDownload(request: self.request,
  237. response: self.response,
  238. fileURL: self.downloadDelegate.fileURL,
  239. error: self.downloadDelegate.error) }
  240. var downloadResponse = DownloadResponse<T.SerializedObject>(
  241. request: self.request,
  242. response: self.response,
  243. temporaryURL: self.downloadDelegate.temporaryURL,
  244. destinationURL: self.downloadDelegate.destinationURL,
  245. resumeData: self.downloadDelegate.resumeData,
  246. result: result,
  247. timeline: self.timeline
  248. )
  249. downloadResponse.add(self.delegate.metrics)
  250. (queue ?? .main).async { completionHandler(downloadResponse) }
  251. }
  252. return self
  253. }
  254. }
  255. // MARK: - Data
  256. extension DataRequest {
  257. /// Adds a handler to be called once the request has finished.
  258. ///
  259. /// - Parameters:
  260. /// - queue: The queue on which the completion handler is dispatched. Defaults to `nil`, which means
  261. /// the handler is called on `.main`.
  262. /// - completionHandler: The code to be executed once the request has finished.
  263. /// - Returns: The request.
  264. @discardableResult
  265. public func responseData(
  266. queue: DispatchQueue? = nil,
  267. completionHandler: @escaping (DataResponse<Data>) -> Void)
  268. -> Self
  269. {
  270. return response(
  271. queue: queue,
  272. responseSerializer: DataResponseSerializer(),
  273. completionHandler: completionHandler
  274. )
  275. }
  276. }
  277. /// A `ResponseSerializer` that performs minimal reponse checking and returns any response data as-is. By default, a
  278. /// request returning `nil` or no data is considered an error. However, if the response is has a status code valid for
  279. /// empty responses (`204`, `205`), then an empty `Data` value is returned.
  280. public final class DataResponseSerializer: ResponseSerializer {
  281. public init() { }
  282. public func serialize(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) throws -> Data {
  283. guard error == nil else { throw error! }
  284. if let response = response, emptyDataStatusCodes.contains(response.statusCode) { return Data() }
  285. guard let validData = data else {
  286. throw AFError.responseSerializationFailed(reason: .inputDataNil)
  287. }
  288. return validData
  289. }
  290. }
  291. extension DownloadRequest {
  292. /// Adds a handler to be called once the request has finished.
  293. ///
  294. /// - Parameters:
  295. /// - queue: The queue on which the completion handler is dispatched. Defaults to `nil`, which means
  296. /// the handler is called on `.main`.
  297. /// - completionHandler: The code to be executed once the request has finished.
  298. /// - Returns: The request.
  299. @discardableResult
  300. public func responseData(
  301. queue: DispatchQueue? = nil,
  302. completionHandler: @escaping (DownloadResponse<Data>) -> Void)
  303. -> Self
  304. {
  305. return response(
  306. queue: queue,
  307. responseSerializer: DataResponseSerializer(),
  308. completionHandler: completionHandler
  309. )
  310. }
  311. }
  312. // MARK: - String
  313. /// A `ResponseSerializer` that decodes the response data as a `String`. By default, a request returning `nil` or no
  314. /// data is considered an error. However, if the response is has a status code valid for empty responses (`204`, `205`),
  315. /// then an empty `String` is returned.
  316. public final class StringResponseSerializer: ResponseSerializer {
  317. let encoding: String.Encoding?
  318. /// Creates an instance with the given `String.Encoding`.
  319. ///
  320. /// - Parameter encoding: A string encoding. Defaults to `nil`, in which case the encoding will be determined from
  321. /// the server response, falling back to the default HTTP character set, `ISO-8859-1`.
  322. public init(encoding: String.Encoding? = nil) {
  323. self.encoding = encoding
  324. }
  325. public func serialize(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) throws -> String {
  326. guard error == nil else { throw error! }
  327. if let response = response, emptyDataStatusCodes.contains(response.statusCode) { return "" }
  328. guard let validData = data else {
  329. throw AFError.responseSerializationFailed(reason: .inputDataNil)
  330. }
  331. var convertedEncoding = encoding
  332. if let encodingName = response?.textEncodingName as CFString!, convertedEncoding == nil {
  333. let ianaCharSet = CFStringConvertIANACharSetNameToEncoding(encodingName)
  334. let nsStringEncoding = CFStringConvertEncodingToNSStringEncoding(ianaCharSet)
  335. convertedEncoding = String.Encoding(rawValue: nsStringEncoding)
  336. }
  337. let actualEncoding = convertedEncoding ?? .isoLatin1
  338. guard let string = String(data: validData, encoding: actualEncoding) else {
  339. throw AFError.responseSerializationFailed(reason: .stringSerializationFailed(encoding: actualEncoding))
  340. }
  341. return string
  342. }
  343. }
  344. extension DataRequest {
  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 (DataResponse<String>) -> Void)
  359. -> Self
  360. {
  361. return response(
  362. queue: queue,
  363. responseSerializer: StringResponseSerializer(encoding: encoding),
  364. completionHandler: completionHandler
  365. )
  366. }
  367. }
  368. extension DownloadRequest {
  369. /// Adds a handler to be called once the request has finished.
  370. ///
  371. /// - Parameters:
  372. /// - queue: The queue on which the completion handler is dispatched. Defaults to `nil`, which means
  373. /// the handler is called on `.main`.
  374. /// - encoding: The string encoding. Defaults to `nil`, in which case the encoding will be determined from
  375. /// the server response, falling back to the default HTTP character set, `ISO-8859-1`.
  376. /// - completionHandler: A closure to be executed once the request has finished.
  377. /// - Returns: The request.
  378. @discardableResult
  379. public func responseString(
  380. queue: DispatchQueue? = nil,
  381. encoding: String.Encoding? = nil,
  382. completionHandler: @escaping (DownloadResponse<String>) -> Void)
  383. -> Self
  384. {
  385. return response(
  386. queue: queue,
  387. responseSerializer: StringResponseSerializer(encoding: encoding),
  388. completionHandler: completionHandler
  389. )
  390. }
  391. }
  392. // MARK: - JSON
  393. /// A `ResponseSerializer` that decodes the response data using `JSONSerialization`. By default, a request returning
  394. /// `nil` or no data is considered an error. However, if the response is has a status code valid for empty responses
  395. /// (`204`, `205`), then an `NSNull` value is returned.
  396. public final class JSONResponseSerializer: ResponseSerializer {
  397. let options: JSONSerialization.ReadingOptions
  398. /// Creates an instance with the given `JSONSerilization.ReadingOptions`.
  399. ///
  400. /// - Parameter options: The options to use. Defaults to `.allowFragments`.
  401. public init(options: JSONSerialization.ReadingOptions = .allowFragments) {
  402. self.options = options
  403. }
  404. public func serialize(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) throws -> Any {
  405. guard error == nil else { throw error! }
  406. guard let validData = data, validData.count > 0 else {
  407. if let response = response, emptyDataStatusCodes.contains(response.statusCode) {
  408. return NSNull()
  409. }
  410. throw AFError.responseSerializationFailed(reason: .inputDataNilOrZeroLength)
  411. }
  412. do {
  413. return try JSONSerialization.jsonObject(with: validData, options: options)
  414. } catch {
  415. throw AFError.responseSerializationFailed(reason: .jsonSerializationFailed(error: error))
  416. }
  417. }
  418. }
  419. extension DataRequest {
  420. /// Adds a handler to be called once the request has finished.
  421. ///
  422. /// - Parameters:
  423. /// - queue: The queue on which the completion handler is dispatched. Defaults to `nil`, which means
  424. /// the handler is called on `.main`.
  425. /// - options: The JSON serialization reading options. Defaults to `.allowFragments`.
  426. /// - completionHandler: A closure to be executed once the request has finished.
  427. /// - Returns: The request.
  428. @discardableResult
  429. public func responseJSON(
  430. queue: DispatchQueue? = nil,
  431. options: JSONSerialization.ReadingOptions = .allowFragments,
  432. completionHandler: @escaping (DataResponse<Any>) -> Void)
  433. -> Self
  434. {
  435. return response(
  436. queue: queue,
  437. responseSerializer: JSONResponseSerializer(options: options),
  438. completionHandler: completionHandler
  439. )
  440. }
  441. }
  442. extension DownloadRequest {
  443. /// Adds a handler to be called once the request has finished.
  444. ///
  445. /// - Parameters:
  446. /// - queue: The queue on which the completion handler is dispatched. Defaults to `nil`, which means
  447. /// the handler is called on `.main`.
  448. /// - options: The JSON serialization reading options. Defaults to `.allowFragments`.
  449. /// - completionHandler: A closure to be executed once the request has finished.
  450. /// - Returns: The request.
  451. @discardableResult
  452. public func responseJSON(
  453. queue: DispatchQueue? = nil,
  454. options: JSONSerialization.ReadingOptions = .allowFragments,
  455. completionHandler: @escaping (DownloadResponse<Any>) -> Void)
  456. -> Self
  457. {
  458. return response(
  459. queue: queue,
  460. responseSerializer: JSONResponseSerializer(options: options),
  461. completionHandler: completionHandler
  462. )
  463. }
  464. }
  465. // MARK: - Empty
  466. /// A type representing an empty response. Use `Empty.response` to get the instance.
  467. public struct Empty: Decodable {
  468. public static let response = Empty()
  469. }
  470. // MARK: - JSON Decodable
  471. /// A `ResponseSerializer` that decodes the response data as a generic value using a `JSONDecoder`. By default, a
  472. /// request returning `nil` or no data is considered an error. However, if the response is has a status code valid for
  473. /// empty responses (`204`, `205`), then the `Empty.response` value is returned.
  474. public final class JSONDecodableResponseSerializer<T: Decodable>: ResponseSerializer {
  475. let decoder: JSONDecoder
  476. /// Creates an instance with the given `JSONDecoder` instance.
  477. ///
  478. /// - Parameter decoder: A decoder. Defaults to a `JSONDecoder` with default settings.
  479. public init(decoder: JSONDecoder = JSONDecoder()) {
  480. self.decoder = decoder
  481. }
  482. public func serialize(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) throws -> T {
  483. guard error == nil else { throw error! }
  484. guard let validData = data, validData.count > 0 else {
  485. if let response = response, emptyDataStatusCodes.contains(response.statusCode) {
  486. guard let emptyResponse = Empty.response as? T else {
  487. throw AFError.responseSerializationFailed(reason: .invalidEmptyResponse(type: "\(T.self)"))
  488. }
  489. return emptyResponse
  490. }
  491. throw AFError.responseSerializationFailed(reason: .inputDataNilOrZeroLength)
  492. }
  493. do {
  494. return try decoder.decode(T.self, from: validData)
  495. } catch {
  496. throw error
  497. }
  498. }
  499. }
  500. extension DataRequest {
  501. /// Adds a handler to be called once the request has finished.
  502. ///
  503. /// - Parameters:
  504. /// - queue: The queue on which the completion handler is dispatched. Defaults to `nil`, which means
  505. /// the handler is called on `.main`.
  506. /// - decoder: The decoder to use to decode the response. Defaults to a `JSONDecoder` with default
  507. /// settings.
  508. /// - completionHandler: A closure to be executed once the request has finished.
  509. /// - Returns: The request.
  510. @discardableResult
  511. public func responseJSONDecodable<T: Decodable>(
  512. queue: DispatchQueue? = nil,
  513. decoder: JSONDecoder = JSONDecoder(),
  514. completionHandler: @escaping (DataResponse<T>) -> Void)
  515. -> Self
  516. {
  517. return response(
  518. queue: queue,
  519. responseSerializer: JSONDecodableResponseSerializer(decoder: decoder),
  520. completionHandler: completionHandler
  521. )
  522. }
  523. }
  524. extension DownloadRequest {
  525. /// Adds a handler to be called once the request has finished.
  526. ///
  527. /// - Parameters:
  528. /// - queue: The queue on which the completion handler is dispatched. Defaults to `nil`, which means
  529. /// the handler is called on `.main`.
  530. /// - options: The property list reading options. Defaults to `[]`.
  531. /// - completionHandler: A closure to be executed once the request has finished.
  532. /// - Returns: The request.
  533. @discardableResult
  534. public func responsePropertyList(
  535. queue: DispatchQueue? = nil,
  536. options: PropertyListSerialization.ReadOptions = [],
  537. completionHandler: @escaping (DownloadResponse<Any>) -> Void)
  538. -> Self
  539. {
  540. return response(
  541. queue: queue,
  542. responseSerializer: PropertyListResponseSerializer(options: options),
  543. completionHandler: completionHandler
  544. )
  545. }
  546. }
  547. // MARK: - PropertyList Decodable
  548. /// A `ResponseSerializer` that decodes the response data as a generic value using a `PropertyListDecoder`. By default,
  549. /// a request returning `nil` or no data is considered an error. However, if the response is has a status code valid for
  550. /// empty responses (`204`, `205`), then the `Empty.response` value is returned.
  551. public final class PropertyListDecodableResponseSerializer<T: Decodable>: ResponseSerializer {
  552. let decoder: PropertyListDecoder
  553. /// Creates an instance with the given `JSONDecoder` instance.
  554. ///
  555. /// - Parameter decoder: A decoder. Defaults to a `PropertyListDecoder` with default settings.
  556. public init(decoder: PropertyListDecoder = PropertyListDecoder()) {
  557. self.decoder = decoder
  558. }
  559. public func serialize(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) -> Result<T> {
  560. guard error == nil else { return .failure(error!) }
  561. guard let validData = data, validData.count > 0 else {
  562. if let response = response, emptyDataStatusCodes.contains(response.statusCode) {
  563. guard let emptyResponse = Empty.response as? T else {
  564. return .failure(AFError.responseSerializationFailed(reason: .invalidEmptyResponse(type: "\(T.self)")))
  565. }
  566. return .success(emptyResponse)
  567. }
  568. return .failure(AFError.responseSerializationFailed(reason: .inputDataNilOrZeroLength))
  569. }
  570. do {
  571. return .success(try decoder.decode(T.self, from: validData))
  572. } catch {
  573. return .failure(error)
  574. }
  575. }
  576. }
  577. /// A set of HTTP response status code that do not contain response data.
  578. private let emptyDataStatusCodes: Set<Int> = [204, 205]