mirror of
https://bitbucket.org/vendoo/vendoo_v1.0.git
synced 2025-12-25 11:47:40 +00:00
616 lines
29 KiB
Swift
616 lines
29 KiB
Swift
/*
|
|
* JBoss, Home of Professional Open Source.
|
|
* Copyright Red Hat, Inc., and individual contributors
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
import Foundation
|
|
|
|
/**
|
|
The HTTP method verb:
|
|
|
|
- GET: GET http verb
|
|
- HEAD: HEAD http verb
|
|
- DELETE: DELETE http verb
|
|
- POST: POST http verb
|
|
- PUT: PUT http verb
|
|
*/
|
|
public enum HttpMethod: String {
|
|
case GET = "GET"
|
|
case HEAD = "HEAD"
|
|
case DELETE = "DELETE"
|
|
case POST = "POST"
|
|
case PUT = "PUT"
|
|
}
|
|
|
|
/**
|
|
The file request type:
|
|
|
|
- Download: Download request
|
|
- Upload: Upload request
|
|
*/
|
|
enum FileRequestType {
|
|
case Download(String?)
|
|
case Upload(UploadType)
|
|
}
|
|
|
|
/**
|
|
The Upload enum type:
|
|
|
|
- Data: for a generic NSData object
|
|
- File: for File passing the URL of the local file to upload
|
|
- Stream: for a Stream request passing the actual NSInputStream
|
|
*/
|
|
enum UploadType {
|
|
case Data(NSData)
|
|
case File(NSURL)
|
|
case Stream(NSInputStream)
|
|
}
|
|
|
|
/**
|
|
Error domain.
|
|
**/
|
|
public let HttpErrorDomain = "HttpDomain"
|
|
/**
|
|
Request error.
|
|
**/
|
|
public let NetworkingOperationFailingURLRequestErrorKey = "NetworkingOperationFailingURLRequestErrorKey"
|
|
/**
|
|
Response error.
|
|
**/
|
|
public let NetworkingOperationFailingURLResponseErrorKey = "NetworkingOperationFailingURLResponseErrorKey"
|
|
|
|
public typealias ProgressBlock = (Int64, Int64, Int64) -> Void
|
|
public typealias CompletionBlock = (AnyObject?, NSError?) -> Void
|
|
|
|
/**
|
|
Main class for performing HTTP operations across RESTful resources.
|
|
*/
|
|
public class Http {
|
|
|
|
var baseURL: String?
|
|
var session: NSURLSession
|
|
var requestSerializer: RequestSerializer
|
|
var responseSerializer: ResponseSerializer
|
|
public var authzModule: AuthzModule?
|
|
|
|
private var delegate: SessionDelegate
|
|
|
|
/**
|
|
Initialize an HTTP object.
|
|
|
|
:param: baseURL the remote base URL of the application (optional).
|
|
:param: sessionConfig the SessionConfiguration object (by default it uses a defaultSessionConfiguration).
|
|
:param: requestSerializer the actual request serializer to use when performing requests.
|
|
:param: responseSerializer the actual response serializer to use upon receiving a response.
|
|
|
|
:returns: the newly intitialized HTTP object
|
|
*/
|
|
public init(baseURL: String? = nil,
|
|
sessionConfig: NSURLSessionConfiguration = NSURLSessionConfiguration.defaultSessionConfiguration(),
|
|
requestSerializer: RequestSerializer = JsonRequestSerializer(),
|
|
responseSerializer: ResponseSerializer = JsonResponseSerializer()) {
|
|
self.baseURL = baseURL
|
|
self.delegate = SessionDelegate()
|
|
self.session = NSURLSession(configuration: sessionConfig, delegate: self.delegate, delegateQueue: NSOperationQueue.mainQueue())
|
|
self.requestSerializer = requestSerializer
|
|
self.responseSerializer = responseSerializer
|
|
}
|
|
|
|
deinit {
|
|
self.session.finishTasksAndInvalidate()
|
|
}
|
|
|
|
/**
|
|
Gateway to perform different http requests including multipart.
|
|
|
|
:param: url the url of the resource.
|
|
:param: parameters the request parameters.
|
|
:param: method the method to be used.
|
|
:param: completionHandler A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: The object created from the response data of request and the `NSError` object describing the network or parsing error that occurred.
|
|
*/
|
|
public func request(method: HttpMethod, path: String, parameters: [String: AnyObject]? = nil, credential: NSURLCredential? = nil, responseSerializer: ResponseSerializer? = nil, completionHandler: CompletionBlock) {
|
|
let block: () -> Void = {
|
|
let finalOptURL = self.calculateURL(self.baseURL, url: path)
|
|
guard let finalURL = finalOptURL else {
|
|
let error = NSError(domain: "AeroGearHttp", code: 0, userInfo: [NSLocalizedDescriptionKey: "Malformed URL"])
|
|
completionHandler(nil, error)
|
|
return
|
|
}
|
|
|
|
var request: NSURLRequest
|
|
var task: NSURLSessionTask?
|
|
var delegate: TaskDataDelegate
|
|
// Merge headers
|
|
let headers = merge(self.requestSerializer.headers, self.authzModule?.authorizationFields())
|
|
|
|
// care for multipart request is multipart data are set
|
|
if (self.hasMultiPartData(parameters)) {
|
|
request = self.requestSerializer.multipartRequest(finalURL, method: method, parameters: parameters, headers: headers)
|
|
task = self.session.uploadTaskWithStreamedRequest(request)
|
|
delegate = TaskUploadDelegate()
|
|
} else {
|
|
request = self.requestSerializer.request(finalURL, method: method, parameters: parameters, headers: headers)
|
|
task = self.session.dataTaskWithRequest(request);
|
|
delegate = TaskDataDelegate()
|
|
}
|
|
|
|
delegate.completionHandler = completionHandler
|
|
delegate.responseSerializer = responseSerializer == nil ? self.responseSerializer : responseSerializer
|
|
delegate.credential = credential
|
|
|
|
self.delegate[task] = delegate
|
|
if let task = task {task.resume()}
|
|
}
|
|
|
|
// cater for authz and pre-authorize prior to performing request
|
|
if (self.authzModule != nil) {
|
|
self.authzModule?.requestAccess({ (response, error ) in
|
|
// if there was an error during authz, no need to continue
|
|
if (error != nil) {
|
|
completionHandler(nil, error)
|
|
return
|
|
}
|
|
// ..otherwise proceed normally
|
|
block();
|
|
})
|
|
} else {
|
|
block()
|
|
}
|
|
}
|
|
|
|
/**
|
|
Gateway to perform different file requests either download or upload.
|
|
|
|
:param: url the url of the resource.
|
|
:param: parameters the request parameters.
|
|
:param: method the method to be used.
|
|
:param: responseSerializer the actual response serializer to use upon receiving a response
|
|
:param: type the file request type
|
|
:param: progress a block that will be invoked to report progress during either download or upload.
|
|
:param: completionHandler A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: The object created from the response data of request and the `NSError` object describing the network or parsing error that occurred.
|
|
*/
|
|
private func fileRequest(url: String, parameters: [String: AnyObject]? = nil, method: HttpMethod, credential: NSURLCredential? = nil, responseSerializer: ResponseSerializer? = nil, type: FileRequestType, progress: ProgressBlock?, completionHandler: CompletionBlock) {
|
|
|
|
let block: () -> Void = {
|
|
let finalOptURL = self.calculateURL(self.baseURL, url: url)
|
|
guard let finalURL = finalOptURL else {
|
|
let error = NSError(domain: "AeroGearHttp", code: 0, userInfo: [NSLocalizedDescriptionKey: "Malformed URL"])
|
|
completionHandler(nil, error)
|
|
return
|
|
}
|
|
var request: NSURLRequest
|
|
// Merge headers
|
|
let headers = merge(self.requestSerializer.headers, self.authzModule?.authorizationFields())
|
|
|
|
// care for multipart request is multipart data are set
|
|
if (self.hasMultiPartData(parameters)) {
|
|
request = self.requestSerializer.multipartRequest(finalURL, method: method, parameters: parameters, headers: headers)
|
|
} else {
|
|
request = self.requestSerializer.request(finalURL, method: method, parameters: parameters, headers: headers)
|
|
}
|
|
|
|
var task: NSURLSessionTask?
|
|
|
|
switch type {
|
|
case .Download(let destinationDirectory):
|
|
task = self.session.downloadTaskWithRequest(request)
|
|
|
|
let delegate = TaskDownloadDelegate()
|
|
delegate.downloadProgress = progress
|
|
delegate.destinationDirectory = destinationDirectory;
|
|
delegate.completionHandler = completionHandler
|
|
delegate.credential = credential
|
|
delegate.responseSerializer = responseSerializer == nil ? self.responseSerializer : responseSerializer
|
|
self.delegate[task] = delegate
|
|
|
|
case .Upload(let uploadType):
|
|
switch uploadType {
|
|
case .Data(let data):
|
|
task = self.session.uploadTaskWithRequest(request, fromData: data)
|
|
case .File(let url):
|
|
task = self.session.uploadTaskWithRequest(request, fromFile: url)
|
|
case .Stream(_):
|
|
task = self.session.uploadTaskWithStreamedRequest(request)
|
|
}
|
|
|
|
let delegate = TaskUploadDelegate()
|
|
delegate.uploadProgress = progress
|
|
delegate.completionHandler = completionHandler
|
|
delegate.credential = credential
|
|
delegate.responseSerializer = responseSerializer
|
|
|
|
self.delegate[task] = delegate
|
|
}
|
|
|
|
if let task = task {task.resume()}
|
|
}
|
|
|
|
// cater for authz and pre-authorize prior to performing request
|
|
if (self.authzModule != nil) {
|
|
self.authzModule?.requestAccess({ (response, error ) in
|
|
// if there was an error during authz, no need to continue
|
|
if (error != nil) {
|
|
completionHandler(nil, error)
|
|
return
|
|
}
|
|
// ..otherwise proceed normally
|
|
block();
|
|
})
|
|
} else {
|
|
block()
|
|
}
|
|
}
|
|
|
|
/**
|
|
Request to download a file.
|
|
|
|
:param: url the URL of the downloadable resource.
|
|
:param: destinationDirectory the destination directory where the file would be stored, if not specified. application's default '.Documents' directory would be used.
|
|
:param: parameters the request parameters.
|
|
:param: credential the credentials to use for basic/digest auth (Note: it is advised that HTTPS should be used by default).
|
|
:param: method the method to be used, by default a .GET request.
|
|
:param: progress a block that will be invoked to report progress during download.
|
|
:param: completionHandler a block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: The object created from the response data of request and the `NSError` object describing the network or parsing error that occurred.
|
|
*/
|
|
public func download(url: String, destinationDirectory: String? = nil, parameters: [String: AnyObject]? = nil, credential: NSURLCredential? = nil, method: HttpMethod = .GET, progress: ProgressBlock?, completionHandler: CompletionBlock) {
|
|
fileRequest(url, parameters: parameters, method: method, credential: credential, type: .Download(destinationDirectory), progress: progress, completionHandler: completionHandler)
|
|
}
|
|
|
|
/**
|
|
Request to upload a file using an NURL of a local file.
|
|
|
|
:param: url the URL to upload resource into.
|
|
:param: file the URL of the local file to be uploaded.
|
|
:param: parameters the request parameters.
|
|
:param: credential the credentials to use for basic/digest auth (Note: it is advised that HTTPS should be used by default).
|
|
:param: method the method to be used, by default a .POST request.
|
|
:param: responseSerializer the actual response serializer to use upon receiving a response.
|
|
:param: progress a block that will be invoked to report progress during upload.
|
|
:param: completionHandler A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: The object created from the response data of request and the `NSError` object describing the network or parsing error that occurred.
|
|
*/
|
|
public func upload(url: String, file: NSURL, parameters: [String: AnyObject]? = nil, credential: NSURLCredential? = nil, method: HttpMethod = .POST, responseSerializer: ResponseSerializer? = nil, progress: ProgressBlock?, completionHandler: CompletionBlock) {
|
|
fileRequest(url, parameters: parameters, method: method, credential: credential, responseSerializer: responseSerializer, type: .Upload(.File(file)), progress: progress, completionHandler: completionHandler)
|
|
}
|
|
|
|
/**
|
|
Request to upload a file using a raw NSData object.
|
|
|
|
:param: url the URL to upload resource into.
|
|
:param: data the data to be uploaded.
|
|
:param: parameters the request parameters.
|
|
:param: credential the credentials to use for basic/digest auth (Note: it is advised that HTTPS should be used by default).
|
|
:param: method the method to be used, by default a .POST request.
|
|
:param: responseSerializer the actual response serializer to use upon receiving a response.
|
|
:param: progress a block that will be invoked to report progress during upload.
|
|
:param: completionHandler A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: The object created from the response data of request and the `NSError` object describing the network or parsing error that occurred.
|
|
*/
|
|
public func upload(url: String, data: NSData, parameters: [String: AnyObject]? = nil, credential: NSURLCredential? = nil, method: HttpMethod = .POST, responseSerializer: ResponseSerializer? = nil, progress: ProgressBlock?, completionHandler: CompletionBlock) {
|
|
fileRequest(url, parameters: parameters, method: method, credential: credential, responseSerializer: responseSerializer, type: .Upload(.Data(data)), progress: progress, completionHandler: completionHandler)
|
|
}
|
|
|
|
/**
|
|
Request to upload a file using an NSInputStream object.
|
|
|
|
- parameter url: the URL to upload resource into.
|
|
- parameter stream: the stream that will be used for uploading.
|
|
- parameter parameters: the request parameters.
|
|
- parameter credential: the credentials to use for basic/digest auth (Note: it is advised that HTTPS should be used by default).
|
|
- parameter method: the method to be used, by default a .POST request.
|
|
- parameter responseSerializer: the actual response serializer to use upon receiving a response.
|
|
- parameter progress: a block that will be invoked to report progress during upload.
|
|
- parameter completionHandler: A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: The object created from the response data of request and the `NSError` object describing the network or parsing error that occurred.
|
|
*/
|
|
public func upload(url: String, stream: NSInputStream, parameters: [String: AnyObject]? = nil, credential: NSURLCredential? = nil, method: HttpMethod = .POST, responseSerializer: ResponseSerializer? = nil, progress: ProgressBlock?, completionHandler: CompletionBlock) {
|
|
fileRequest(url, parameters: parameters, method: method, credential: credential, responseSerializer: responseSerializer, type: .Upload(.Stream(stream)), progress: progress, completionHandler: completionHandler)
|
|
}
|
|
|
|
|
|
// MARK: Private API
|
|
|
|
// MARK: SessionDelegate
|
|
class SessionDelegate: NSObject, NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate {
|
|
|
|
private var delegates: [Int: TaskDelegate]
|
|
|
|
private subscript(task: NSURLSessionTask?) -> TaskDelegate? {
|
|
get {
|
|
guard let task = task else {
|
|
return nil
|
|
}
|
|
return self.delegates[task.taskIdentifier]
|
|
}
|
|
|
|
set (newValue) {
|
|
guard let task = task else {
|
|
return
|
|
}
|
|
self.delegates[task.taskIdentifier] = newValue
|
|
}
|
|
}
|
|
|
|
required override init() {
|
|
self.delegates = Dictionary()
|
|
super.init()
|
|
}
|
|
|
|
func URLSession(session: NSURLSession, didBecomeInvalidWithError error: NSError?) {
|
|
// TODO
|
|
}
|
|
|
|
func URLSession(session: NSURLSession, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) {
|
|
completionHandler(.PerformDefaultHandling, nil)
|
|
}
|
|
|
|
func URLSessionDidFinishEventsForBackgroundURLSession(session: NSURLSession) {
|
|
// TODO
|
|
}
|
|
|
|
// MARK: NSURLSessionTaskDelegate
|
|
|
|
func URLSession(session: NSURLSession, task: NSURLSessionTask, willPerformHTTPRedirection response: NSHTTPURLResponse, newRequest request: NSURLRequest, completionHandler: (NSURLRequest?) -> Void) {
|
|
|
|
if let delegate = self[task] {
|
|
delegate.URLSession(session, task: task, willPerformHTTPRedirection: response, newRequest: request, completionHandler: completionHandler)
|
|
}
|
|
}
|
|
|
|
func URLSession(session: NSURLSession, task: NSURLSessionTask, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) {
|
|
|
|
if let delegate = self[task] {
|
|
delegate.URLSession(session, task: task, didReceiveChallenge: challenge, completionHandler: completionHandler)
|
|
} else {
|
|
self.URLSession(session, didReceiveChallenge: challenge, completionHandler: completionHandler)
|
|
}
|
|
}
|
|
|
|
func URLSession(session: NSURLSession, task: NSURLSessionTask, needNewBodyStream completionHandler: (NSInputStream?) -> Void) {
|
|
if let delegate = self[task] {
|
|
delegate.URLSession(session, task: task, needNewBodyStream: completionHandler)
|
|
}
|
|
}
|
|
|
|
func URLSession(session: NSURLSession, task: NSURLSessionTask, didSendBodyData bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) {
|
|
if let delegate = self[task] as? TaskUploadDelegate {
|
|
delegate.URLSession(session, task: task, didSendBodyData: bytesSent, totalBytesSent: totalBytesSent, totalBytesExpectedToSend: totalBytesExpectedToSend)
|
|
}
|
|
}
|
|
|
|
func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
|
|
if let delegate = self[task] {
|
|
delegate.URLSession(session, task: task, didCompleteWithError: error)
|
|
|
|
self[task] = nil
|
|
}
|
|
}
|
|
|
|
// MARK: NSURLSessionDataDelegate
|
|
|
|
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveResponse response: NSURLResponse, completionHandler: (NSURLSessionResponseDisposition) -> Void) {
|
|
completionHandler(.Allow)
|
|
}
|
|
|
|
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didBecomeDownloadTask downloadTask: NSURLSessionDownloadTask) {
|
|
let downloadDelegate = TaskDownloadDelegate()
|
|
self[downloadTask] = downloadDelegate
|
|
}
|
|
|
|
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
|
|
if let delegate = self[dataTask] as? TaskDataDelegate {
|
|
delegate.URLSession(session, dataTask: dataTask, didReceiveData: data)
|
|
}
|
|
}
|
|
|
|
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, willCacheResponse proposedResponse: NSCachedURLResponse, completionHandler: (NSCachedURLResponse?) -> Void) {
|
|
completionHandler(proposedResponse)
|
|
}
|
|
|
|
// MARK: NSURLSessionDownloadDelegate
|
|
|
|
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didFinishDownloadingToURL location: NSURL) {
|
|
if let delegate = self[downloadTask] as? TaskDownloadDelegate {
|
|
delegate.URLSession(session, downloadTask: downloadTask, didFinishDownloadingToURL: location)
|
|
}
|
|
}
|
|
|
|
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
|
|
if let delegate = self[downloadTask] as? TaskDownloadDelegate {
|
|
delegate.URLSession(session, downloadTask: downloadTask, didWriteData: bytesWritten, totalBytesWritten: totalBytesWritten, totalBytesExpectedToWrite: totalBytesExpectedToWrite)
|
|
}
|
|
}
|
|
|
|
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didResumeAtOffset fileOffset: Int64, expectedTotalBytes: Int64) {
|
|
if let delegate = self[downloadTask] as? TaskDownloadDelegate {
|
|
delegate.URLSession(session, downloadTask: downloadTask, didResumeAtOffset: fileOffset, expectedTotalBytes: expectedTotalBytes)
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: NSURLSessionTaskDelegate
|
|
class TaskDelegate: NSObject, NSURLSessionTaskDelegate {
|
|
|
|
var data: NSData? { return nil }
|
|
var completionHandler: ((AnyObject?, NSError?) -> Void)?
|
|
var responseSerializer: ResponseSerializer?
|
|
|
|
var credential: NSURLCredential?
|
|
|
|
func URLSession(session: NSURLSession, task: NSURLSessionTask, willPerformHTTPRedirection response: NSHTTPURLResponse, newRequest request: NSURLRequest, completionHandler: (NSURLRequest?) -> Void) {
|
|
|
|
completionHandler(request)
|
|
}
|
|
|
|
func URLSession(session: NSURLSession, task: NSURLSessionTask, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) {
|
|
var disposition: NSURLSessionAuthChallengeDisposition = .PerformDefaultHandling
|
|
var credential: NSURLCredential?
|
|
|
|
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)) {
|
|
|
|
}
|
|
|
|
func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
|
|
if error != nil {
|
|
completionHandler?(nil, error)
|
|
return
|
|
}
|
|
|
|
|
|
let response = task.response as! NSHTTPURLResponse
|
|
if let _ = task as? NSURLSessionDownloadTask {
|
|
completionHandler?(response, error)
|
|
return
|
|
}
|
|
|
|
var responseObject: AnyObject? = nil
|
|
do {
|
|
if let data = data {
|
|
try self.responseSerializer?.validateResponse(response, data)
|
|
responseObject = self.responseSerializer?.response(data, response.statusCode)
|
|
completionHandler?(responseObject, nil)
|
|
}
|
|
} catch let error as NSError {
|
|
var userInfo = error.userInfo
|
|
userInfo["StatusCode"] = response.statusCode
|
|
let errorToRethrow = NSError(domain: error.domain, code: error.code, userInfo: userInfo)
|
|
completionHandler?(responseObject, errorToRethrow)
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: NSURLSessionDataDelegate
|
|
class TaskDataDelegate: TaskDelegate, NSURLSessionDataDelegate {
|
|
|
|
private var mutableData: NSMutableData
|
|
|
|
override var data: NSData? {
|
|
return self.mutableData
|
|
}
|
|
|
|
override init() {
|
|
self.mutableData = NSMutableData()
|
|
}
|
|
|
|
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveResponse response: NSURLResponse, completionHandler: (NSURLSessionResponseDisposition) -> Void) {
|
|
completionHandler(.Allow)
|
|
}
|
|
|
|
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
|
|
self.mutableData.appendData(data)
|
|
}
|
|
|
|
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, willCacheResponse proposedResponse: NSCachedURLResponse, completionHandler: (NSCachedURLResponse?) -> Void) {
|
|
let cachedResponse = proposedResponse
|
|
completionHandler(cachedResponse)
|
|
}
|
|
}
|
|
|
|
// MARK: NSURLSessionDownloadDelegate
|
|
class TaskDownloadDelegate: TaskDelegate, NSURLSessionDownloadDelegate {
|
|
|
|
var downloadProgress: ((Int64, Int64, Int64) -> Void)?
|
|
var resumeData: NSData?
|
|
var destinationDirectory: NSString?
|
|
|
|
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didFinishDownloadingToURL location: NSURL) {
|
|
let filename = downloadTask.response?.suggestedFilename
|
|
|
|
// calculate final destination
|
|
var finalDestination: NSURL
|
|
if (destinationDirectory == nil) { // use 'default documents' directory if not set
|
|
// use default documents directory
|
|
let documentsDirectory = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0] as NSURL
|
|
#if swift(>=2.3)
|
|
// this compiles on Xcode 8 / Swift 2.3 / iOS 10
|
|
finalDestination = documentsDirectory.URLByAppendingPathComponent(filename!)!
|
|
#else
|
|
// this compiles on Xcode 7 / Swift 2.2 / iOS 9
|
|
finalDestination = documentsDirectory.URLByAppendingPathComponent(filename!)
|
|
#endif
|
|
} else {
|
|
// check that the directory exists
|
|
let path = destinationDirectory?.stringByAppendingPathComponent(filename!)
|
|
finalDestination = NSURL(fileURLWithPath: path!)
|
|
}
|
|
|
|
do {
|
|
try NSFileManager.defaultManager().moveItemAtURL(location, toURL: finalDestination)
|
|
} catch _ {
|
|
}
|
|
}
|
|
|
|
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
|
|
|
|
self.downloadProgress?(bytesWritten, totalBytesWritten, totalBytesExpectedToWrite)
|
|
}
|
|
|
|
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didResumeAtOffset fileOffset: Int64, expectedTotalBytes: Int64) {
|
|
}
|
|
}
|
|
|
|
// MARK: NSURLSessionTaskDelegate
|
|
class TaskUploadDelegate: TaskDataDelegate {
|
|
|
|
var uploadProgress: ((Int64, Int64, Int64) -> Void)?
|
|
|
|
func URLSession(session: NSURLSession, task: NSURLSessionTask, didSendBodyData bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) {
|
|
self.uploadProgress?(bytesSent, totalBytesSent, totalBytesExpectedToSend)
|
|
}
|
|
}
|
|
|
|
// MARK: Utility methods
|
|
public func calculateURL(baseURL: String?, url: String) -> NSURL? {
|
|
var url = url
|
|
if (baseURL == nil || url.hasPrefix("http")) {
|
|
return NSURL(string: url)!
|
|
}
|
|
|
|
guard let finalURL = NSURL(string: baseURL!) else {return nil}
|
|
if (url.hasPrefix("/")) {
|
|
url = url.substringFromIndex(url.startIndex.advancedBy(1))
|
|
}
|
|
|
|
return finalURL.URLByAppendingPathComponent(url);
|
|
}
|
|
|
|
public func hasMultiPartData(parameters: [String: AnyObject]?) -> Bool {
|
|
if (parameters == nil) {
|
|
return false
|
|
}
|
|
|
|
var isMultiPart = false
|
|
for (_, value) in parameters! {
|
|
if value is MultiPartData {
|
|
isMultiPart = true
|
|
break
|
|
}
|
|
}
|
|
|
|
return isMultiPart
|
|
}
|
|
}
|