PageRenderTime 48ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/Pods/Alamofire/Source/Manager.swift

https://gitlab.com/pkgroup1/Pokedex
Swift | 695 lines | 341 code | 93 blank | 261 comment | 51 complexity | 5dfbeeff06c32d96b4e90b232fff9378 MD5 | raw file
  1. // Manager.swift
  2. //
  3. // Copyright (c) 2014–2016 Alamofire Software Foundation (http://alamofire.org/)
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. import Foundation
  23. /**
  24. Responsible for creating and managing `Request` objects, as well as their underlying `NSURLSession`.
  25. */
  26. public class Manager {
  27. // MARK: - Properties
  28. /**
  29. A shared instance of `Manager`, used by top-level Alamofire request methods, and suitable for use directly
  30. for any ad hoc requests.
  31. */
  32. public static let sharedInstance: Manager = {
  33. let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
  34. configuration.HTTPAdditionalHeaders = Manager.defaultHTTPHeaders
  35. return Manager(configuration: configuration)
  36. }()
  37. /**
  38. Creates default values for the "Accept-Encoding", "Accept-Language" and "User-Agent" headers.
  39. */
  40. public static let defaultHTTPHeaders: [String: String] = {
  41. // Accept-Encoding HTTP Header; see https://tools.ietf.org/html/rfc7230#section-4.2.3
  42. let acceptEncoding: String = "gzip;q=1.0, compress;q=0.5"
  43. // Accept-Language HTTP Header; see https://tools.ietf.org/html/rfc7231#section-5.3.5
  44. let acceptLanguage = NSLocale.preferredLanguages().prefix(6).enumerate().map { index, languageCode in
  45. let quality = 1.0 - (Double(index) * 0.1)
  46. return "\(languageCode);q=\(quality)"
  47. }.joinWithSeparator(", ")
  48. // User-Agent Header; see https://tools.ietf.org/html/rfc7231#section-5.5.3
  49. let userAgent: String = {
  50. if let info = NSBundle.mainBundle().infoDictionary {
  51. let executable: AnyObject = info[kCFBundleExecutableKey as String] ?? "Unknown"
  52. let bundle: AnyObject = info[kCFBundleIdentifierKey as String] ?? "Unknown"
  53. let version: AnyObject = info[kCFBundleVersionKey as String] ?? "Unknown"
  54. let os: AnyObject = NSProcessInfo.processInfo().operatingSystemVersionString ?? "Unknown"
  55. var mutableUserAgent = NSMutableString(string: "\(executable)/\(bundle) (\(version); OS \(os))") as CFMutableString
  56. let transform = NSString(string: "Any-Latin; Latin-ASCII; [:^ASCII:] Remove") as CFString
  57. if CFStringTransform(mutableUserAgent, UnsafeMutablePointer<CFRange>(nil), transform, false) {
  58. return mutableUserAgent as String
  59. }
  60. }
  61. return "Alamofire"
  62. }()
  63. return [
  64. "Accept-Encoding": acceptEncoding,
  65. "Accept-Language": acceptLanguage,
  66. "User-Agent": userAgent
  67. ]
  68. }()
  69. let queue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL)
  70. /// The underlying session.
  71. public let session: NSURLSession
  72. /// The session delegate handling all the task and session delegate callbacks.
  73. public let delegate: SessionDelegate
  74. /// Whether to start requests immediately after being constructed. `true` by default.
  75. public var startRequestsImmediately: Bool = true
  76. /**
  77. The background completion handler closure provided by the UIApplicationDelegate
  78. `application:handleEventsForBackgroundURLSession:completionHandler:` method. By setting the background
  79. completion handler, the SessionDelegate `sessionDidFinishEventsForBackgroundURLSession` closure implementation
  80. will automatically call the handler.
  81. If you need to handle your own events before the handler is called, then you need to override the
  82. SessionDelegate `sessionDidFinishEventsForBackgroundURLSession` and manually call the handler when finished.
  83. `nil` by default.
  84. */
  85. public var backgroundCompletionHandler: (() -> Void)?
  86. // MARK: - Lifecycle
  87. /**
  88. Initializes the `Manager` instance with the specified configuration, delegate and server trust policy.
  89. - parameter configuration: The configuration used to construct the managed session.
  90. `NSURLSessionConfiguration.defaultSessionConfiguration()` by default.
  91. - parameter delegate: The delegate used when initializing the session. `SessionDelegate()` by
  92. default.
  93. - parameter serverTrustPolicyManager: The server trust policy manager to use for evaluating all server trust
  94. challenges. `nil` by default.
  95. - returns: The new `Manager` instance.
  96. */
  97. public init(
  98. configuration: NSURLSessionConfiguration = NSURLSessionConfiguration.defaultSessionConfiguration(),
  99. delegate: SessionDelegate = SessionDelegate(),
  100. serverTrustPolicyManager: ServerTrustPolicyManager? = nil)
  101. {
  102. self.delegate = delegate
  103. self.session = NSURLSession(configuration: configuration, delegate: delegate, delegateQueue: nil)
  104. commonInit(serverTrustPolicyManager: serverTrustPolicyManager)
  105. }
  106. /**
  107. Initializes the `Manager` instance with the specified session, delegate and server trust policy.
  108. - parameter session: The URL session.
  109. - parameter delegate: The delegate of the URL session. Must equal the URL session's delegate.
  110. - parameter serverTrustPolicyManager: The server trust policy manager to use for evaluating all server trust
  111. challenges. `nil` by default.
  112. - returns: The new `Manager` instance if the URL session's delegate matches the delegate parameter.
  113. */
  114. public init?(
  115. session: NSURLSession,
  116. delegate: SessionDelegate,
  117. serverTrustPolicyManager: ServerTrustPolicyManager? = nil)
  118. {
  119. self.delegate = delegate
  120. self.session = session
  121. guard delegate === session.delegate else { return nil }
  122. commonInit(serverTrustPolicyManager: serverTrustPolicyManager)
  123. }
  124. private func commonInit(serverTrustPolicyManager serverTrustPolicyManager: ServerTrustPolicyManager?) {
  125. session.serverTrustPolicyManager = serverTrustPolicyManager
  126. delegate.sessionDidFinishEventsForBackgroundURLSession = { [weak self] session in
  127. guard let strongSelf = self else { return }
  128. dispatch_async(dispatch_get_main_queue()) { strongSelf.backgroundCompletionHandler?() }
  129. }
  130. }
  131. deinit {
  132. session.invalidateAndCancel()
  133. }
  134. // MARK: - Request
  135. /**
  136. Creates a request for the specified method, URL string, parameters, parameter encoding and headers.
  137. - parameter method: The HTTP method.
  138. - parameter URLString: The URL string.
  139. - parameter parameters: The parameters. `nil` by default.
  140. - parameter encoding: The parameter encoding. `.URL` by default.
  141. - parameter headers: The HTTP headers. `nil` by default.
  142. - returns: The created request.
  143. */
  144. public func request(
  145. method: Method,
  146. _ URLString: URLStringConvertible,
  147. parameters: [String: AnyObject]? = nil,
  148. encoding: ParameterEncoding = .URL,
  149. headers: [String: String]? = nil)
  150. -> Request
  151. {
  152. let mutableURLRequest = URLRequest(method, URLString, headers: headers)
  153. let encodedURLRequest = encoding.encode(mutableURLRequest, parameters: parameters).0
  154. return request(encodedURLRequest)
  155. }
  156. /**
  157. Creates a request for the specified URL request.
  158. If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.
  159. - parameter URLRequest: The URL request
  160. - returns: The created request.
  161. */
  162. public func request(URLRequest: URLRequestConvertible) -> Request {
  163. var dataTask: NSURLSessionDataTask!
  164. dispatch_sync(queue) { dataTask = self.session.dataTaskWithRequest(URLRequest.URLRequest) }
  165. let request = Request(session: session, task: dataTask)
  166. delegate[request.delegate.task] = request.delegate
  167. if startRequestsImmediately {
  168. request.resume()
  169. }
  170. return request
  171. }
  172. // MARK: - SessionDelegate
  173. /**
  174. Responsible for handling all delegate callbacks for the underlying session.
  175. */
  176. public final class SessionDelegate: NSObject, NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate {
  177. private var subdelegates: [Int: Request.TaskDelegate] = [:]
  178. private let subdelegateQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_CONCURRENT)
  179. subscript(task: NSURLSessionTask) -> Request.TaskDelegate? {
  180. get {
  181. var subdelegate: Request.TaskDelegate?
  182. dispatch_sync(subdelegateQueue) { subdelegate = self.subdelegates[task.taskIdentifier] }
  183. return subdelegate
  184. }
  185. set {
  186. dispatch_barrier_async(subdelegateQueue) { self.subdelegates[task.taskIdentifier] = newValue }
  187. }
  188. }
  189. /**
  190. Initializes the `SessionDelegate` instance.
  191. - returns: The new `SessionDelegate` instance.
  192. */
  193. public override init() {
  194. super.init()
  195. }
  196. // MARK: - NSURLSessionDelegate
  197. // MARK: Override Closures
  198. /// Overrides default behavior for NSURLSessionDelegate method `URLSession:didBecomeInvalidWithError:`.
  199. public var sessionDidBecomeInvalidWithError: ((NSURLSession, NSError?) -> Void)?
  200. /// Overrides default behavior for NSURLSessionDelegate method `URLSession:didReceiveChallenge:completionHandler:`.
  201. public var sessionDidReceiveChallenge: ((NSURLSession, NSURLAuthenticationChallenge) -> (NSURLSessionAuthChallengeDisposition, NSURLCredential?))?
  202. /// Overrides default behavior for NSURLSessionDelegate method `URLSessionDidFinishEventsForBackgroundURLSession:`.
  203. public var sessionDidFinishEventsForBackgroundURLSession: ((NSURLSession) -> Void)?
  204. // MARK: Delegate Methods
  205. /**
  206. Tells the delegate that the session has been invalidated.
  207. - parameter session: The session object that was invalidated.
  208. - parameter error: The error that caused invalidation, or nil if the invalidation was explicit.
  209. */
  210. public func URLSession(session: NSURLSession, didBecomeInvalidWithError error: NSError?) {
  211. sessionDidBecomeInvalidWithError?(session, error)
  212. }
  213. /**
  214. Requests credentials from the delegate in response to a session-level authentication request from the remote server.
  215. - parameter session: The session containing the task that requested authentication.
  216. - parameter challenge: An object that contains the request for authentication.
  217. - parameter completionHandler: A handler that your delegate method must call providing the disposition and credential.
  218. */
  219. public func URLSession(
  220. session: NSURLSession,
  221. didReceiveChallenge challenge: NSURLAuthenticationChallenge,
  222. completionHandler: ((NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void))
  223. {
  224. var disposition: NSURLSessionAuthChallengeDisposition = .PerformDefaultHandling
  225. var credential: NSURLCredential?
  226. if let sessionDidReceiveChallenge = sessionDidReceiveChallenge {
  227. (disposition, credential) = sessionDidReceiveChallenge(session, challenge)
  228. } else if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
  229. let host = challenge.protectionSpace.host
  230. if let
  231. serverTrustPolicy = session.serverTrustPolicyManager?.serverTrustPolicyForHost(host),
  232. serverTrust = challenge.protectionSpace.serverTrust
  233. {
  234. if serverTrustPolicy.evaluateServerTrust(serverTrust, isValidForHost: host) {
  235. disposition = .UseCredential
  236. credential = NSURLCredential(forTrust: serverTrust)
  237. } else {
  238. disposition = .CancelAuthenticationChallenge
  239. }
  240. }
  241. }
  242. completionHandler(disposition, credential)
  243. }
  244. /**
  245. Tells the delegate that all messages enqueued for a session have been delivered.
  246. - parameter session: The session that no longer has any outstanding requests.
  247. */
  248. public func URLSessionDidFinishEventsForBackgroundURLSession(session: NSURLSession) {
  249. sessionDidFinishEventsForBackgroundURLSession?(session)
  250. }
  251. // MARK: - NSURLSessionTaskDelegate
  252. // MARK: Override Closures
  253. /// Overrides default behavior for NSURLSessionTaskDelegate method `URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:`.
  254. public var taskWillPerformHTTPRedirection: ((NSURLSession, NSURLSessionTask, NSHTTPURLResponse, NSURLRequest) -> NSURLRequest?)?
  255. /// Overrides default behavior for NSURLSessionTaskDelegate method `URLSession:task:didReceiveChallenge:completionHandler:`.
  256. public var taskDidReceiveChallenge: ((NSURLSession, NSURLSessionTask, NSURLAuthenticationChallenge) -> (NSURLSessionAuthChallengeDisposition, NSURLCredential?))?
  257. /// Overrides default behavior for NSURLSessionTaskDelegate method `URLSession:session:task:needNewBodyStream:`.
  258. public var taskNeedNewBodyStream: ((NSURLSession, NSURLSessionTask) -> NSInputStream!)?
  259. /// Overrides default behavior for NSURLSessionTaskDelegate method `URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:`.
  260. public var taskDidSendBodyData: ((NSURLSession, NSURLSessionTask, Int64, Int64, Int64) -> Void)?
  261. /// Overrides default behavior for NSURLSessionTaskDelegate method `URLSession:task:didCompleteWithError:`.
  262. public var taskDidComplete: ((NSURLSession, NSURLSessionTask, NSError?) -> Void)?
  263. // MARK: Delegate Methods
  264. /**
  265. Tells the delegate that the remote server requested an HTTP redirect.
  266. - parameter session: The session containing the task whose request resulted in a redirect.
  267. - parameter task: The task whose request resulted in a redirect.
  268. - parameter response: An object containing the server’s response to the original request.
  269. - parameter request: A URL request object filled out with the new location.
  270. - parameter completionHandler: A closure that your handler should call with either the value of the request
  271. parameter, a modified URL request object, or NULL to refuse the redirect and
  272. return the body of the redirect response.
  273. */
  274. public func URLSession(
  275. session: NSURLSession,
  276. task: NSURLSessionTask,
  277. willPerformHTTPRedirection response: NSHTTPURLResponse,
  278. newRequest request: NSURLRequest,
  279. completionHandler: ((NSURLRequest?) -> Void))
  280. {
  281. var redirectRequest: NSURLRequest? = request
  282. if let taskWillPerformHTTPRedirection = taskWillPerformHTTPRedirection {
  283. redirectRequest = taskWillPerformHTTPRedirection(session, task, response, request)
  284. }
  285. completionHandler(redirectRequest)
  286. }
  287. /**
  288. Requests credentials from the delegate in response to an authentication request from the remote server.
  289. - parameter session: The session containing the task whose request requires authentication.
  290. - parameter task: The task whose request requires authentication.
  291. - parameter challenge: An object that contains the request for authentication.
  292. - parameter completionHandler: A handler that your delegate method must call providing the disposition and credential.
  293. */
  294. public func URLSession(
  295. session: NSURLSession,
  296. task: NSURLSessionTask,
  297. didReceiveChallenge challenge: NSURLAuthenticationChallenge,
  298. completionHandler: ((NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void))
  299. {
  300. if let taskDidReceiveChallenge = taskDidReceiveChallenge {
  301. completionHandler(taskDidReceiveChallenge(session, task, challenge))
  302. } else if let delegate = self[task] {
  303. delegate.URLSession(
  304. session,
  305. task: task,
  306. didReceiveChallenge: challenge,
  307. completionHandler: completionHandler
  308. )
  309. } else {
  310. URLSession(session, didReceiveChallenge: challenge, completionHandler: completionHandler)
  311. }
  312. }
  313. /**
  314. Tells the delegate when a task requires a new request body stream to send to the remote server.
  315. - parameter session: The session containing the task that needs a new body stream.
  316. - parameter task: The task that needs a new body stream.
  317. - parameter completionHandler: A completion handler that your delegate method should call with the new body stream.
  318. */
  319. public func URLSession(
  320. session: NSURLSession,
  321. task: NSURLSessionTask,
  322. needNewBodyStream completionHandler: ((NSInputStream?) -> Void))
  323. {
  324. if let taskNeedNewBodyStream = taskNeedNewBodyStream {
  325. completionHandler(taskNeedNewBodyStream(session, task))
  326. } else if let delegate = self[task] {
  327. delegate.URLSession(session, task: task, needNewBodyStream: completionHandler)
  328. }
  329. }
  330. /**
  331. Periodically informs the delegate of the progress of sending body content to the server.
  332. - parameter session: The session containing the data task.
  333. - parameter task: The data task.
  334. - parameter bytesSent: The number of bytes sent since the last time this delegate method was called.
  335. - parameter totalBytesSent: The total number of bytes sent so far.
  336. - parameter totalBytesExpectedToSend: The expected length of the body data.
  337. */
  338. public func URLSession(
  339. session: NSURLSession,
  340. task: NSURLSessionTask,
  341. didSendBodyData bytesSent: Int64,
  342. totalBytesSent: Int64,
  343. totalBytesExpectedToSend: Int64)
  344. {
  345. if let taskDidSendBodyData = taskDidSendBodyData {
  346. taskDidSendBodyData(session, task, bytesSent, totalBytesSent, totalBytesExpectedToSend)
  347. } else if let delegate = self[task] as? Request.UploadTaskDelegate {
  348. delegate.URLSession(
  349. session,
  350. task: task,
  351. didSendBodyData: bytesSent,
  352. totalBytesSent: totalBytesSent,
  353. totalBytesExpectedToSend: totalBytesExpectedToSend
  354. )
  355. }
  356. }
  357. /**
  358. Tells the delegate that the task finished transferring data.
  359. - parameter session: The session containing the task whose request finished transferring data.
  360. - parameter task: The task whose request finished transferring data.
  361. - parameter error: If an error occurred, an error object indicating how the transfer failed, otherwise nil.
  362. */
  363. public func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
  364. if let taskDidComplete = taskDidComplete {
  365. taskDidComplete(session, task, error)
  366. } else if let delegate = self[task] {
  367. delegate.URLSession(session, task: task, didCompleteWithError: error)
  368. }
  369. NSNotificationCenter.defaultCenter().postNotificationName(Notifications.Task.DidComplete, object: task)
  370. self[task] = nil
  371. }
  372. // MARK: - NSURLSessionDataDelegate
  373. // MARK: Override Closures
  374. /// Overrides default behavior for NSURLSessionDataDelegate method `URLSession:dataTask:didReceiveResponse:completionHandler:`.
  375. public var dataTaskDidReceiveResponse: ((NSURLSession, NSURLSessionDataTask, NSURLResponse) -> NSURLSessionResponseDisposition)?
  376. /// Overrides default behavior for NSURLSessionDataDelegate method `URLSession:dataTask:didBecomeDownloadTask:`.
  377. public var dataTaskDidBecomeDownloadTask: ((NSURLSession, NSURLSessionDataTask, NSURLSessionDownloadTask) -> Void)?
  378. /// Overrides default behavior for NSURLSessionDataDelegate method `URLSession:dataTask:didReceiveData:`.
  379. public var dataTaskDidReceiveData: ((NSURLSession, NSURLSessionDataTask, NSData) -> Void)?
  380. /// Overrides default behavior for NSURLSessionDataDelegate method `URLSession:dataTask:willCacheResponse:completionHandler:`.
  381. public var dataTaskWillCacheResponse: ((NSURLSession, NSURLSessionDataTask, NSCachedURLResponse) -> NSCachedURLResponse!)?
  382. // MARK: Delegate Methods
  383. /**
  384. Tells the delegate that the data task received the initial reply (headers) from the server.
  385. - parameter session: The session containing the data task that received an initial reply.
  386. - parameter dataTask: The data task that received an initial reply.
  387. - parameter response: A URL response object populated with headers.
  388. - parameter completionHandler: A completion handler that your code calls to continue the transfer, passing a
  389. constant to indicate whether the transfer should continue as a data task or
  390. should become a download task.
  391. */
  392. public func URLSession(
  393. session: NSURLSession,
  394. dataTask: NSURLSessionDataTask,
  395. didReceiveResponse response: NSURLResponse,
  396. completionHandler: ((NSURLSessionResponseDisposition) -> Void))
  397. {
  398. var disposition: NSURLSessionResponseDisposition = .Allow
  399. if let dataTaskDidReceiveResponse = dataTaskDidReceiveResponse {
  400. disposition = dataTaskDidReceiveResponse(session, dataTask, response)
  401. }
  402. completionHandler(disposition)
  403. }
  404. /**
  405. Tells the delegate that the data task was changed to a download task.
  406. - parameter session: The session containing the task that was replaced by a download task.
  407. - parameter dataTask: The data task that was replaced by a download task.
  408. - parameter downloadTask: The new download task that replaced the data task.
  409. */
  410. public func URLSession(
  411. session: NSURLSession,
  412. dataTask: NSURLSessionDataTask,
  413. didBecomeDownloadTask downloadTask: NSURLSessionDownloadTask)
  414. {
  415. if let dataTaskDidBecomeDownloadTask = dataTaskDidBecomeDownloadTask {
  416. dataTaskDidBecomeDownloadTask(session, dataTask, downloadTask)
  417. } else {
  418. let downloadDelegate = Request.DownloadTaskDelegate(task: downloadTask)
  419. self[downloadTask] = downloadDelegate
  420. }
  421. }
  422. /**
  423. Tells the delegate that the data task has received some of the expected data.
  424. - parameter session: The session containing the data task that provided data.
  425. - parameter dataTask: The data task that provided data.
  426. - parameter data: A data object containing the transferred data.
  427. */
  428. public func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
  429. if let dataTaskDidReceiveData = dataTaskDidReceiveData {
  430. dataTaskDidReceiveData(session, dataTask, data)
  431. } else if let delegate = self[dataTask] as? Request.DataTaskDelegate {
  432. delegate.URLSession(session, dataTask: dataTask, didReceiveData: data)
  433. }
  434. }
  435. /**
  436. Asks the delegate whether the data (or upload) task should store the response in the cache.
  437. - parameter session: The session containing the data (or upload) task.
  438. - parameter dataTask: The data (or upload) task.
  439. - parameter proposedResponse: The default caching behavior. This behavior is determined based on the current
  440. caching policy and the values of certain received headers, such as the Pragma
  441. and Cache-Control headers.
  442. - parameter completionHandler: A block that your handler must call, providing either the original proposed
  443. response, a modified version of that response, or NULL to prevent caching the
  444. response. If your delegate implements this method, it must call this completion
  445. handler; otherwise, your app leaks memory.
  446. */
  447. public func URLSession(
  448. session: NSURLSession,
  449. dataTask: NSURLSessionDataTask,
  450. willCacheResponse proposedResponse: NSCachedURLResponse,
  451. completionHandler: ((NSCachedURLResponse?) -> Void))
  452. {
  453. if let dataTaskWillCacheResponse = dataTaskWillCacheResponse {
  454. completionHandler(dataTaskWillCacheResponse(session, dataTask, proposedResponse))
  455. } else if let delegate = self[dataTask] as? Request.DataTaskDelegate {
  456. delegate.URLSession(
  457. session,
  458. dataTask: dataTask,
  459. willCacheResponse: proposedResponse,
  460. completionHandler: completionHandler
  461. )
  462. } else {
  463. completionHandler(proposedResponse)
  464. }
  465. }
  466. // MARK: - NSURLSessionDownloadDelegate
  467. // MARK: Override Closures
  468. /// Overrides default behavior for NSURLSessionDownloadDelegate method `URLSession:downloadTask:didFinishDownloadingToURL:`.
  469. public var downloadTaskDidFinishDownloadingToURL: ((NSURLSession, NSURLSessionDownloadTask, NSURL) -> Void)?
  470. /// Overrides default behavior for NSURLSessionDownloadDelegate method `URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:`.
  471. public var downloadTaskDidWriteData: ((NSURLSession, NSURLSessionDownloadTask, Int64, Int64, Int64) -> Void)?
  472. /// Overrides default behavior for NSURLSessionDownloadDelegate method `URLSession:downloadTask:didResumeAtOffset:expectedTotalBytes:`.
  473. public var downloadTaskDidResumeAtOffset: ((NSURLSession, NSURLSessionDownloadTask, Int64, Int64) -> Void)?
  474. // MARK: Delegate Methods
  475. /**
  476. Tells the delegate that a download task has finished downloading.
  477. - parameter session: The session containing the download task that finished.
  478. - parameter downloadTask: The download task that finished.
  479. - parameter location: A file URL for the temporary file. Because the file is temporary, you must either
  480. open the file for reading or move it to a permanent location in your app’s sandbox
  481. container directory before returning from this delegate method.
  482. */
  483. public func URLSession(
  484. session: NSURLSession,
  485. downloadTask: NSURLSessionDownloadTask,
  486. didFinishDownloadingToURL location: NSURL)
  487. {
  488. if let downloadTaskDidFinishDownloadingToURL = downloadTaskDidFinishDownloadingToURL {
  489. downloadTaskDidFinishDownloadingToURL(session, downloadTask, location)
  490. } else if let delegate = self[downloadTask] as? Request.DownloadTaskDelegate {
  491. delegate.URLSession(session, downloadTask: downloadTask, didFinishDownloadingToURL: location)
  492. }
  493. }
  494. /**
  495. Periodically informs the delegate about the download’s progress.
  496. - parameter session: The session containing the download task.
  497. - parameter downloadTask: The download task.
  498. - parameter bytesWritten: The number of bytes transferred since the last time this delegate
  499. method was called.
  500. - parameter totalBytesWritten: The total number of bytes transferred so far.
  501. - parameter totalBytesExpectedToWrite: The expected length of the file, as provided by the Content-Length
  502. header. If this header was not provided, the value is
  503. `NSURLSessionTransferSizeUnknown`.
  504. */
  505. public func URLSession(
  506. session: NSURLSession,
  507. downloadTask: NSURLSessionDownloadTask,
  508. didWriteData bytesWritten: Int64,
  509. totalBytesWritten: Int64,
  510. totalBytesExpectedToWrite: Int64)
  511. {
  512. if let downloadTaskDidWriteData = downloadTaskDidWriteData {
  513. downloadTaskDidWriteData(session, downloadTask, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite)
  514. } else if let delegate = self[downloadTask] as? Request.DownloadTaskDelegate {
  515. delegate.URLSession(
  516. session,
  517. downloadTask: downloadTask,
  518. didWriteData: bytesWritten,
  519. totalBytesWritten: totalBytesWritten,
  520. totalBytesExpectedToWrite: totalBytesExpectedToWrite
  521. )
  522. }
  523. }
  524. /**
  525. Tells the delegate that the download task has resumed downloading.
  526. - parameter session: The session containing the download task that finished.
  527. - parameter downloadTask: The download task that resumed. See explanation in the discussion.
  528. - parameter fileOffset: If the file's cache policy or last modified date prevents reuse of the
  529. existing content, then this value is zero. Otherwise, this value is an
  530. integer representing the number of bytes on disk that do not need to be
  531. retrieved again.
  532. - parameter expectedTotalBytes: The expected length of the file, as provided by the Content-Length header.
  533. If this header was not provided, the value is NSURLSessionTransferSizeUnknown.
  534. */
  535. public func URLSession(
  536. session: NSURLSession,
  537. downloadTask: NSURLSessionDownloadTask,
  538. didResumeAtOffset fileOffset: Int64,
  539. expectedTotalBytes: Int64)
  540. {
  541. if let downloadTaskDidResumeAtOffset = downloadTaskDidResumeAtOffset {
  542. downloadTaskDidResumeAtOffset(session, downloadTask, fileOffset, expectedTotalBytes)
  543. } else if let delegate = self[downloadTask] as? Request.DownloadTaskDelegate {
  544. delegate.URLSession(
  545. session,
  546. downloadTask: downloadTask,
  547. didResumeAtOffset: fileOffset,
  548. expectedTotalBytes: expectedTotalBytes
  549. )
  550. }
  551. }
  552. // MARK: - NSURLSessionStreamDelegate
  553. var _streamTaskReadClosed: Any?
  554. var _streamTaskWriteClosed: Any?
  555. var _streamTaskBetterRouteDiscovered: Any?
  556. var _streamTaskDidBecomeInputStream: Any?
  557. // MARK: - NSObject
  558. public override func respondsToSelector(selector: Selector) -> Bool {
  559. switch selector {
  560. case "URLSession:didBecomeInvalidWithError:":
  561. return sessionDidBecomeInvalidWithError != nil
  562. case "URLSession:didReceiveChallenge:completionHandler:":
  563. return sessionDidReceiveChallenge != nil
  564. case "URLSessionDidFinishEventsForBackgroundURLSession:":
  565. return sessionDidFinishEventsForBackgroundURLSession != nil
  566. case "URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:":
  567. return taskWillPerformHTTPRedirection != nil
  568. case "URLSession:dataTask:didReceiveResponse:completionHandler:":
  569. return dataTaskDidReceiveResponse != nil
  570. default:
  571. return self.dynamicType.instancesRespondToSelector(selector)
  572. }
  573. }
  574. }
  575. }