ResponseSerialization.swift 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607
  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. 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: - Timeline
  114. extension Request {
  115. var timeline: Timeline {
  116. let requestStartTime = self.startTime ?? CFAbsoluteTimeGetCurrent()
  117. let requestCompletedTime = self.endTime ?? CFAbsoluteTimeGetCurrent()
  118. let initialResponseTime = self.delegate.initialResponseTime ?? requestCompletedTime
  119. return Timeline(
  120. requestStartTime: requestStartTime,
  121. initialResponseTime: initialResponseTime,
  122. requestCompletedTime: requestCompletedTime,
  123. serializationCompletedTime: CFAbsoluteTimeGetCurrent()
  124. )
  125. }
  126. }
  127. // MARK: - Default
  128. extension DataRequest {
  129. /// Adds a handler to be called once the request has finished.
  130. ///
  131. /// - Parameters:
  132. /// - queue: The queue on which the completion handler is dispatched. Defaults to `nil`, which means
  133. /// the handler is called on `.main`.
  134. /// - completionHandler: The code to be executed once the request has finished.
  135. /// - Returns: The request.
  136. @discardableResult
  137. public func response(queue: DispatchQueue? = nil, completionHandler: @escaping (DefaultDataResponse) -> Void) -> Self {
  138. delegate.queue.addOperation {
  139. (queue ?? DispatchQueue.main).async {
  140. var dataResponse = DefaultDataResponse(
  141. request: self.request,
  142. response: self.response,
  143. data: self.delegate.data,
  144. error: self.delegate.error,
  145. timeline: self.timeline
  146. )
  147. dataResponse.add(self.delegate.metrics)
  148. completionHandler(dataResponse)
  149. }
  150. }
  151. return self
  152. }
  153. /// Adds a handler to be called once the request has finished.
  154. ///
  155. /// - Parameters:
  156. /// - queue: The queue on which the completion handler is dispatched. Defaults to `nil`, which means
  157. /// the handler is called on `.main`.
  158. /// - responseSerializer: The response serializer responsible for serializing the request, response, and data.
  159. /// - completionHandler: The code to be executed once the request has finished.
  160. /// - Returns: The request.
  161. @discardableResult
  162. public func response<T: DataResponseSerializerProtocol>(
  163. queue: DispatchQueue? = nil,
  164. responseSerializer: T,
  165. completionHandler: @escaping (DataResponse<T.SerializedObject>) -> Void)
  166. -> Self
  167. {
  168. delegate.queue.addOperation {
  169. let result = Result { try responseSerializer.serialize(request: self.request,
  170. response: self.response,
  171. data: self.delegate.data,
  172. error: self.delegate.error) }
  173. var dataResponse = DataResponse<T.SerializedObject>(
  174. request: self.request,
  175. response: self.response,
  176. data: self.delegate.data,
  177. result: result,
  178. timeline: self.timeline
  179. )
  180. dataResponse.add(self.delegate.metrics)
  181. (queue ?? .main).async { completionHandler(dataResponse) }
  182. }
  183. return self
  184. }
  185. }
  186. extension DownloadRequest {
  187. /// Adds a handler to be called once the request has finished.
  188. ///
  189. /// - Parameters:
  190. /// - queue: The queue on which the completion handler is dispatched. Defaults to `nil`, which means
  191. /// the handler is called on `.main`.
  192. /// - completionHandler: The code to be executed once the request has finished.
  193. /// - Returns: The request.
  194. @discardableResult
  195. public func response(
  196. queue: DispatchQueue? = nil,
  197. completionHandler: @escaping (DefaultDownloadResponse) -> Void)
  198. -> Self
  199. {
  200. delegate.queue.addOperation {
  201. (queue ?? .main).async {
  202. var downloadResponse = DefaultDownloadResponse(
  203. request: self.request,
  204. response: self.response,
  205. temporaryURL: self.downloadDelegate.temporaryURL,
  206. destinationURL: self.downloadDelegate.destinationURL,
  207. resumeData: self.downloadDelegate.resumeData,
  208. error: self.downloadDelegate.error,
  209. timeline: self.timeline
  210. )
  211. downloadResponse.add(self.delegate.metrics)
  212. completionHandler(downloadResponse)
  213. }
  214. }
  215. return self
  216. }
  217. /// Adds a handler to be called once the request has finished.
  218. ///
  219. /// - Parameters:
  220. /// - queue: The queue on which the completion handler is dispatched. Defaults to `nil`, which means
  221. /// the handler is called on `.main`.
  222. /// - responseSerializer: The response serializer responsible for serializing the request, response, and data
  223. /// contained in the destination url.
  224. /// - completionHandler: The code to be executed once the request has finished.
  225. /// - Returns: The request.
  226. @discardableResult
  227. public func response<T: DownloadResponseSerializerProtocol>(
  228. queue: DispatchQueue? = nil,
  229. responseSerializer: T,
  230. completionHandler: @escaping (DownloadResponse<T.SerializedObject>) -> Void)
  231. -> Self
  232. {
  233. delegate.queue.addOperation {
  234. let result = Result { try responseSerializer.serializeDownload(request: self.request,
  235. response: self.response,
  236. fileURL: self.downloadDelegate.fileURL,
  237. error: self.downloadDelegate.error) }
  238. var downloadResponse = DownloadResponse<T.SerializedObject>(
  239. request: self.request,
  240. response: self.response,
  241. temporaryURL: self.downloadDelegate.temporaryURL,
  242. destinationURL: self.downloadDelegate.destinationURL,
  243. resumeData: self.downloadDelegate.resumeData,
  244. result: result,
  245. timeline: self.timeline
  246. )
  247. downloadResponse.add(self.delegate.metrics)
  248. (queue ?? .main).async { completionHandler(downloadResponse) }
  249. }
  250. return self
  251. }
  252. }
  253. // MARK: - Data
  254. extension DataRequest {
  255. /// Adds a handler to be called once the request has finished.
  256. ///
  257. /// - Parameters:
  258. /// - queue: The queue on which the completion handler is dispatched. Defaults to `nil`, which means
  259. /// the handler is called on `.main`.
  260. /// - completionHandler: The code to be executed once the request has finished.
  261. /// - Returns: The request.
  262. @discardableResult
  263. public func responseData(
  264. queue: DispatchQueue? = nil,
  265. completionHandler: @escaping (DataResponse<Data>) -> Void)
  266. -> Self
  267. {
  268. return response(
  269. queue: queue,
  270. responseSerializer: DataResponseSerializer(),
  271. completionHandler: completionHandler
  272. )
  273. }
  274. }
  275. /// A `ResponseSerializer` that performs minimal reponse checking and returns any response data as-is. By default, a
  276. /// request returning `nil` or no data is considered an error. However, if the response is has a status code valid for
  277. /// empty responses (`204`, `205`), then an empty `Data` value is returned.
  278. public final class DataResponseSerializer: ResponseSerializer {
  279. public init() { }
  280. public func serialize(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) throws -> Data {
  281. guard error == nil else { throw error! }
  282. if let response = response, emptyDataStatusCodes.contains(response.statusCode) { return Data() }
  283. guard let validData = data else {
  284. throw AFError.responseSerializationFailed(reason: .inputDataNil)
  285. }
  286. return validData
  287. }
  288. }
  289. extension DownloadRequest {
  290. /// Adds a handler to be called once the request has finished.
  291. ///
  292. /// - Parameters:
  293. /// - queue: The queue on which the completion handler is dispatched. Defaults to `nil`, which means
  294. /// the handler is called on `.main`.
  295. /// - completionHandler: The code to be executed once the request has finished.
  296. /// - Returns: The request.
  297. @discardableResult
  298. public func responseData(
  299. queue: DispatchQueue? = nil,
  300. completionHandler: @escaping (DownloadResponse<Data>) -> Void)
  301. -> Self
  302. {
  303. return response(
  304. queue: queue,
  305. responseSerializer: DataResponseSerializer(),
  306. completionHandler: completionHandler
  307. )
  308. }
  309. }
  310. // MARK: - String
  311. /// A `ResponseSerializer` that decodes the response data as a `String`. By default, a request returning `nil` or no
  312. /// data is considered an error. However, if the response is has a status code valid for empty responses (`204`, `205`),
  313. /// then an empty `String` is returned.
  314. public final class StringResponseSerializer: ResponseSerializer {
  315. let encoding: String.Encoding?
  316. /// Creates an instance with the given `String.Encoding`.
  317. ///
  318. /// - Parameter encoding: A string encoding. Defaults to `nil`, in which case the encoding will be determined from
  319. /// the server response, falling back to the default HTTP character set, `ISO-8859-1`.
  320. public init(encoding: String.Encoding? = nil) {
  321. self.encoding = encoding
  322. }
  323. public func serialize(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) throws -> String {
  324. guard error == nil else { throw error! }
  325. if let response = response, emptyDataStatusCodes.contains(response.statusCode) { return "" }
  326. guard let validData = data else {
  327. throw AFError.responseSerializationFailed(reason: .inputDataNil)
  328. }
  329. var convertedEncoding = encoding
  330. if let encodingName = response?.textEncodingName as CFString!, convertedEncoding == nil {
  331. let ianaCharSet = CFStringConvertIANACharSetNameToEncoding(encodingName)
  332. let nsStringEncoding = CFStringConvertEncodingToNSStringEncoding(ianaCharSet)
  333. convertedEncoding = String.Encoding(rawValue: nsStringEncoding)
  334. }
  335. let actualEncoding = convertedEncoding ?? .isoLatin1
  336. guard let string = String(data: validData, encoding: actualEncoding) else {
  337. throw AFError.responseSerializationFailed(reason: .stringSerializationFailed(encoding: actualEncoding))
  338. }
  339. return string
  340. }
  341. }
  342. extension DataRequest {
  343. /// Adds a handler to be called once the request has finished.
  344. ///
  345. /// - Parameters:
  346. /// - queue: The queue on which the completion handler is dispatched. Defaults to `nil`, which means
  347. /// the handler is called on `.main`.
  348. /// - encoding: The string encoding. Defaults to `nil`, in which case the encoding will be determined from
  349. /// the server response, falling back to the default HTTP character set, `ISO-8859-1`.
  350. /// - completionHandler: A closure to be executed once the request has finished.
  351. /// - Returns: The request.
  352. @discardableResult
  353. public func responseString(
  354. queue: DispatchQueue? = nil,
  355. encoding: String.Encoding? = nil,
  356. completionHandler: @escaping (DataResponse<String>) -> Void)
  357. -> Self
  358. {
  359. return response(
  360. queue: queue,
  361. responseSerializer: StringResponseSerializer(encoding: encoding),
  362. completionHandler: completionHandler
  363. )
  364. }
  365. }
  366. extension DownloadRequest {
  367. /// Adds a handler to be called once the request has finished.
  368. ///
  369. /// - Parameters:
  370. /// - queue: The queue on which the completion handler is dispatched. Defaults to `nil`, which means
  371. /// the handler is called on `.main`.
  372. /// - encoding: The string encoding. Defaults to `nil`, in which case the encoding will be determined from
  373. /// the server response, falling back to the default HTTP character set, `ISO-8859-1`.
  374. /// - completionHandler: A closure to be executed once the request has finished.
  375. /// - Returns: The request.
  376. @discardableResult
  377. public func responseString(
  378. queue: DispatchQueue? = nil,
  379. encoding: String.Encoding? = nil,
  380. completionHandler: @escaping (DownloadResponse<String>) -> Void)
  381. -> Self
  382. {
  383. return response(
  384. queue: queue,
  385. responseSerializer: StringResponseSerializer(encoding: encoding),
  386. completionHandler: completionHandler
  387. )
  388. }
  389. }
  390. // MARK: - JSON
  391. /// A `ResponseSerializer` that decodes the response data using `JSONSerialization`. By default, a request returning
  392. /// `nil` or no data is considered an error. However, if the response is has a status code valid for empty responses
  393. /// (`204`, `205`), then an `NSNull` value is returned.
  394. public final class JSONResponseSerializer: ResponseSerializer {
  395. let options: JSONSerialization.ReadingOptions
  396. /// Creates an instance with the given `JSONSerilization.ReadingOptions`.
  397. ///
  398. /// - Parameter options: The options to use. Defaults to `.allowFragments`.
  399. public init(options: JSONSerialization.ReadingOptions = .allowFragments) {
  400. self.options = options
  401. }
  402. public func serialize(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) throws -> Any {
  403. guard error == nil else { throw error! }
  404. guard let validData = data, validData.count > 0 else {
  405. if let response = response, emptyDataStatusCodes.contains(response.statusCode) {
  406. return NSNull()
  407. }
  408. throw AFError.responseSerializationFailed(reason: .inputDataNilOrZeroLength)
  409. }
  410. do {
  411. return try JSONSerialization.jsonObject(with: validData, options: options)
  412. } catch {
  413. throw AFError.responseSerializationFailed(reason: .jsonSerializationFailed(error: error))
  414. }
  415. }
  416. }
  417. extension DataRequest {
  418. /// Adds a handler to be called once the request has finished.
  419. ///
  420. /// - Parameters:
  421. /// - queue: The queue on which the completion handler is dispatched. Defaults to `nil`, which means
  422. /// the handler is called on `.main`.
  423. /// - options: The JSON serialization reading options. Defaults to `.allowFragments`.
  424. /// - completionHandler: A closure to be executed once the request has finished.
  425. /// - Returns: The request.
  426. @discardableResult
  427. public func responseJSON(
  428. queue: DispatchQueue? = nil,
  429. options: JSONSerialization.ReadingOptions = .allowFragments,
  430. completionHandler: @escaping (DataResponse<Any>) -> Void)
  431. -> Self
  432. {
  433. return response(
  434. queue: queue,
  435. responseSerializer: JSONResponseSerializer(options: options),
  436. completionHandler: completionHandler
  437. )
  438. }
  439. }
  440. extension DownloadRequest {
  441. /// Adds a handler to be called once the request has finished.
  442. ///
  443. /// - Parameters:
  444. /// - queue: The queue on which the completion handler is dispatched. Defaults to `nil`, which means
  445. /// the handler is called on `.main`.
  446. /// - options: The JSON serialization reading options. Defaults to `.allowFragments`.
  447. /// - completionHandler: A closure to be executed once the request has finished.
  448. /// - Returns: The request.
  449. @discardableResult
  450. public func responseJSON(
  451. queue: DispatchQueue? = nil,
  452. options: JSONSerialization.ReadingOptions = .allowFragments,
  453. completionHandler: @escaping (DownloadResponse<Any>) -> Void)
  454. -> Self
  455. {
  456. return response(
  457. queue: queue,
  458. responseSerializer: JSONResponseSerializer(options: options),
  459. completionHandler: completionHandler
  460. )
  461. }
  462. }
  463. // MARK: - Empty
  464. /// A type representing an empty response. Use `Empty.response` to get the instance.
  465. public struct Empty: Decodable {
  466. public static let response = Empty()
  467. }
  468. // MARK: - JSON Decodable
  469. /// A `ResponseSerializer` that decodes the response data as a generic value using a `JSONDecoder`. By default, a
  470. /// request returning `nil` or no data is considered an error. However, if the response is has a status code valid for
  471. /// empty responses (`204`, `205`), then the `Empty.response` value is returned.
  472. public final class JSONDecodableResponseSerializer<T: Decodable>: ResponseSerializer {
  473. let decoder: JSONDecoder
  474. /// Creates an instance with the given `JSONDecoder` instance.
  475. ///
  476. /// - Parameter decoder: A decoder. Defaults to a `JSONDecoder` with default settings.
  477. public init(decoder: JSONDecoder = JSONDecoder()) {
  478. self.decoder = decoder
  479. }
  480. public func serialize(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) throws -> T {
  481. guard error == nil else { throw error! }
  482. guard let validData = data, validData.count > 0 else {
  483. if let response = response, emptyDataStatusCodes.contains(response.statusCode) {
  484. guard let emptyResponse = Empty.response as? T else {
  485. throw AFError.responseSerializationFailed(reason: .invalidEmptyResponse(type: "\(T.self)"))
  486. }
  487. return emptyResponse
  488. }
  489. throw AFError.responseSerializationFailed(reason: .inputDataNilOrZeroLength)
  490. }
  491. do {
  492. return try decoder.decode(T.self, from: validData)
  493. } catch {
  494. throw error
  495. }
  496. }
  497. }
  498. extension DataRequest {
  499. /// Adds a handler to be called once the request has finished.
  500. ///
  501. /// - Parameters:
  502. /// - queue: The queue on which the completion handler is dispatched. Defaults to `nil`, which means
  503. /// the handler is called on `.main`.
  504. /// - decoder: The decoder to use to decode the response. Defaults to a `JSONDecoder` with default
  505. /// settings.
  506. /// - completionHandler: A closure to be executed once the request has finished.
  507. /// - Returns: The request.
  508. @discardableResult
  509. public func responseJSONDecodable<T: Decodable>(
  510. queue: DispatchQueue? = nil,
  511. decoder: JSONDecoder = JSONDecoder(),
  512. completionHandler: @escaping (DataResponse<T>) -> Void)
  513. -> Self
  514. {
  515. return response(
  516. queue: queue,
  517. responseSerializer: JSONDecodableResponseSerializer(decoder: decoder),
  518. completionHandler: completionHandler
  519. )
  520. }
  521. }
  522. /// A set of HTTP response status code that do not contain response data.
  523. private let emptyDataStatusCodes: Set<Int> = [204, 205]