mirror of
https://bitbucket.org/vendoo/vendoo_v1.0.git
synced 2025-12-25 11:47:40 +00:00
308 lines
13 KiB
Swift
308 lines
13 KiB
Swift
//
|
|
// OAuthSwiftHTTPRequest.swift
|
|
// OAuthSwift
|
|
//
|
|
// Created by Dongri Jin on 6/21/14.
|
|
// Copyright (c) 2014 Dongri Jin. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
public class OAuthSwiftHTTPRequest: NSObject, NSURLSessionDelegate {
|
|
|
|
public typealias SuccessHandler = (data: NSData, response: NSHTTPURLResponse) -> Void
|
|
public typealias FailureHandler = (error: NSError) -> Void
|
|
|
|
public enum Method: String {
|
|
case GET, POST, PUT, DELETE, PATCH, HEAD //, OPTIONS, TRACE, CONNECT
|
|
|
|
var isBody: Bool {
|
|
return self == .POST || self == .PUT || self == .PATCH
|
|
}
|
|
}
|
|
|
|
@objc public enum ParamsLocation : Int {
|
|
case AuthorizationHeader, /*FormEncodedBody,*/ RequestURIQuery
|
|
}
|
|
|
|
var URL: NSURL
|
|
var HTTPMethod: Method
|
|
var HTTPBody: NSData?
|
|
|
|
var request: NSMutableURLRequest?
|
|
var task: NSURLSessionTask?
|
|
var session: NSURLSession!
|
|
|
|
var headers: Dictionary<String, String>
|
|
var parameters: Dictionary<String, AnyObject>
|
|
|
|
var dataEncoding: NSStringEncoding
|
|
var charset: CFString {
|
|
return CFStringConvertEncodingToIANACharSetName(CFStringConvertNSStringEncodingToEncoding(self.dataEncoding))
|
|
}
|
|
|
|
var timeoutInterval: NSTimeInterval
|
|
|
|
var HTTPShouldHandleCookies: Bool
|
|
|
|
var response: NSHTTPURLResponse!
|
|
var responseData: NSMutableData
|
|
|
|
var successHandler: SuccessHandler?
|
|
var failureHandler: FailureHandler?
|
|
|
|
var paramsLocation: ParamsLocation
|
|
|
|
public static var executionContext: (() -> Void) -> Void = { block in
|
|
return dispatch_async(dispatch_get_main_queue(), block)
|
|
}
|
|
|
|
convenience init(URL: NSURL) {
|
|
self.init(URL: URL, method: .GET, parameters: [:])
|
|
}
|
|
|
|
init(URL: NSURL, method: Method, parameters: Dictionary<String, AnyObject>, paramsLocation : ParamsLocation = .AuthorizationHeader) {
|
|
self.URL = URL
|
|
self.HTTPMethod = method
|
|
self.headers = [:]
|
|
self.parameters = parameters
|
|
self.dataEncoding = NSUTF8StringEncoding
|
|
self.timeoutInterval = 60
|
|
self.HTTPShouldHandleCookies = false
|
|
self.responseData = NSMutableData()
|
|
self.paramsLocation = paramsLocation
|
|
}
|
|
|
|
init(request: NSURLRequest, paramsLocation : ParamsLocation = .AuthorizationHeader) {
|
|
self.request = request.mutableCopy() as? NSMutableURLRequest
|
|
|
|
self.URL = request.URL!
|
|
self.HTTPMethod = Method(rawValue: request.HTTPMethod ?? "") ?? .GET
|
|
self.headers = request.allHTTPHeaderFields ?? [:]
|
|
self.parameters = [:]
|
|
self.HTTPBody = request.HTTPBody
|
|
self.dataEncoding = NSUTF8StringEncoding
|
|
self.timeoutInterval = request.timeoutInterval
|
|
self.HTTPShouldHandleCookies = request.HTTPShouldHandleCookies
|
|
self.responseData = NSMutableData()
|
|
self.paramsLocation = paramsLocation
|
|
}
|
|
|
|
func start() {
|
|
if (request == nil) {
|
|
var error: NSError?
|
|
|
|
do {
|
|
self.request = try self.makeRequest()
|
|
} catch let error1 as NSError {
|
|
error = error1
|
|
self.request = nil
|
|
}
|
|
|
|
if ((error) != nil) {
|
|
print(error!.localizedDescription)
|
|
}
|
|
}
|
|
|
|
OAuthSwiftHTTPRequest.executionContext {
|
|
self.session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration(),
|
|
delegate: self,
|
|
delegateQueue: NSOperationQueue.mainQueue())
|
|
self.task = self.session.dataTaskWithRequest(self.request!) { [unowned self] data, response, error -> Void in
|
|
#if os(iOS)
|
|
#if !OAUTH_APP_EXTENSIONS
|
|
UIApplication.sharedApplication().networkActivityIndicatorVisible = false
|
|
#endif
|
|
#endif
|
|
|
|
guard error == nil else {
|
|
self.failureHandler?(error: error!)
|
|
return
|
|
}
|
|
|
|
guard response != nil && (response as? NSHTTPURLResponse) != nil && data != nil else {
|
|
let responseString = NSString(data: self.responseData, encoding: self.dataEncoding)
|
|
let localizedDescription = OAuthSwiftHTTPRequest.descriptionForHTTPStatus(self.response.statusCode, responseString: responseString! as String)
|
|
let userInfo : [NSObject : AnyObject] = [NSLocalizedDescriptionKey: localizedDescription, "Response-Headers": self.response.allHeaderFields]
|
|
let error = NSError(domain: NSURLErrorDomain, code: self.response.statusCode, userInfo: userInfo)
|
|
self.failureHandler?(error: error)
|
|
return
|
|
}
|
|
|
|
self.response = response as? NSHTTPURLResponse
|
|
self.responseData.length = 0
|
|
self.responseData.appendData(data!)
|
|
|
|
if (response as? NSHTTPURLResponse)?.statusCode >= 400 {
|
|
let responseString = NSString(data: self.responseData, encoding: self.dataEncoding)
|
|
let localizedDescription = OAuthSwiftHTTPRequest.descriptionForHTTPStatus(self.response.statusCode, responseString: responseString! as String)
|
|
let userInfo : [NSObject : AnyObject] = [
|
|
NSLocalizedDescriptionKey: localizedDescription,
|
|
"Response-Headers": self.response.allHeaderFields,
|
|
"Response-Body": responseString ?? NSNull()
|
|
]
|
|
let error = NSError(domain: NSURLErrorDomain, code: self.response.statusCode, userInfo: userInfo)
|
|
self.failureHandler?(error: error)
|
|
return
|
|
}
|
|
|
|
self.successHandler?(data: self.responseData, response: self.response)
|
|
}
|
|
self.task?.resume()
|
|
|
|
#if os(iOS)
|
|
#if !OAUTH_APP_EXTENSIONS
|
|
UIApplication.sharedApplication().networkActivityIndicatorVisible = true
|
|
#endif
|
|
#endif
|
|
}
|
|
}
|
|
|
|
public func cancel() {
|
|
task?.cancel()
|
|
}
|
|
|
|
public func makeRequest() throws -> NSMutableURLRequest {
|
|
return try OAuthSwiftHTTPRequest.makeRequest(self.URL, method: self.HTTPMethod, headers: self.headers, parameters: self.parameters, dataEncoding: self.dataEncoding, body: self.HTTPBody, paramsLocation: self.paramsLocation)
|
|
}
|
|
|
|
public class func makeRequest(
|
|
URL: NSURL,
|
|
method: Method,
|
|
headers: [String : String],
|
|
parameters: Dictionary<String, AnyObject>,
|
|
dataEncoding: NSStringEncoding,
|
|
body: NSData? = nil,
|
|
paramsLocation: ParamsLocation = .AuthorizationHeader) throws -> NSMutableURLRequest {
|
|
let request = NSMutableURLRequest(URL: URL)
|
|
request.HTTPMethod = method.rawValue
|
|
return try setupRequestForOAuth(request,
|
|
headers: headers,
|
|
parameters: parameters,
|
|
dataEncoding: dataEncoding,
|
|
body: body,
|
|
paramsLocation: paramsLocation
|
|
)
|
|
|
|
}
|
|
|
|
public class func setupRequestForOAuth(request: NSMutableURLRequest,
|
|
headers: [String : String],
|
|
parameters: Dictionary<String, AnyObject>,
|
|
dataEncoding: NSStringEncoding,
|
|
body: NSData? = nil,
|
|
paramsLocation : ParamsLocation = .AuthorizationHeader) throws -> NSMutableURLRequest {
|
|
for (key, value) in headers {
|
|
request.setValue(value, forHTTPHeaderField: key)
|
|
}
|
|
|
|
let charset = CFStringConvertEncodingToIANACharSetName(CFStringConvertNSStringEncodingToEncoding(dataEncoding))
|
|
|
|
let finalParameters : Dictionary<String, AnyObject>
|
|
switch (paramsLocation) {
|
|
case .AuthorizationHeader:
|
|
finalParameters = parameters.filter { key, _ in !key.hasPrefix("oauth_") }
|
|
case .RequestURIQuery:
|
|
finalParameters = parameters
|
|
}
|
|
|
|
if let b = body {
|
|
request.HTTPBody = b
|
|
} else {
|
|
if finalParameters.count > 0 {
|
|
if request.HTTPMethod == "GET" || request.HTTPMethod == "HEAD" || request.HTTPMethod == "DELETE" {
|
|
let queryString = finalParameters.urlEncodedQueryStringWithEncoding(dataEncoding)
|
|
let URL = request.URL!
|
|
request.URL = URL.URLByAppendingQueryString(queryString)
|
|
if headers["Content-Type"] == nil {
|
|
request.setValue("application/x-www-form-urlencoded; charset=\(charset)", forHTTPHeaderField: "Content-Type")
|
|
}
|
|
}
|
|
else {
|
|
if let contentType = headers["Content-Type"] where contentType.rangeOfString("application/json") != nil {
|
|
let jsonData: NSData = try NSJSONSerialization.dataWithJSONObject(finalParameters, options: [])
|
|
request.setValue("application/json; charset=\(charset)", forHTTPHeaderField: "Content-Type")
|
|
request.HTTPBody = jsonData
|
|
}
|
|
else {
|
|
request.setValue("application/x-www-form-urlencoded; charset=\(charset)", forHTTPHeaderField: "Content-Type")
|
|
let queryString = finalParameters.urlEncodedQueryStringWithEncoding(dataEncoding)
|
|
request.HTTPBody = queryString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return request
|
|
}
|
|
|
|
class func stringWithData(data: NSData, encodingName: String?) -> String {
|
|
var encoding: UInt = NSUTF8StringEncoding
|
|
|
|
if (encodingName != nil) {
|
|
let encodingNameString = encodingName! as NSString
|
|
encoding = CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding(encodingNameString))
|
|
|
|
if encoding == UInt(kCFStringEncodingInvalidId) {
|
|
encoding = NSUTF8StringEncoding // by default
|
|
}
|
|
}
|
|
|
|
return NSString(data: data, encoding: encoding)! as String
|
|
}
|
|
|
|
class func descriptionForHTTPStatus(status: Int, responseString: String) -> String {
|
|
var s = "HTTP Status \(status)"
|
|
|
|
var description: String?
|
|
// http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
|
|
if status == 400 { description = "Bad Request" }
|
|
if status == 401 { description = "Unauthorized" }
|
|
if status == 402 { description = "Payment Required" }
|
|
if status == 403 { description = "Forbidden" }
|
|
if status == 404 { description = "Not Found" }
|
|
if status == 405 { description = "Method Not Allowed" }
|
|
if status == 406 { description = "Not Acceptable" }
|
|
if status == 407 { description = "Proxy Authentication Required" }
|
|
if status == 408 { description = "Request Timeout" }
|
|
if status == 409 { description = "Conflict" }
|
|
if status == 410 { description = "Gone" }
|
|
if status == 411 { description = "Length Required" }
|
|
if status == 412 { description = "Precondition Failed" }
|
|
if status == 413 { description = "Payload Too Large" }
|
|
if status == 414 { description = "URI Too Long" }
|
|
if status == 415 { description = "Unsupported Media Type" }
|
|
if status == 416 { description = "Requested Range Not Satisfiable" }
|
|
if status == 417 { description = "Expectation Failed" }
|
|
if status == 422 { description = "Unprocessable Entity" }
|
|
if status == 423 { description = "Locked" }
|
|
if status == 424 { description = "Failed Dependency" }
|
|
if status == 425 { description = "Unassigned" }
|
|
if status == 426 { description = "Upgrade Required" }
|
|
if status == 427 { description = "Unassigned" }
|
|
if status == 428 { description = "Precondition Required" }
|
|
if status == 429 { description = "Too Many Requests" }
|
|
if status == 430 { description = "Unassigned" }
|
|
if status == 431 { description = "Request Header Fields Too Large" }
|
|
if status == 432 { description = "Unassigned" }
|
|
if status == 500 { description = "Internal Server Error" }
|
|
if status == 501 { description = "Not Implemented" }
|
|
if status == 502 { description = "Bad Gateway" }
|
|
if status == 503 { description = "Service Unavailable" }
|
|
if status == 504 { description = "Gateway Timeout" }
|
|
if status == 505 { description = "HTTP Version Not Supported" }
|
|
if status == 506 { description = "Variant Also Negotiates" }
|
|
if status == 507 { description = "Insufficient Storage" }
|
|
if status == 508 { description = "Loop Detected" }
|
|
if status == 509 { description = "Unassigned" }
|
|
if status == 510 { description = "Not Extended" }
|
|
if status == 511 { description = "Network Authentication Required" }
|
|
|
|
if (description != nil) {
|
|
s = s + ": " + description! + ", Response: " + responseString
|
|
}
|
|
|
|
return s
|
|
}
|
|
|
|
}
|