Răsfoiți Sursa

Moved the Request class into a separate Swift file.

Christian Noon 10 ani în urmă
părinte
comite
fbe66b3be1
3 a modificat fișierele cu 434 adăugiri și 405 ștergeri
  1. 6 0
      Alamofire.xcodeproj/project.pbxproj
  2. 0 405
      Source/Alamofire.swift
  3. 428 0
      Source/Request.swift

+ 6 - 0
Alamofire.xcodeproj/project.pbxproj

@@ -9,6 +9,8 @@
 /* Begin PBXBuildFile section */
 		4CDE2C371AF8932A00BABAE5 /* Manager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CDE2C361AF8932A00BABAE5 /* Manager.swift */; };
 		4CDE2C381AF8932A00BABAE5 /* Manager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CDE2C361AF8932A00BABAE5 /* Manager.swift */; };
+		4CDE2C3A1AF899EC00BABAE5 /* Request.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CDE2C391AF899EC00BABAE5 /* Request.swift */; };
+		4CDE2C3B1AF899EC00BABAE5 /* Request.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CDE2C391AF899EC00BABAE5 /* Request.swift */; };
 		4CE2724F1AF88FB500F1D59A /* ParameterEncoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE2724E1AF88FB500F1D59A /* ParameterEncoding.swift */; };
 		4CE272501AF88FB500F1D59A /* ParameterEncoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE2724E1AF88FB500F1D59A /* ParameterEncoding.swift */; };
 		4DD67C241A5C58FB00ED2280 /* Alamofire.h in Headers */ = {isa = PBXBuildFile; fileRef = F8111E3819A95C8B0040E7D1 /* Alamofire.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -55,6 +57,7 @@
 
 /* Begin PBXFileReference section */
 		4CDE2C361AF8932A00BABAE5 /* Manager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Manager.swift; sourceTree = "<group>"; };
+		4CDE2C391AF899EC00BABAE5 /* Request.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Request.swift; sourceTree = "<group>"; };
 		4CE2724E1AF88FB500F1D59A /* ParameterEncoding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParameterEncoding.swift; sourceTree = "<group>"; };
 		4DD67C0B1A5C55C900ED2280 /* Alamofire.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Alamofire.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		F8111E3319A95C8B0040E7D1 /* Alamofire.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Alamofire.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -134,6 +137,7 @@
 				F897FF4019AA800700AB5182 /* Alamofire.swift */,
 				4CDE2C361AF8932A00BABAE5 /* Manager.swift */,
 				4CE2724E1AF88FB500F1D59A /* ParameterEncoding.swift */,
+				4CDE2C391AF899EC00BABAE5 /* Request.swift */,
 				F8111E3619A95C8B0040E7D1 /* Supporting Files */,
 			);
 			path = Source;
@@ -347,6 +351,7 @@
 			buildActionMask = 2147483647;
 			files = (
 				4CE272501AF88FB500F1D59A /* ParameterEncoding.swift in Sources */,
+				4CDE2C3B1AF899EC00BABAE5 /* Request.swift in Sources */,
 				4CDE2C381AF8932A00BABAE5 /* Manager.swift in Sources */,
 				4DD67C251A5C590000ED2280 /* Alamofire.swift in Sources */,
 			);
@@ -357,6 +362,7 @@
 			buildActionMask = 2147483647;
 			files = (
 				4CE2724F1AF88FB500F1D59A /* ParameterEncoding.swift in Sources */,
+				4CDE2C3A1AF899EC00BABAE5 /* Request.swift in Sources */,
 				4CDE2C371AF8932A00BABAE5 /* Manager.swift in Sources */,
 				F897FF4119AA800700AB5182 /* Alamofire.swift in Sources */,
 			);

+ 0 - 405
Source/Alamofire.swift

@@ -83,317 +83,6 @@ extension NSURLRequest: URLRequestConvertible {
     }
 }
 
-// MARK: -
-
-/**
-    Responsible for sending a request and receiving the response and associated data from the server, as well as managing its underlying `NSURLSessionTask`.
-*/
-public class Request {
-    let delegate: TaskDelegate
-
-    /// The underlying task.
-    public var task: NSURLSessionTask { return delegate.task }
-
-    /// The session belonging to the underlying task.
-    public let session: NSURLSession
-
-    /// The request sent or to be sent to the server.
-    public var request: NSURLRequest { return task.originalRequest }
-
-    /// The response received from the server, if any.
-    public var response: NSHTTPURLResponse? { return task.response as? NSHTTPURLResponse }
-
-    /// The progress of the request lifecycle.
-    public var progress: NSProgress { return delegate.progress }
-
-    init(session: NSURLSession, task: NSURLSessionTask) {
-        self.session = session
-
-        switch task {
-        case is NSURLSessionUploadTask:
-            self.delegate = UploadTaskDelegate(task: task)
-        case is NSURLSessionDataTask:
-            self.delegate = DataTaskDelegate(task: task)
-        case is NSURLSessionDownloadTask:
-            self.delegate = DownloadTaskDelegate(task: task)
-        default:
-            self.delegate = TaskDelegate(task: task)
-        }
-    }
-
-    // MARK: Authentication
-
-    /**
-        Associates an HTTP Basic credential with the request.
-
-        :param: user The user.
-        :param: password The password.
-
-        :returns: The request.
-    */
-    public func authenticate(#user: String, password: String) -> Self {
-        let credential = NSURLCredential(user: user, password: password, persistence: .ForSession)
-
-        return authenticate(usingCredential: credential)
-    }
-
-    /**
-        Associates a specified credential with the request.
-
-        :param: credential The credential.
-
-        :returns: The request.
-    */
-    public func authenticate(usingCredential credential: NSURLCredential) -> Self {
-        delegate.credential = credential
-
-        return self
-    }
-
-    // MARK: Progress
-
-    /**
-        Sets a closure to be called periodically during the lifecycle of the request as data is written to or read from the server.
-
-        - For uploads, the progress closure returns the bytes written, total bytes written, and total bytes expected to write.
-        - For downloads, the progress closure returns the bytes read, total bytes read, and total bytes expected to write.
-
-        :param: closure The code to be executed periodically during the lifecycle of the request.
-
-        :returns: The request.
-    */
-    public func progress(closure: ((Int64, Int64, Int64) -> Void)? = nil) -> Self {
-        if let uploadDelegate = delegate as? UploadTaskDelegate {
-            uploadDelegate.uploadProgress = closure
-        } else if let dataDelegate = delegate as? DataTaskDelegate {
-            dataDelegate.dataProgress = closure
-        } else if let downloadDelegate = delegate as? DownloadTaskDelegate {
-            downloadDelegate.downloadProgress = closure
-        }
-
-        return self
-    }
-
-    // MARK: Response
-
-    /**
-        A closure used by response handlers that takes a request, response, and data and returns a serialized object and any error that occured in the process.
-    */
-    public typealias Serializer = (NSURLRequest, NSHTTPURLResponse?, NSData?) -> (AnyObject?, NSError?)
-
-    /**
-        Creates a response serializer that returns the associated data as-is.
-
-        :returns: A data response serializer.
-    */
-    public class func responseDataSerializer() -> Serializer {
-        return { (request, response, data) in
-            return (data, nil)
-        }
-    }
-
-    /**
-        Adds a handler to be called once the request has finished.
-
-        :param: completionHandler The code to be executed once the request has finished.
-
-        :returns: The request.
-    */
-    public func response(completionHandler: (NSURLRequest, NSHTTPURLResponse?, AnyObject?, NSError?) -> Void) -> Self {
-        return response(serializer: Request.responseDataSerializer(), completionHandler: completionHandler)
-    }
-
-    /**
-        Adds a handler to be called once the request has finished.
-
-        :param: queue The queue on which the completion handler is dispatched.
-        :param: serializer The closure responsible for serializing the request, response, and data.
-        :param: completionHandler The code to be executed once the request has finished.
-
-        :returns: The request.
-    */
-    public func response(queue: dispatch_queue_t? = nil, serializer: Serializer, completionHandler: (NSURLRequest, NSHTTPURLResponse?, AnyObject?, NSError?) -> Void) -> Self {
-        delegate.queue.addOperationWithBlock {
-            let (responseObject: AnyObject?, serializationError: NSError?) = serializer(self.request, self.response, self.delegate.data)
-
-            dispatch_async(queue ?? dispatch_get_main_queue()) {
-                completionHandler(self.request, self.response, responseObject, self.delegate.error ?? serializationError)
-            }
-        }
-
-        return self
-    }
-
-    /**
-        Suspends the request.
-    */
-    public func suspend() {
-        task.suspend()
-    }
-
-    /**
-        Resumes the request.
-    */
-    public func resume() {
-        task.resume()
-    }
-
-    /**
-        Cancels the request.
-    */
-    public func cancel() {
-        if let downloadDelegate = delegate as? DownloadTaskDelegate {
-            downloadDelegate.downloadTask.cancelByProducingResumeData { (data) in
-                downloadDelegate.resumeData = data
-            }
-        } else {
-            task.cancel()
-        }
-    }
-
-    class TaskDelegate: NSObject, NSURLSessionTaskDelegate {
-        let task: NSURLSessionTask
-        let queue: NSOperationQueue
-        let progress: NSProgress
-
-        var data: NSData? { return nil }
-        private(set) var error: NSError?
-
-        var credential: NSURLCredential?
-
-        var taskWillPerformHTTPRedirection: ((NSURLSession!, NSURLSessionTask!, NSHTTPURLResponse!, NSURLRequest!) -> (NSURLRequest!))?
-        var taskDidReceiveChallenge: ((NSURLSession!, NSURLSessionTask!, NSURLAuthenticationChallenge) -> (NSURLSessionAuthChallengeDisposition, NSURLCredential?))?
-        var taskDidSendBodyData: ((NSURLSession!, NSURLSessionTask!, Int64, Int64, Int64) -> Void)?
-        var taskNeedNewBodyStream: ((NSURLSession!, NSURLSessionTask!) -> (NSInputStream!))?
-
-        init(task: NSURLSessionTask) {
-            self.task = task
-            self.progress = NSProgress(totalUnitCount: 0)
-            self.queue = {
-                let operationQueue = NSOperationQueue()
-                operationQueue.maxConcurrentOperationCount = 1
-                operationQueue.qualityOfService = NSQualityOfService.Utility
-                operationQueue.suspended = true
-
-                return operationQueue
-            }()
-        }
-
-        deinit {
-            queue.cancelAllOperations()
-            queue.suspended = true
-        }
-
-        // MARK: NSURLSessionTaskDelegate
-
-        func URLSession(session: NSURLSession, task: NSURLSessionTask, willPerformHTTPRedirection response: NSHTTPURLResponse, newRequest request: NSURLRequest, completionHandler: ((NSURLRequest!) -> Void)) {
-            var redirectRequest = request
-            if taskWillPerformHTTPRedirection != nil {
-                redirectRequest = taskWillPerformHTTPRedirection!(session, task, response, request)
-            }
-
-            completionHandler(redirectRequest)
-        }
-
-        func URLSession(session: NSURLSession, task: NSURLSessionTask, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: ((NSURLSessionAuthChallengeDisposition, NSURLCredential!) -> Void)) {
-            var disposition: NSURLSessionAuthChallengeDisposition = .PerformDefaultHandling
-            var credential: NSURLCredential?
-
-            if taskDidReceiveChallenge != nil {
-                (disposition, credential) = taskDidReceiveChallenge!(session, task, challenge)
-            } else {
-                if challenge.previousFailureCount > 0 {
-                    disposition = .CancelAuthenticationChallenge
-                } else {
-                    credential = self.credential ?? session.configuration.URLCredentialStorage?.defaultCredentialForProtectionSpace(challenge.protectionSpace)
-                    if credential != nil {
-                        disposition = .UseCredential
-                    }
-                }
-            }
-
-            completionHandler(disposition, credential)
-        }
-
-        func URLSession(session: NSURLSession, task: NSURLSessionTask, needNewBodyStream completionHandler: ((NSInputStream!) -> Void)) {
-            var bodyStream: NSInputStream?
-            if taskNeedNewBodyStream != nil {
-                bodyStream = taskNeedNewBodyStream!(session, task)
-            }
-
-            completionHandler(bodyStream)
-        }
-
-        func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
-            if error != nil {
-                self.error = error
-            }
-
-            queue.suspended = false
-        }
-    }
-
-    class DataTaskDelegate: TaskDelegate, NSURLSessionDataDelegate {
-        var dataTask: NSURLSessionDataTask! { return task as! NSURLSessionDataTask }
-
-        private var mutableData: NSMutableData
-        override var data: NSData? {
-            return mutableData
-        }
-
-        private var expectedContentLength: Int64?
-
-        var dataTaskDidReceiveResponse: ((NSURLSession!, NSURLSessionDataTask!, NSURLResponse!) -> (NSURLSessionResponseDisposition))?
-        var dataTaskDidBecomeDownloadTask: ((NSURLSession!, NSURLSessionDataTask!) -> Void)?
-        var dataTaskDidReceiveData: ((NSURLSession!, NSURLSessionDataTask!, NSData!) -> Void)?
-        var dataTaskWillCacheResponse: ((NSURLSession!, NSURLSessionDataTask!, NSCachedURLResponse!) -> (NSCachedURLResponse))?
-        var dataProgress: ((bytesReceived: Int64, totalBytesReceived: Int64, totalBytesExpectedToReceive: Int64) -> Void)?
-
-        override init(task: NSURLSessionTask) {
-            self.mutableData = NSMutableData()
-            super.init(task: task)
-        }
-
-        // MARK: NSURLSessionDataDelegate
-
-        func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveResponse response: NSURLResponse, completionHandler: ((NSURLSessionResponseDisposition) -> Void)) {
-            var disposition: NSURLSessionResponseDisposition = .Allow
-
-            expectedContentLength = response.expectedContentLength
-
-            if dataTaskDidReceiveResponse != nil {
-                disposition = dataTaskDidReceiveResponse!(session, dataTask, response)
-            }
-
-            completionHandler(disposition)
-        }
-
-        func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didBecomeDownloadTask downloadTask: NSURLSessionDownloadTask) {
-            dataTaskDidBecomeDownloadTask?(session, dataTask)
-        }
-
-        func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
-            dataTaskDidReceiveData?(session, dataTask, data)
-
-            mutableData.appendData(data)
-
-            if let expectedContentLength = dataTask.response?.expectedContentLength {
-                dataProgress?(bytesReceived: Int64(data.length), totalBytesReceived: Int64(mutableData.length), totalBytesExpectedToReceive: expectedContentLength)
-            }
-        }
-
-        func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, willCacheResponse proposedResponse: NSCachedURLResponse, completionHandler: ((NSCachedURLResponse!) -> Void)) {
-            var cachedResponse = proposedResponse
-
-            if dataTaskWillCacheResponse != nil {
-                cachedResponse = dataTaskWillCacheResponse!(session, dataTask, proposedResponse)
-            }
-
-            completionHandler(cachedResponse)
-        }
-    }
-}
-
 // MARK: - Validation
 
 extension Request {
@@ -825,100 +514,6 @@ extension Request {
     }
 }
 
-// MARK: - Printable
-
-extension Request: Printable {
-    /// The textual representation used when written to an output stream, which includes the HTTP method and URL, as well as the response status code if a response has been received.
-    public var description: String {
-        var components: [String] = []
-        if request.HTTPMethod != nil {
-            components.append(request.HTTPMethod!)
-        }
-
-        components.append(request.URL!.absoluteString!)
-
-        if response != nil {
-            components.append("(\(response!.statusCode))")
-        }
-
-        return join(" ", components)
-    }
-}
-
-extension Request: DebugPrintable {
-    func cURLRepresentation() -> String {
-        var components: [String] = ["$ curl -i"]
-
-        let URL = request.URL
-
-        if request.HTTPMethod != nil && request.HTTPMethod != "GET" {
-            components.append("-X \(request.HTTPMethod!)")
-        }
-
-        if let credentialStorage = self.session.configuration.URLCredentialStorage {
-            let protectionSpace = NSURLProtectionSpace(host: URL!.host!, port: URL!.port?.integerValue ?? 0, `protocol`: URL!.scheme!, realm: URL!.host!, authenticationMethod: NSURLAuthenticationMethodHTTPBasic)
-            if let credentials = credentialStorage.credentialsForProtectionSpace(protectionSpace)?.values.array {
-                for credential: NSURLCredential in (credentials as! [NSURLCredential]) {
-                    components.append("-u \(credential.user!):\(credential.password!)")
-                }
-            } else {
-                if let credential = delegate.credential {
-                    components.append("-u \(credential.user!):\(credential.password!)")
-                }
-            }
-        }
-
-        // Temporarily disabled on OS X due to build failure for CocoaPods
-        // See https://github.com/CocoaPods/swift/issues/24
-        #if !os(OSX)
-        if let cookieStorage = session.configuration.HTTPCookieStorage,
-               cookies = cookieStorage.cookiesForURL(URL!) as? [NSHTTPCookie]
-            where !cookies.isEmpty
-        {
-            let string = cookies.reduce(""){ $0 + "\($1.name)=\($1.value ?? String());" }
-            components.append("-b \"\(string.substringToIndex(string.endIndex.predecessor()))\"")
-        }
-        #endif
-
-        if request.allHTTPHeaderFields != nil {
-            for (field, value) in request.allHTTPHeaderFields! {
-                switch field {
-                case "Cookie":
-                    continue
-                default:
-                    components.append("-H \"\(field): \(value)\"")
-                }
-            }
-        }
-
-        if session.configuration.HTTPAdditionalHeaders != nil {
-            for (field, value) in session.configuration.HTTPAdditionalHeaders! {
-                switch field {
-                case "Cookie":
-                    continue
-                default:
-                    components.append("-H \"\(field): \(value)\"")
-                }
-            }
-        }
-
-        if let HTTPBody = request.HTTPBody,
-               escapedBody = NSString(data: HTTPBody, encoding: NSUTF8StringEncoding)?.stringByReplacingOccurrencesOfString("\"", withString: "\\\"")
-        {
-            components.append("-d \"\(escapedBody)\"")
-        }
-
-        components.append("\"\(URL!.absoluteString!)\"")
-
-        return join(" \\\n\t", components)
-    }
-
-    /// The textual representation used when written to an output stream, in the form of a cURL command.
-    public var debugDescription: String {
-        return cURLRepresentation()
-    }
-}
-
 // MARK: - Response Serializers
 
 // MARK: String

+ 428 - 0
Source/Request.swift

@@ -0,0 +1,428 @@
+// Alamofire.swift
+//
+// Copyright (c) 2014–2015 Alamofire Software Foundation (http://alamofire.org/)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+/**
+    Responsible for sending a request and receiving the response and associated data from the server, as well as managing its underlying `NSURLSessionTask`.
+*/
+public class Request {
+    let delegate: TaskDelegate
+    
+    /// The underlying task.
+    public var task: NSURLSessionTask { return delegate.task }
+    
+    /// The session belonging to the underlying task.
+    public let session: NSURLSession
+    
+    /// The request sent or to be sent to the server.
+    public var request: NSURLRequest { return task.originalRequest }
+    
+    /// The response received from the server, if any.
+    public var response: NSHTTPURLResponse? { return task.response as? NSHTTPURLResponse }
+    
+    /// The progress of the request lifecycle.
+    public var progress: NSProgress { return delegate.progress }
+    
+    init(session: NSURLSession, task: NSURLSessionTask) {
+        self.session = session
+        
+        switch task {
+        case is NSURLSessionUploadTask:
+            self.delegate = UploadTaskDelegate(task: task)
+        case is NSURLSessionDataTask:
+            self.delegate = DataTaskDelegate(task: task)
+        case is NSURLSessionDownloadTask:
+            self.delegate = DownloadTaskDelegate(task: task)
+        default:
+            self.delegate = TaskDelegate(task: task)
+        }
+    }
+    
+    // MARK: Authentication
+    
+    /**
+        Associates an HTTP Basic credential with the request.
+    
+        :param: user The user.
+        :param: password The password.
+    
+        :returns: The request.
+    */
+    public func authenticate(#user: String, password: String) -> Self {
+        let credential = NSURLCredential(user: user, password: password, persistence: .ForSession)
+        
+        return authenticate(usingCredential: credential)
+    }
+    
+    /**
+        Associates a specified credential with the request.
+        
+        :param: credential The credential.
+        
+        :returns: The request.
+    */
+    public func authenticate(usingCredential credential: NSURLCredential) -> Self {
+        delegate.credential = credential
+        
+        return self
+    }
+    
+    // MARK: Progress
+    
+    /**
+        Sets a closure to be called periodically during the lifecycle of the request as data is written to or read from the server.
+        
+        - For uploads, the progress closure returns the bytes written, total bytes written, and total bytes expected to write.
+        - For downloads, the progress closure returns the bytes read, total bytes read, and total bytes expected to write.
+        
+        :param: closure The code to be executed periodically during the lifecycle of the request.
+        
+        :returns: The request.
+    */
+    public func progress(closure: ((Int64, Int64, Int64) -> Void)? = nil) -> Self {
+        if let uploadDelegate = delegate as? UploadTaskDelegate {
+            uploadDelegate.uploadProgress = closure
+        } else if let dataDelegate = delegate as? DataTaskDelegate {
+            dataDelegate.dataProgress = closure
+        } else if let downloadDelegate = delegate as? DownloadTaskDelegate {
+            downloadDelegate.downloadProgress = closure
+        }
+        
+        return self
+    }
+    
+    // MARK: Response
+    
+    /**
+        A closure used by response handlers that takes a request, response, and data and returns a serialized object and any error that occured in the process.
+    */
+    public typealias Serializer = (NSURLRequest, NSHTTPURLResponse?, NSData?) -> (AnyObject?, NSError?)
+    
+    /**
+        Creates a response serializer that returns the associated data as-is.
+        
+        :returns: A data response serializer.
+    */
+    public class func responseDataSerializer() -> Serializer {
+        return { (request, response, data) in
+            return (data, nil)
+        }
+    }
+    
+    /**
+        Adds a handler to be called once the request has finished.
+        
+        :param: completionHandler The code to be executed once the request has finished.
+        
+        :returns: The request.
+    */
+    public func response(completionHandler: (NSURLRequest, NSHTTPURLResponse?, AnyObject?, NSError?) -> Void) -> Self {
+        return response(serializer: Request.responseDataSerializer(), completionHandler: completionHandler)
+    }
+    
+    /**
+        Adds a handler to be called once the request has finished.
+        
+        :param: queue The queue on which the completion handler is dispatched.
+        :param: serializer The closure responsible for serializing the request, response, and data.
+        :param: completionHandler The code to be executed once the request has finished.
+        
+        :returns: The request.
+    */
+    public func response(queue: dispatch_queue_t? = nil, serializer: Serializer, completionHandler: (NSURLRequest, NSHTTPURLResponse?, AnyObject?, NSError?) -> Void) -> Self {
+        delegate.queue.addOperationWithBlock {
+            let (responseObject: AnyObject?, serializationError: NSError?) = serializer(self.request, self.response, self.delegate.data)
+            
+            dispatch_async(queue ?? dispatch_get_main_queue()) {
+                completionHandler(self.request, self.response, responseObject, self.delegate.error ?? serializationError)
+            }
+        }
+        
+        return self
+    }
+    
+    /**
+        Suspends the request.
+    */
+    public func suspend() {
+        task.suspend()
+    }
+    
+    /**
+        Resumes the request.
+    */
+    public func resume() {
+        task.resume()
+    }
+    
+    /**
+        Cancels the request.
+    */
+    public func cancel() {
+        if let downloadDelegate = delegate as? DownloadTaskDelegate {
+            downloadDelegate.downloadTask.cancelByProducingResumeData { (data) in
+                downloadDelegate.resumeData = data
+            }
+        } else {
+            task.cancel()
+        }
+    }
+    
+    class TaskDelegate: NSObject, NSURLSessionTaskDelegate {
+        let task: NSURLSessionTask
+        let queue: NSOperationQueue
+        let progress: NSProgress
+        
+        var data: NSData? { return nil }
+        private(set) var error: NSError?
+        
+        var credential: NSURLCredential?
+        
+        var taskWillPerformHTTPRedirection: ((NSURLSession!, NSURLSessionTask!, NSHTTPURLResponse!, NSURLRequest!) -> (NSURLRequest!))?
+        var taskDidReceiveChallenge: ((NSURLSession!, NSURLSessionTask!, NSURLAuthenticationChallenge) -> (NSURLSessionAuthChallengeDisposition, NSURLCredential?))?
+        var taskDidSendBodyData: ((NSURLSession!, NSURLSessionTask!, Int64, Int64, Int64) -> Void)?
+        var taskNeedNewBodyStream: ((NSURLSession!, NSURLSessionTask!) -> (NSInputStream!))?
+        
+        init(task: NSURLSessionTask) {
+            self.task = task
+            self.progress = NSProgress(totalUnitCount: 0)
+            self.queue = {
+                let operationQueue = NSOperationQueue()
+                operationQueue.maxConcurrentOperationCount = 1
+                operationQueue.qualityOfService = NSQualityOfService.Utility
+                operationQueue.suspended = true
+                
+                return operationQueue
+            }()
+        }
+        
+        deinit {
+            queue.cancelAllOperations()
+            queue.suspended = true
+        }
+        
+        // MARK: NSURLSessionTaskDelegate
+        
+        func URLSession(session: NSURLSession, task: NSURLSessionTask, willPerformHTTPRedirection response: NSHTTPURLResponse, newRequest request: NSURLRequest, completionHandler: ((NSURLRequest!) -> Void)) {
+            var redirectRequest = request
+            if taskWillPerformHTTPRedirection != nil {
+                redirectRequest = taskWillPerformHTTPRedirection!(session, task, response, request)
+            }
+            
+            completionHandler(redirectRequest)
+        }
+        
+        func URLSession(session: NSURLSession, task: NSURLSessionTask, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: ((NSURLSessionAuthChallengeDisposition, NSURLCredential!) -> Void)) {
+            var disposition: NSURLSessionAuthChallengeDisposition = .PerformDefaultHandling
+            var credential: NSURLCredential?
+            
+            if taskDidReceiveChallenge != nil {
+                (disposition, credential) = taskDidReceiveChallenge!(session, task, challenge)
+            } else {
+                if challenge.previousFailureCount > 0 {
+                    disposition = .CancelAuthenticationChallenge
+                } else {
+                    credential = self.credential ?? session.configuration.URLCredentialStorage?.defaultCredentialForProtectionSpace(challenge.protectionSpace)
+                    if credential != nil {
+                        disposition = .UseCredential
+                    }
+                }
+            }
+            
+            completionHandler(disposition, credential)
+        }
+        
+        func URLSession(session: NSURLSession, task: NSURLSessionTask, needNewBodyStream completionHandler: ((NSInputStream!) -> Void)) {
+            var bodyStream: NSInputStream?
+            if taskNeedNewBodyStream != nil {
+                bodyStream = taskNeedNewBodyStream!(session, task)
+            }
+            
+            completionHandler(bodyStream)
+        }
+        
+        func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
+            if error != nil {
+                self.error = error
+            }
+            
+            queue.suspended = false
+        }
+    }
+    
+    class DataTaskDelegate: TaskDelegate, NSURLSessionDataDelegate {
+        var dataTask: NSURLSessionDataTask! { return task as! NSURLSessionDataTask }
+        
+        private var mutableData: NSMutableData
+        override var data: NSData? {
+            return mutableData
+        }
+        
+        private var expectedContentLength: Int64?
+        
+        var dataTaskDidReceiveResponse: ((NSURLSession!, NSURLSessionDataTask!, NSURLResponse!) -> (NSURLSessionResponseDisposition))?
+        var dataTaskDidBecomeDownloadTask: ((NSURLSession!, NSURLSessionDataTask!) -> Void)?
+        var dataTaskDidReceiveData: ((NSURLSession!, NSURLSessionDataTask!, NSData!) -> Void)?
+        var dataTaskWillCacheResponse: ((NSURLSession!, NSURLSessionDataTask!, NSCachedURLResponse!) -> (NSCachedURLResponse))?
+        var dataProgress: ((bytesReceived: Int64, totalBytesReceived: Int64, totalBytesExpectedToReceive: Int64) -> Void)?
+        
+        override init(task: NSURLSessionTask) {
+            self.mutableData = NSMutableData()
+            super.init(task: task)
+        }
+        
+        // MARK: NSURLSessionDataDelegate
+        
+        func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveResponse response: NSURLResponse, completionHandler: ((NSURLSessionResponseDisposition) -> Void)) {
+            var disposition: NSURLSessionResponseDisposition = .Allow
+            
+            expectedContentLength = response.expectedContentLength
+            
+            if dataTaskDidReceiveResponse != nil {
+                disposition = dataTaskDidReceiveResponse!(session, dataTask, response)
+            }
+            
+            completionHandler(disposition)
+        }
+        
+        func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didBecomeDownloadTask downloadTask: NSURLSessionDownloadTask) {
+            dataTaskDidBecomeDownloadTask?(session, dataTask)
+        }
+        
+        func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
+            dataTaskDidReceiveData?(session, dataTask, data)
+            
+            mutableData.appendData(data)
+            
+            if let expectedContentLength = dataTask.response?.expectedContentLength {
+                dataProgress?(bytesReceived: Int64(data.length), totalBytesReceived: Int64(mutableData.length), totalBytesExpectedToReceive: expectedContentLength)
+            }
+        }
+        
+        func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, willCacheResponse proposedResponse: NSCachedURLResponse, completionHandler: ((NSCachedURLResponse!) -> Void)) {
+            var cachedResponse = proposedResponse
+            
+            if dataTaskWillCacheResponse != nil {
+                cachedResponse = dataTaskWillCacheResponse!(session, dataTask, proposedResponse)
+            }
+            
+            completionHandler(cachedResponse)
+        }
+    }
+}
+
+// MARK: - Printable
+
+extension Request: Printable {
+    /// The textual representation used when written to an output stream, which includes the HTTP method and URL, as well as the response status code if a response has been received.
+    public var description: String {
+        var components: [String] = []
+        if request.HTTPMethod != nil {
+            components.append(request.HTTPMethod!)
+        }
+        
+        components.append(request.URL!.absoluteString!)
+        
+        if response != nil {
+            components.append("(\(response!.statusCode))")
+        }
+        
+        return join(" ", components)
+    }
+}
+
+// MARK: - DebugPrintable
+
+extension Request: DebugPrintable {
+    func cURLRepresentation() -> String {
+        var components: [String] = ["$ curl -i"]
+        
+        let URL = request.URL
+        
+        if request.HTTPMethod != nil && request.HTTPMethod != "GET" {
+            components.append("-X \(request.HTTPMethod!)")
+        }
+        
+        if let credentialStorage = self.session.configuration.URLCredentialStorage {
+            let protectionSpace = NSURLProtectionSpace(host: URL!.host!, port: URL!.port?.integerValue ?? 0, `protocol`: URL!.scheme!, realm: URL!.host!, authenticationMethod: NSURLAuthenticationMethodHTTPBasic)
+            if let credentials = credentialStorage.credentialsForProtectionSpace(protectionSpace)?.values.array {
+                for credential: NSURLCredential in (credentials as! [NSURLCredential]) {
+                    components.append("-u \(credential.user!):\(credential.password!)")
+                }
+            } else {
+                if let credential = delegate.credential {
+                    components.append("-u \(credential.user!):\(credential.password!)")
+                }
+            }
+        }
+        
+        // Temporarily disabled on OS X due to build failure for CocoaPods
+        // See https://github.com/CocoaPods/swift/issues/24
+        #if !os(OSX)
+            if let cookieStorage = session.configuration.HTTPCookieStorage,
+                cookies = cookieStorage.cookiesForURL(URL!) as? [NSHTTPCookie]
+                where !cookies.isEmpty
+            {
+                let string = cookies.reduce(""){ $0 + "\($1.name)=\($1.value ?? String());" }
+                components.append("-b \"\(string.substringToIndex(string.endIndex.predecessor()))\"")
+            }
+        #endif
+        
+        if request.allHTTPHeaderFields != nil {
+            for (field, value) in request.allHTTPHeaderFields! {
+                switch field {
+                case "Cookie":
+                    continue
+                default:
+                    components.append("-H \"\(field): \(value)\"")
+                }
+            }
+        }
+        
+        if session.configuration.HTTPAdditionalHeaders != nil {
+            for (field, value) in session.configuration.HTTPAdditionalHeaders! {
+                switch field {
+                case "Cookie":
+                    continue
+                default:
+                    components.append("-H \"\(field): \(value)\"")
+                }
+            }
+        }
+        
+        if let HTTPBody = request.HTTPBody,
+            escapedBody = NSString(data: HTTPBody, encoding: NSUTF8StringEncoding)?.stringByReplacingOccurrencesOfString("\"", withString: "\\\"")
+        {
+            components.append("-d \"\(escapedBody)\"")
+        }
+        
+        components.append("\"\(URL!.absoluteString!)\"")
+        
+        return join(" \\\n\t", components)
+    }
+    
+    /// The textual representation used when written to an output stream, in the form of a cURL command.
+    public var debugDescription: String {
+        return cURLRepresentation()
+    }
+}