ResponseSerialization.swift 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  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. // MARK: ResponseSerializer
  26. /**
  27. The type in which all response serializers must conform to in order to serialize a response.
  28. */
  29. public protocol ResponseSerializerType {
  30. /// The type of serialized object to be created by this `ResponseSerializerType`.
  31. associatedtype SerializedObject
  32. /// The type of error to be created by this `ResponseSerializer` if serialization fails.
  33. associatedtype ErrorObject: ErrorType
  34. /**
  35. A closure used by response handlers that takes a request, response, data and error and returns a result.
  36. */
  37. var serializeResponse: (NSURLRequest?, NSHTTPURLResponse?, NSData?, NSError?) -> Result<SerializedObject, ErrorObject> { get }
  38. }
  39. // MARK: -
  40. /**
  41. A generic `ResponseSerializerType` used to serialize a request, response, and data into a serialized object.
  42. */
  43. public struct ResponseSerializer<Value, Error: ErrorType>: ResponseSerializerType {
  44. /// The type of serialized object to be created by this `ResponseSerializer`.
  45. public typealias SerializedObject = Value
  46. /// The type of error to be created by this `ResponseSerializer` if serialization fails.
  47. public typealias ErrorObject = Error
  48. /**
  49. A closure used by response handlers that takes a request, response, data and error and returns a result.
  50. */
  51. public var serializeResponse: (NSURLRequest?, NSHTTPURLResponse?, NSData?, NSError?) -> Result<Value, Error>
  52. /**
  53. Initializes the `ResponseSerializer` instance with the given serialize response closure.
  54. - parameter serializeResponse: The closure used to serialize the response.
  55. - returns: The new generic response serializer instance.
  56. */
  57. public init(serializeResponse: (NSURLRequest?, NSHTTPURLResponse?, NSData?, NSError?) -> Result<Value, Error>) {
  58. self.serializeResponse = serializeResponse
  59. }
  60. }
  61. // MARK: - Default
  62. extension Request {
  63. /**
  64. Adds a handler to be called once the request has finished.
  65. - parameter queue: The queue on which the completion handler is dispatched.
  66. - parameter completionHandler: The code to be executed once the request has finished.
  67. - returns: The request.
  68. */
  69. public func response(
  70. queue queue: dispatch_queue_t? = nil,
  71. completionHandler: (NSURLRequest?, NSHTTPURLResponse?, NSData?, NSError?) -> Void)
  72. -> Self
  73. {
  74. delegate.queue.addOperationWithBlock {
  75. dispatch_async(queue ?? dispatch_get_main_queue()) {
  76. completionHandler(self.request, self.response, self.delegate.data, self.delegate.error)
  77. }
  78. }
  79. return self
  80. }
  81. /**
  82. Adds a handler to be called once the request has finished.
  83. - parameter queue: The queue on which the completion handler is dispatched.
  84. - parameter responseSerializer: The response serializer responsible for serializing the request, response,
  85. and data.
  86. - parameter completionHandler: The code to be executed once the request has finished.
  87. - returns: The request.
  88. */
  89. public func response<T: ResponseSerializerType>(
  90. queue queue: dispatch_queue_t? = nil,
  91. responseSerializer: T,
  92. completionHandler: Response<T.SerializedObject, T.ErrorObject> -> Void)
  93. -> Self
  94. {
  95. delegate.queue.addOperationWithBlock {
  96. let result = responseSerializer.serializeResponse(
  97. self.request,
  98. self.response,
  99. self.delegate.data,
  100. self.delegate.error
  101. )
  102. let requestCompletedTime = self.endTime ?? CFAbsoluteTimeGetCurrent()
  103. let initialResponseTime = self.delegate.initialResponseTime ?? requestCompletedTime
  104. let timeline = Timeline(
  105. requestStartTime: self.startTime ?? CFAbsoluteTimeGetCurrent(),
  106. initialResponseTime: initialResponseTime,
  107. requestCompletedTime: requestCompletedTime,
  108. serializationCompletedTime: CFAbsoluteTimeGetCurrent()
  109. )
  110. let response = Response<T.SerializedObject, T.ErrorObject>(
  111. request: self.request,
  112. response: self.response,
  113. data: self.delegate.data,
  114. result: result,
  115. timeline: timeline
  116. )
  117. dispatch_async(queue ?? dispatch_get_main_queue()) { completionHandler(response) }
  118. }
  119. return self
  120. }
  121. }
  122. // MARK: - Data
  123. extension Request {
  124. /**
  125. Creates a response serializer that returns the associated data as-is.
  126. - returns: A data response serializer.
  127. */
  128. public static func dataResponseSerializer() -> ResponseSerializer<NSData, NSError> {
  129. return ResponseSerializer { _, response, data, error in
  130. guard error == nil else { return .Failure(error!) }
  131. if let response = response where response.statusCode == 204 { return .Success(NSData()) }
  132. guard let validData = data else {
  133. let failureReason = "Data could not be serialized. Input data was nil."
  134. let error = Error.error(code: .DataSerializationFailed, failureReason: failureReason)
  135. return .Failure(error)
  136. }
  137. return .Success(validData)
  138. }
  139. }
  140. /**
  141. Adds a handler to be called once the request has finished.
  142. - parameter completionHandler: The code to be executed once the request has finished.
  143. - returns: The request.
  144. */
  145. public func responseData(
  146. queue queue: dispatch_queue_t? = nil,
  147. completionHandler: Response<NSData, NSError> -> Void)
  148. -> Self
  149. {
  150. return response(queue: queue, responseSerializer: Request.dataResponseSerializer(), completionHandler: completionHandler)
  151. }
  152. }
  153. // MARK: - String
  154. extension Request {
  155. /**
  156. Creates a response serializer that returns a string initialized from the response data with the specified
  157. string encoding.
  158. - parameter encoding: The string encoding. If `nil`, the string encoding will be determined from the server
  159. response, falling back to the default HTTP default character set, ISO-8859-1.
  160. - returns: A string response serializer.
  161. */
  162. public static func stringResponseSerializer(
  163. encoding encoding: NSStringEncoding? = nil)
  164. -> ResponseSerializer<String, NSError>
  165. {
  166. return ResponseSerializer { _, response, data, error in
  167. guard error == nil else { return .Failure(error!) }
  168. if let response = response where response.statusCode == 204 { return .Success("") }
  169. guard let validData = data else {
  170. let failureReason = "String could not be serialized. Input data was nil."
  171. let error = Error.error(code: .StringSerializationFailed, failureReason: failureReason)
  172. return .Failure(error)
  173. }
  174. var convertedEncoding = encoding
  175. if let encodingName = response?.textEncodingName where convertedEncoding == nil {
  176. convertedEncoding = CFStringConvertEncodingToNSStringEncoding(
  177. CFStringConvertIANACharSetNameToEncoding(encodingName)
  178. )
  179. }
  180. let actualEncoding = convertedEncoding ?? NSISOLatin1StringEncoding
  181. if let string = String(data: validData, encoding: actualEncoding) {
  182. return .Success(string)
  183. } else {
  184. let failureReason = "String could not be serialized with encoding: \(actualEncoding)"
  185. let error = Error.error(code: .StringSerializationFailed, failureReason: failureReason)
  186. return .Failure(error)
  187. }
  188. }
  189. }
  190. /**
  191. Adds a handler to be called once the request has finished.
  192. - parameter encoding: The string encoding. If `nil`, the string encoding will be determined from the
  193. server response, falling back to the default HTTP default character set,
  194. ISO-8859-1.
  195. - parameter completionHandler: A closure to be executed once the request has finished.
  196. - returns: The request.
  197. */
  198. public func responseString(
  199. queue queue: dispatch_queue_t? = nil,
  200. encoding: NSStringEncoding? = nil,
  201. completionHandler: Response<String, NSError> -> Void)
  202. -> Self
  203. {
  204. return response(
  205. queue: queue,
  206. responseSerializer: Request.stringResponseSerializer(encoding: encoding),
  207. completionHandler: completionHandler
  208. )
  209. }
  210. }
  211. // MARK: - JSON
  212. extension Request {
  213. /**
  214. Creates a response serializer that returns a JSON object constructed from the response data using
  215. `NSJSONSerialization` with the specified reading options.
  216. - parameter options: The JSON serialization reading options. `.AllowFragments` by default.
  217. - returns: A JSON object response serializer.
  218. */
  219. public static func JSONResponseSerializer(
  220. options options: NSJSONReadingOptions = .AllowFragments)
  221. -> ResponseSerializer<AnyObject, NSError>
  222. {
  223. return ResponseSerializer { _, response, data, error in
  224. guard error == nil else { return .Failure(error!) }
  225. if let response = response where response.statusCode == 204 { return .Success(NSNull()) }
  226. guard let validData = data where validData.length > 0 else {
  227. let failureReason = "JSON could not be serialized. Input data was nil or zero length."
  228. let error = Error.error(code: .JSONSerializationFailed, failureReason: failureReason)
  229. return .Failure(error)
  230. }
  231. do {
  232. let JSON = try NSJSONSerialization.JSONObjectWithData(validData, options: options)
  233. return .Success(JSON)
  234. } catch {
  235. return .Failure(error as NSError)
  236. }
  237. }
  238. }
  239. /**
  240. Adds a handler to be called once the request has finished.
  241. - parameter options: The JSON serialization reading options. `.AllowFragments` by default.
  242. - parameter completionHandler: A closure to be executed once the request has finished.
  243. - returns: The request.
  244. */
  245. public func responseJSON(
  246. queue queue: dispatch_queue_t? = nil,
  247. options: NSJSONReadingOptions = .AllowFragments,
  248. completionHandler: Response<AnyObject, NSError> -> Void)
  249. -> Self
  250. {
  251. return response(
  252. queue: queue,
  253. responseSerializer: Request.JSONResponseSerializer(options: options),
  254. completionHandler: completionHandler
  255. )
  256. }
  257. }
  258. // MARK: - Property List
  259. extension Request {
  260. /**
  261. Creates a response serializer that returns an object constructed from the response data using
  262. `NSPropertyListSerialization` with the specified reading options.
  263. - parameter options: The property list reading options. `NSPropertyListReadOptions()` by default.
  264. - returns: A property list object response serializer.
  265. */
  266. public static func propertyListResponseSerializer(
  267. options options: NSPropertyListReadOptions = NSPropertyListReadOptions())
  268. -> ResponseSerializer<AnyObject, NSError>
  269. {
  270. return ResponseSerializer { _, response, data, error in
  271. guard error == nil else { return .Failure(error!) }
  272. if let response = response where response.statusCode == 204 { return .Success(NSNull()) }
  273. guard let validData = data where validData.length > 0 else {
  274. let failureReason = "Property list could not be serialized. Input data was nil or zero length."
  275. let error = Error.error(code: .PropertyListSerializationFailed, failureReason: failureReason)
  276. return .Failure(error)
  277. }
  278. do {
  279. let plist = try NSPropertyListSerialization.propertyListWithData(validData, options: options, format: nil)
  280. return .Success(plist)
  281. } catch {
  282. return .Failure(error as NSError)
  283. }
  284. }
  285. }
  286. /**
  287. Adds a handler to be called once the request has finished.
  288. - parameter options: The property list reading options. `0` by default.
  289. - parameter completionHandler: A closure to be executed once the request has finished. The closure takes 3
  290. arguments: the URL request, the URL response, the server data and the result
  291. produced while creating the property list.
  292. - returns: The request.
  293. */
  294. public func responsePropertyList(
  295. queue queue: dispatch_queue_t? = nil,
  296. options: NSPropertyListReadOptions = NSPropertyListReadOptions(),
  297. completionHandler: Response<AnyObject, NSError> -> Void)
  298. -> Self
  299. {
  300. return response(
  301. queue: queue,
  302. responseSerializer: Request.propertyListResponseSerializer(options: options),
  303. completionHandler: completionHandler
  304. )
  305. }
  306. }