diff --git a/README.md b/README.md index ebc35db37dd4780dc539e31488c6c4f3d47f44e9..daba8b1b8be4cd5d9fe05f1f715198e9cb36b776 100644 --- a/README.md +++ b/README.md @@ -1023,6 +1023,74 @@ enum Router: URLRequestConvertible { Alamofire.request(Router.ReadUser("mattt")) // GET /users/mattt ``` +### SessionDelegate + +By default, an Alamofire `Manager` instance creates an internal `SessionDelegate` object to handle all the various types of delegate callbacks that are generated by the underlying `NSURLSession`. The implementations of each delegate method handle the most common use cases for these types of calls abstracting the complexity away from the top-level APIs. However, advanced users may find the need to override the default functionality for various reasons. + +#### Override Closures + +The first way to customize the `SessionDelegate` behavior is through the use of the override closures. Each closure gives you the ability to override the implementation of the matching `SessionDelegate` API, yet still use the default implementation for all other APIs. This makes it easy to customize subsets of the delegate functionality. Here are a few examples of some of the override closures available: + +```swift +/// Overrides default behavior for NSURLSessionDelegate method `URLSession:didReceiveChallenge:completionHandler:`. +public var sessionDidReceiveChallenge: ((NSURLSession, NSURLAuthenticationChallenge) -> (NSURLSessionAuthChallengeDisposition, NSURLCredential?))? + +/// Overrides default behavior for NSURLSessionDelegate method `URLSessionDidFinishEventsForBackgroundURLSession:`. +public var sessionDidFinishEventsForBackgroundURLSession: ((NSURLSession) -> Void)? + +/// Overrides default behavior for NSURLSessionTaskDelegate method `URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:`. +public var taskWillPerformHTTPRedirection: ((NSURLSession, NSURLSessionTask, NSHTTPURLResponse, NSURLRequest) -> NSURLRequest?)? + +/// Overrides default behavior for NSURLSessionDataDelegate method `URLSession:dataTask:willCacheResponse:completionHandler:`. +public var dataTaskWillCacheResponse: ((NSURLSession, NSURLSessionDataTask, NSCachedURLResponse) -> NSCachedURLResponse?)? +``` + +The following is a short example of how to use the `taskWillPerformHTTPRedirection` to avoid following redirects to any `apple.com` domains. + +```swift +let delegate: Alamofire.Manager.SessionDelegate = manager.delegate + +delegate.taskWillPerformHTTPRedirection = { session, task, response, request in + var finalRequest = request + + if let originalRequest = task.originalRequest where originalRequest.URLString.containsString("apple.com") { + finalRequest = originalRequest + } + + return finalRequest +} +``` + +#### Subclassing + +Another way to override the default implementation of the `SessionDelegate` is to subclass it. Subclassing allows you completely customize the behavior of the API or to create a proxy for the API and still use the default implementation. Creating a proxy allows you to log events, emit notifications, provide pre and post hook implementations, etc. Here's a quick example of subclassing the `SessionDelegate` and logging a message when a redirect occurs. + +```swift +class LoggingSessionDelegate: Manager.SessionDelegate { + override func URLSession( + session: NSURLSession, + task: NSURLSessionTask, + willPerformHTTPRedirection response: NSHTTPURLResponse, + newRequest request: NSURLRequest, + completionHandler: NSURLRequest? -> Void) + { + print("URLSession will perform HTTP redirection to request: \(request)") + + super.URLSession( + session, + task: task, + willPerformHTTPRedirection: response, + newRequest: request, + completionHandler: completionHandler + ) + } +} +``` + +Generally, either the default implementation or the override closures should provide the necessary functionality required. Subclassing should only be used as a last resort. + +> It is important to keep in mind that the `subdelegates` are initialized and destroyed in the default implementation. Be careful when subclassing to not introduce memory leaks. + ### Security Using a secure HTTPS connection when communicating with servers and web services is an important step in securing sensitive data. By default, Alamofire will evaluate the certificate chain provided by the server using Apple's built in validation provided by the Security framework. While this guarantees the certificate chain is valid, it does not prevent man-in-the-middle (MITM) attacks or other potential vulnerabilities. In order to mitigate MITM attacks, applications dealing with sensitive customer data or financial information should use certificate or public key pinning provided by the `ServerTrustPolicy`. diff --git a/Source/Manager.swift b/Source/Manager.swift index 319f84667099d88c825f720c582e897f17d89769..283fc11ab3d129ea88d1f9fee683414b5c0e496f 100644 --- a/Source/Manager.swift +++ b/Source/Manager.swift @@ -218,7 +218,7 @@ public class Manager { /** Responsible for handling all delegate callbacks for the underlying session. */ - public final class SessionDelegate: NSObject, NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate { + public class SessionDelegate: NSObject, NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate { private var subdelegates: [Int: Request.TaskDelegate] = [:] private let subdelegateQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_CONCURRENT) @@ -229,7 +229,6 @@ public class Manager { return subdelegate } - set { dispatch_barrier_async(subdelegateQueue) { self.subdelegates[task.taskIdentifier] = newValue } }