Manager.swift 37 KB

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