ResponseSerialization.swift 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708
  1. //
  2. // ResponseSerialization.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. /// The type in which all data response serializers must conform to in order to serialize a response.
  26. public protocol DataResponseSerializerProtocol {
  27. /// The type of serialized object to be created by this `DataResponseSerializerType`.
  28. associatedtype SerializedObject
  29. /// A closure used by response handlers that takes a request, response, data and error and returns a result.
  30. var serializeResponse: (URLRequest?, HTTPURLResponse?, Data?, Error?) -> Result<SerializedObject> { get }
  31. }
  32. // MARK: -
  33. /// A generic `DataResponseSerializerType` used to serialize a request, response, and data into a serialized object.
  34. public struct DataResponseSerializer<Value>: DataResponseSerializerProtocol {
  35. /// The type of serialized object to be created by this `DataResponseSerializer`.
  36. public typealias SerializedObject = Value
  37. /// A closure used by response handlers that takes a request, response, data and error and returns a result.
  38. public var serializeResponse: (URLRequest?, HTTPURLResponse?, Data?, Error?) -> Result<Value>
  39. /// Initializes the `ResponseSerializer` instance with the given serialize response closure.
  40. ///
  41. /// - parameter serializeResponse: The closure used to serialize the response.
  42. ///
  43. /// - returns: The new generic response serializer instance.
  44. public init(serializeResponse: @escaping (URLRequest?, HTTPURLResponse?, Data?, Error?) -> Result<Value>) {
  45. self.serializeResponse = serializeResponse
  46. }
  47. }
  48. // MARK: -
  49. /// The type in which all download response serializers must conform to in order to serialize a response.
  50. public protocol DownloadResponseSerializerProtocol {
  51. /// The type of serialized object to be created by this `DownloadResponseSerializerType`.
  52. associatedtype SerializedObject
  53. /// A closure used by response handlers that takes a request, response, url and error and returns a result.
  54. var serializeResponse: (URLRequest?, HTTPURLResponse?, URL?, Error?) -> Result<SerializedObject> { get }
  55. }
  56. // MARK: -
  57. /// A generic `DownloadResponseSerializerType` used to serialize a request, response, and data into a serialized object.
  58. public struct DownloadResponseSerializer<Value>: DownloadResponseSerializerProtocol {
  59. /// The type of serialized object to be created by this `DownloadResponseSerializer`.
  60. public typealias SerializedObject = Value
  61. /// A closure used by response handlers that takes a request, response, url and error and returns a result.
  62. public var serializeResponse: (URLRequest?, HTTPURLResponse?, URL?, Error?) -> Result<Value>
  63. /// Initializes the `ResponseSerializer` instance with the given serialize response closure.
  64. ///
  65. /// - parameter serializeResponse: The closure used to serialize the response.
  66. ///
  67. /// - returns: The new generic response serializer instance.
  68. public init(serializeResponse: @escaping (URLRequest?, HTTPURLResponse?, URL?, Error?) -> Result<Value>) {
  69. self.serializeResponse = serializeResponse
  70. }
  71. }
  72. // MARK: - Default
  73. extension DataRequest {
  74. /// Adds a handler to be called once the request has finished.
  75. ///
  76. /// - parameter queue: The queue on which the completion handler is dispatched.
  77. /// - parameter completionHandler: The code to be executed once the request has finished.
  78. ///
  79. /// - returns: The request.
  80. @discardableResult
  81. public func response(queue: DispatchQueue? = nil, completionHandler: @escaping (DefaultDataResponse) -> Void) -> Self {
  82. delegate.queue.addOperation {
  83. (queue ?? DispatchQueue.main).async {
  84. let dataResponse = DefaultDataResponse(
  85. request: self.request,
  86. response: self.response,
  87. data: self.delegate.data,
  88. error: self.delegate.error
  89. )
  90. completionHandler(dataResponse)
  91. }
  92. }
  93. return self
  94. }
  95. /// Adds a handler to be called once the request has finished.
  96. ///
  97. /// - parameter queue: The queue on which the completion handler is dispatched.
  98. /// - parameter responseSerializer: The response serializer responsible for serializing the request, response,
  99. /// and data.
  100. /// - parameter completionHandler: The code to be executed once the request has finished.
  101. ///
  102. /// - returns: The request.
  103. @discardableResult
  104. public func response<T: DataResponseSerializerProtocol>(
  105. queue: DispatchQueue? = nil,
  106. responseSerializer: T,
  107. completionHandler: @escaping (DataResponse<T.SerializedObject>) -> Void)
  108. -> Self
  109. {
  110. delegate.queue.addOperation {
  111. let result = responseSerializer.serializeResponse(
  112. self.request,
  113. self.response,
  114. self.delegate.data,
  115. self.delegate.error
  116. )
  117. let requestCompletedTime = self.endTime ?? CFAbsoluteTimeGetCurrent()
  118. let initialResponseTime = self.delegate.initialResponseTime ?? requestCompletedTime
  119. let timeline = Timeline(
  120. requestStartTime: self.startTime ?? CFAbsoluteTimeGetCurrent(),
  121. initialResponseTime: initialResponseTime,
  122. requestCompletedTime: requestCompletedTime,
  123. serializationCompletedTime: CFAbsoluteTimeGetCurrent()
  124. )
  125. let response = DataResponse<T.SerializedObject>(
  126. request: self.request,
  127. response: self.response,
  128. data: self.delegate.data,
  129. result: result,
  130. timeline: timeline
  131. )
  132. (queue ?? DispatchQueue.main).async { completionHandler(response) }
  133. }
  134. return self
  135. }
  136. }
  137. extension DownloadRequest {
  138. /// Adds a handler to be called once the request has finished.
  139. ///
  140. /// - parameter queue: The queue on which the completion handler is dispatched.
  141. /// - parameter completionHandler: The code to be executed once the request has finished.
  142. ///
  143. /// - returns: The request.
  144. @discardableResult
  145. public func response(
  146. queue: DispatchQueue? = nil,
  147. completionHandler: @escaping (DefaultDownloadResponse) -> Void)
  148. -> Self
  149. {
  150. delegate.queue.addOperation {
  151. (queue ?? DispatchQueue.main).async {
  152. let downloadResponse = DefaultDownloadResponse(
  153. request: self.request,
  154. response: self.response,
  155. temporaryURL: self.downloadDelegate.temporaryURL,
  156. destinationURL: self.downloadDelegate.destinationURL,
  157. resumeData: self.downloadDelegate.resumeData,
  158. error: self.downloadDelegate.error
  159. )
  160. completionHandler(downloadResponse)
  161. }
  162. }
  163. return self
  164. }
  165. /// Adds a handler to be called once the request has finished.
  166. ///
  167. /// - parameter queue: The queue on which the completion handler is dispatched.
  168. /// - parameter responseSerializer: The response serializer responsible for serializing the request, response,
  169. /// and data contained in the destination url.
  170. /// - parameter completionHandler: The code to be executed once the request has finished.
  171. ///
  172. /// - returns: The request.
  173. @discardableResult
  174. public func response<T: DownloadResponseSerializerProtocol>(
  175. queue: DispatchQueue? = nil,
  176. responseSerializer: T,
  177. completionHandler: @escaping (DownloadResponse<T.SerializedObject>) -> Void)
  178. -> Self
  179. {
  180. delegate.queue.addOperation {
  181. let result = responseSerializer.serializeResponse(
  182. self.request,
  183. self.response,
  184. self.downloadDelegate.fileURL,
  185. self.downloadDelegate.error
  186. )
  187. let requestCompletedTime = self.endTime ?? CFAbsoluteTimeGetCurrent()
  188. let initialResponseTime = self.delegate.initialResponseTime ?? requestCompletedTime
  189. let timeline = Timeline(
  190. requestStartTime: self.startTime ?? CFAbsoluteTimeGetCurrent(),
  191. initialResponseTime: initialResponseTime,
  192. requestCompletedTime: requestCompletedTime,
  193. serializationCompletedTime: CFAbsoluteTimeGetCurrent()
  194. )
  195. let response = DownloadResponse<T.SerializedObject>(
  196. request: self.request,
  197. response: self.response,
  198. temporaryURL: self.downloadDelegate.temporaryURL,
  199. destinationURL: self.downloadDelegate.destinationURL,
  200. resumeData: self.downloadDelegate.resumeData,
  201. result: result,
  202. timeline: timeline
  203. )
  204. (queue ?? DispatchQueue.main).async { completionHandler(response) }
  205. }
  206. return self
  207. }
  208. }
  209. // MARK: - Data
  210. extension Request {
  211. /// Returns a result data type that contains the response data as-is.
  212. ///
  213. /// - parameter response: The response from the server.
  214. /// - parameter data: The data returned from the server.
  215. /// - parameter error: The error already encountered if it exists.
  216. ///
  217. /// - returns: The result data type.
  218. public static func serializeResponseData(response: HTTPURLResponse?, data: Data?, error: Error?) -> Result<Data> {
  219. guard error == nil else { return .failure(error!) }
  220. if let response = response, emptyDataStatusCodes.contains(response.statusCode) { return .success(Data()) }
  221. guard let validData = data else {
  222. return .failure(AFError.responseSerializationFailed(reason: .inputDataNil))
  223. }
  224. return .success(validData)
  225. }
  226. }
  227. extension DataRequest {
  228. /// Creates a response serializer that returns the associated data as-is.
  229. ///
  230. /// - returns: A data response serializer.
  231. public static func dataResponseSerializer() -> DataResponseSerializer<Data> {
  232. return DataResponseSerializer { _, response, data, error in
  233. return Request.serializeResponseData(response: response, data: data, error: error)
  234. }
  235. }
  236. /// Adds a handler to be called once the request has finished.
  237. ///
  238. /// - parameter completionHandler: The code to be executed once the request has finished.
  239. ///
  240. /// - returns: The request.
  241. @discardableResult
  242. public func responseData(
  243. queue: DispatchQueue? = nil,
  244. completionHandler: @escaping (DataResponse<Data>) -> Void)
  245. -> Self
  246. {
  247. return response(
  248. queue: queue,
  249. responseSerializer: DataRequest.dataResponseSerializer(),
  250. completionHandler: completionHandler
  251. )
  252. }
  253. }
  254. extension DownloadRequest {
  255. /// Creates a response serializer that returns the associated data as-is.
  256. ///
  257. /// - returns: A data response serializer.
  258. public static func dataResponseSerializer() -> DownloadResponseSerializer<Data> {
  259. return DownloadResponseSerializer { _, response, fileURL, error in
  260. guard error == nil else { return .failure(error!) }
  261. guard let fileURL = fileURL else {
  262. return .failure(AFError.responseSerializationFailed(reason: .inputFileNil))
  263. }
  264. do {
  265. let data = try Data(contentsOf: fileURL)
  266. return Request.serializeResponseData(response: response, data: data, error: error)
  267. } catch {
  268. return .failure(AFError.responseSerializationFailed(reason: .inputFileReadFailed(at: fileURL)))
  269. }
  270. }
  271. }
  272. /// Adds a handler to be called once the request has finished.
  273. ///
  274. /// - parameter completionHandler: The code to be executed once the request has finished.
  275. ///
  276. /// - returns: The request.
  277. @discardableResult
  278. public func responseData(
  279. queue: DispatchQueue? = nil,
  280. completionHandler: @escaping (DownloadResponse<Data>) -> Void)
  281. -> Self
  282. {
  283. return response(
  284. queue: queue,
  285. responseSerializer: DownloadRequest.dataResponseSerializer(),
  286. completionHandler: completionHandler
  287. )
  288. }
  289. }
  290. // MARK: - String
  291. extension Request {
  292. /// Returns a result string type initialized from the response data with the specified string encoding.
  293. ///
  294. /// - parameter encoding: The string encoding. If `nil`, the string encoding will be determined from the server
  295. /// response, falling back to the default HTTP default character set, ISO-8859-1.
  296. /// - parameter response: The response from the server.
  297. /// - parameter data: The data returned from the server.
  298. /// - parameter error: The error already encountered if it exists.
  299. ///
  300. /// - returns: The result data type.
  301. public static func serializeResponseString(
  302. encoding: String.Encoding?,
  303. response: HTTPURLResponse?,
  304. data: Data?,
  305. error: Error?)
  306. -> Result<String>
  307. {
  308. guard error == nil else { return .failure(error!) }
  309. if let response = response, emptyDataStatusCodes.contains(response.statusCode) { return .success("") }
  310. guard let validData = data else {
  311. return .failure(AFError.responseSerializationFailed(reason: .inputDataNil))
  312. }
  313. var convertedEncoding = encoding
  314. if let encodingName = response?.textEncodingName as CFString!, convertedEncoding == nil {
  315. convertedEncoding = String.Encoding(rawValue: CFStringConvertEncodingToNSStringEncoding(
  316. CFStringConvertIANACharSetNameToEncoding(encodingName))
  317. )
  318. }
  319. let actualEncoding = convertedEncoding ?? String.Encoding.isoLatin1
  320. if let string = String(data: validData, encoding: actualEncoding) {
  321. return .success(string)
  322. } else {
  323. return .failure(AFError.responseSerializationFailed(reason: .stringSerializationFailed(encoding: actualEncoding)))
  324. }
  325. }
  326. }
  327. extension DataRequest {
  328. /// Creates a response serializer that returns a result string type initialized from the response data with
  329. /// the specified string encoding.
  330. ///
  331. /// - parameter encoding: The string encoding. If `nil`, the string encoding will be determined from the server
  332. /// response, falling back to the default HTTP default character set, ISO-8859-1.
  333. ///
  334. /// - returns: A string response serializer.
  335. public static func stringResponseSerializer(encoding: String.Encoding? = nil) -> DataResponseSerializer<String> {
  336. return DataResponseSerializer { _, response, data, error in
  337. return Request.serializeResponseString(encoding: encoding, response: response, data: data, error: error)
  338. }
  339. }
  340. /// Adds a handler to be called once the request has finished.
  341. ///
  342. /// - parameter encoding: The string encoding. If `nil`, the string encoding will be determined from the
  343. /// server response, falling back to the default HTTP default character set,
  344. /// ISO-8859-1.
  345. /// - parameter completionHandler: A closure to be executed once the request has finished.
  346. ///
  347. /// - returns: The request.
  348. @discardableResult
  349. public func responseString(
  350. queue: DispatchQueue? = nil,
  351. encoding: String.Encoding? = nil,
  352. completionHandler: @escaping (DataResponse<String>) -> Void)
  353. -> Self
  354. {
  355. return response(
  356. queue: queue,
  357. responseSerializer: DataRequest.stringResponseSerializer(encoding: encoding),
  358. completionHandler: completionHandler
  359. )
  360. }
  361. }
  362. extension DownloadRequest {
  363. /// Creates a response serializer that returns a result string type initialized from the response data with
  364. /// the specified string encoding.
  365. ///
  366. /// - parameter encoding: The string encoding. If `nil`, the string encoding will be determined from the server
  367. /// response, falling back to the default HTTP default character set, ISO-8859-1.
  368. ///
  369. /// - returns: A string response serializer.
  370. public static func stringResponseSerializer(encoding: String.Encoding? = nil) -> DownloadResponseSerializer<String> {
  371. return DownloadResponseSerializer { _, response, fileURL, error in
  372. guard error == nil else { return .failure(error!) }
  373. guard let fileURL = fileURL else {
  374. return .failure(AFError.responseSerializationFailed(reason: .inputFileNil))
  375. }
  376. do {
  377. let data = try Data(contentsOf: fileURL)
  378. return Request.serializeResponseString(encoding: encoding, response: response, data: data, error: error)
  379. } catch {
  380. return .failure(AFError.responseSerializationFailed(reason: .inputFileReadFailed(at: fileURL)))
  381. }
  382. }
  383. }
  384. /// Adds a handler to be called once the request has finished.
  385. ///
  386. /// - parameter encoding: The string encoding. If `nil`, the string encoding will be determined from the
  387. /// server response, falling back to the default HTTP default character set,
  388. /// ISO-8859-1.
  389. /// - parameter completionHandler: A closure to be executed once the request has finished.
  390. ///
  391. /// - returns: The request.
  392. @discardableResult
  393. public func responseString(
  394. queue: DispatchQueue? = nil,
  395. encoding: String.Encoding? = nil,
  396. completionHandler: @escaping (DownloadResponse<String>) -> Void)
  397. -> Self
  398. {
  399. return response(
  400. queue: queue,
  401. responseSerializer: DownloadRequest.stringResponseSerializer(encoding: encoding),
  402. completionHandler: completionHandler
  403. )
  404. }
  405. }
  406. // MARK: - JSON
  407. extension Request {
  408. /// Returns a JSON object contained in a result type constructed from the response data using `JSONSerialization`
  409. /// with the specified reading options.
  410. ///
  411. /// - parameter options: The JSON serialization reading options. Defaults to `.allowFragments`.
  412. /// - parameter response: The response from the server.
  413. /// - parameter data: The data returned from the server.
  414. /// - parameter error: The error already encountered if it exists.
  415. ///
  416. /// - returns: The result data type.
  417. public static func serializeResponseJSON(
  418. options: JSONSerialization.ReadingOptions,
  419. response: HTTPURLResponse?,
  420. data: Data?,
  421. error: Error?)
  422. -> Result<Any>
  423. {
  424. guard error == nil else { return .failure(error!) }
  425. if let response = response, emptyDataStatusCodes.contains(response.statusCode) { return .success(NSNull()) }
  426. guard let validData = data, validData.count > 0 else {
  427. return .failure(AFError.responseSerializationFailed(reason: .inputDataNilOrZeroLength))
  428. }
  429. do {
  430. let json = try JSONSerialization.jsonObject(with: validData, options: options)
  431. return .success(json)
  432. } catch {
  433. return .failure(AFError.responseSerializationFailed(reason: .jsonSerializationFailed(error: error)))
  434. }
  435. }
  436. }
  437. extension DataRequest {
  438. /// Creates a response serializer that returns a JSON object result type constructed from the response data using
  439. /// `JSONSerialization` with the specified reading options.
  440. ///
  441. /// - parameter options: The JSON serialization reading options. Defaults to `.allowFragments`.
  442. ///
  443. /// - returns: A JSON object response serializer.
  444. public static func jsonResponseSerializer(
  445. options: JSONSerialization.ReadingOptions = .allowFragments)
  446. -> DataResponseSerializer<Any>
  447. {
  448. return DataResponseSerializer { _, response, data, error in
  449. return Request.serializeResponseJSON(options: options, response: response, data: data, error: error)
  450. }
  451. }
  452. /// Adds a handler to be called once the request has finished.
  453. ///
  454. /// - parameter options: The JSON serialization reading options. Defaults to `.allowFragments`.
  455. /// - parameter completionHandler: A closure to be executed once the request has finished.
  456. ///
  457. /// - returns: The request.
  458. @discardableResult
  459. public func responseJSON(
  460. queue: DispatchQueue? = nil,
  461. options: JSONSerialization.ReadingOptions = .allowFragments,
  462. completionHandler: @escaping (DataResponse<Any>) -> Void)
  463. -> Self
  464. {
  465. return response(
  466. queue: queue,
  467. responseSerializer: DataRequest.jsonResponseSerializer(options: options),
  468. completionHandler: completionHandler
  469. )
  470. }
  471. }
  472. extension DownloadRequest {
  473. /// Creates a response serializer that returns a JSON object result type constructed from the response data using
  474. /// `JSONSerialization` with the specified reading options.
  475. ///
  476. /// - parameter options: The JSON serialization reading options. Defaults to `.allowFragments`.
  477. ///
  478. /// - returns: A JSON object response serializer.
  479. public static func jsonResponseSerializer(
  480. options: JSONSerialization.ReadingOptions = .allowFragments)
  481. -> DownloadResponseSerializer<Any>
  482. {
  483. return DownloadResponseSerializer { _, response, fileURL, error in
  484. guard error == nil else { return .failure(error!) }
  485. guard let fileURL = fileURL else {
  486. return .failure(AFError.responseSerializationFailed(reason: .inputFileNil))
  487. }
  488. do {
  489. let data = try Data(contentsOf: fileURL)
  490. return Request.serializeResponseJSON(options: options, response: response, data: data, error: error)
  491. } catch {
  492. return .failure(AFError.responseSerializationFailed(reason: .inputFileReadFailed(at: fileURL)))
  493. }
  494. }
  495. }
  496. /// Adds a handler to be called once the request has finished.
  497. ///
  498. /// - parameter options: The JSON serialization reading options. Defaults to `.allowFragments`.
  499. /// - parameter completionHandler: A closure to be executed once the request has finished.
  500. ///
  501. /// - returns: The request.
  502. @discardableResult
  503. public func responseJSON(
  504. queue: DispatchQueue? = nil,
  505. options: JSONSerialization.ReadingOptions = .allowFragments,
  506. completionHandler: @escaping (DownloadResponse<Any>) -> Void)
  507. -> Self
  508. {
  509. return response(
  510. queue: queue,
  511. responseSerializer: DownloadRequest.jsonResponseSerializer(options: options),
  512. completionHandler: completionHandler
  513. )
  514. }
  515. }
  516. // MARK: - Property List
  517. extension Request {
  518. /// Returns a plist object contained in a result type constructed from the response data using
  519. /// `PropertyListSerialization` with the specified reading options.
  520. ///
  521. /// - parameter options: The property list reading options. Defaults to `[]`.
  522. /// - parameter response: The response from the server.
  523. /// - parameter data: The data returned from the server.
  524. /// - parameter error: The error already encountered if it exists.
  525. ///
  526. /// - returns: The result data type.
  527. public static func serializeResponsePropertyList(
  528. options: PropertyListSerialization.ReadOptions,
  529. response: HTTPURLResponse?,
  530. data: Data?,
  531. error: Error?)
  532. -> Result<Any>
  533. {
  534. guard error == nil else { return .failure(error!) }
  535. if let response = response, emptyDataStatusCodes.contains(response.statusCode) { return .success(NSNull()) }
  536. guard let validData = data, validData.count > 0 else {
  537. return .failure(AFError.responseSerializationFailed(reason: .inputDataNilOrZeroLength))
  538. }
  539. do {
  540. let plist = try PropertyListSerialization.propertyList(from: validData, options: options, format: nil)
  541. return .success(plist)
  542. } catch {
  543. return .failure(AFError.responseSerializationFailed(reason: .propertyListSerializationFailed(error: error)))
  544. }
  545. }
  546. }
  547. extension DataRequest {
  548. /// Creates a response serializer that returns an object constructed from the response data using
  549. /// `PropertyListSerialization` with the specified reading options.
  550. ///
  551. /// - parameter options: The property list reading options. Defaults to `[]`.
  552. ///
  553. /// - returns: A property list object response serializer.
  554. public static func propertyListResponseSerializer(
  555. options: PropertyListSerialization.ReadOptions = [])
  556. -> DataResponseSerializer<Any>
  557. {
  558. return DataResponseSerializer { _, response, data, error in
  559. return Request.serializeResponsePropertyList(options: options, response: response, data: data, error: error)
  560. }
  561. }
  562. /// Adds a handler to be called once the request has finished.
  563. ///
  564. /// - parameter options: The property list reading options. Defaults to `[]`.
  565. /// - parameter completionHandler: A closure to be executed once the request has finished.
  566. ///
  567. /// - returns: The request.
  568. @discardableResult
  569. public func responsePropertyList(
  570. queue: DispatchQueue? = nil,
  571. options: PropertyListSerialization.ReadOptions = [],
  572. completionHandler: @escaping (DataResponse<Any>) -> Void)
  573. -> Self
  574. {
  575. return response(
  576. queue: queue,
  577. responseSerializer: DataRequest.propertyListResponseSerializer(options: options),
  578. completionHandler: completionHandler
  579. )
  580. }
  581. }
  582. extension DownloadRequest {
  583. /// Creates a response serializer that returns an object constructed from the response data using
  584. /// `PropertyListSerialization` with the specified reading options.
  585. ///
  586. /// - parameter options: The property list reading options. Defaults to `[]`.
  587. ///
  588. /// - returns: A property list object response serializer.
  589. public static func propertyListResponseSerializer(
  590. options: PropertyListSerialization.ReadOptions = [])
  591. -> DownloadResponseSerializer<Any>
  592. {
  593. return DownloadResponseSerializer { _, response, fileURL, error in
  594. guard error == nil else { return .failure(error!) }
  595. guard let fileURL = fileURL else {
  596. return .failure(AFError.responseSerializationFailed(reason: .inputFileNil))
  597. }
  598. do {
  599. let data = try Data(contentsOf: fileURL)
  600. return Request.serializeResponsePropertyList(options: options, response: response, data: data, error: error)
  601. } catch {
  602. return .failure(AFError.responseSerializationFailed(reason: .inputFileReadFailed(at: fileURL)))
  603. }
  604. }
  605. }
  606. /// Adds a handler to be called once the request has finished.
  607. ///
  608. /// - parameter options: The property list reading options. Defaults to `[]`.
  609. /// - parameter completionHandler: A closure to be executed once the request has finished.
  610. ///
  611. /// - returns: The request.
  612. @discardableResult
  613. public func responsePropertyList(
  614. queue: DispatchQueue? = nil,
  615. options: PropertyListSerialization.ReadOptions = [],
  616. completionHandler: @escaping (DownloadResponse<Any>) -> Void)
  617. -> Self
  618. {
  619. return response(
  620. queue: queue,
  621. responseSerializer: DownloadRequest.propertyListResponseSerializer(options: options),
  622. completionHandler: completionHandler
  623. )
  624. }
  625. }
  626. /// A set of HTTP response status code that do not contain response data.
  627. private let emptyDataStatusCodes: Set<Int> = [204, 205]