├── .gitignore ├── .swiftlint.yml ├── LICENSE ├── PocketNet.podspec ├── PocketNet.xcodeproj ├── project.pbxproj └── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── PocketNet ├── Info.plist ├── Net │ ├── FormData.swift │ ├── NetErrors.swift │ ├── NetRequest.swift │ ├── NetSupport.swift │ ├── NetworkResponse.swift │ ├── PocketNet.swift │ └── PocketNetAlamoFire │ │ ├── CustomServerTrustPolicyManager.swift │ │ ├── CustomSessionDelegate.swift │ │ ├── PocketAlamofireAdapter.swift │ │ └── PocketNetAlamofire.swift └── PocketNet.h ├── PocketNetTests ├── Info.plist └── NetTests.swift ├── PocketNet_logo.png ├── README.md └── StaticPods ├── Alamofire 4.8.1 ├── AlamofireLicense │ └── LICENSE └── Source │ ├── AFError.swift │ ├── Alamofire.swift │ ├── DispatchQueue+Alamofire.swift │ ├── MultipartFormData.swift │ ├── NetworkReachabilityManager.swift │ ├── Notifications.swift │ ├── ParameterEncoding.swift │ ├── Request.swift │ ├── Response.swift │ ├── ResponseSerialization.swift │ ├── Result.swift │ ├── ServerTrustPolicy.swift │ ├── SessionDelegate.swift │ ├── SessionManager.swift │ ├── TaskDelegate.swift │ ├── Timeline.swift │ └── Validation.swift └── Reqres ├── ReqresLicense └── LICENSE └── Source ├── Reqres.swift ├── ReqresDefaultLogger.swift └── ReqresLogging.swift /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | *.DS_Store 6 | 7 | ## Build generated 8 | build/ 9 | DerivedData/ 10 | 11 | ## Various settings 12 | *.pbxuser 13 | !default.pbxuser 14 | *.mode1v3 15 | !default.mode1v3 16 | *.mode2v3 17 | !default.mode2v3 18 | *.perspectivev3 19 | !default.perspectivev3 20 | xcuserdata/ 21 | 22 | ## Other 23 | *.moved-aside 24 | *.xccheckout 25 | *.xcscmblueprint 26 | 27 | ## Obj-C/Swift specific 28 | *.hmap 29 | *.ipa 30 | *.dSYM.zip 31 | *.dSYM 32 | 33 | ## Playgrounds 34 | timeline.xctimeline 35 | playground.xcworkspace 36 | 37 | # Swift Package Manager 38 | # 39 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 40 | # Packages/ 41 | # Package.pins 42 | .build/ 43 | 44 | # CocoaPods 45 | # 46 | # We recommend against adding the Pods directory to your .gitignore. However 47 | # you should judge for yourself, the pros and cons are mentioned at: 48 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 49 | # 50 | # Pods/ 51 | 52 | # Carthage 53 | # 54 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 55 | # Carthage/Checkouts 56 | 57 | Carthage/Build 58 | 59 | # fastlane 60 | # 61 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 62 | # screenshots whenever they are needed. 63 | # For more information about the recommended setup visit: 64 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 65 | 66 | fastlane/report.xml 67 | fastlane/Preview.html 68 | fastlane/screenshots 69 | fastlane/test_output -------------------------------------------------------------------------------- /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | disabled_rules: # rule identifiers to exclude from running 2 | - line_length 3 | - trailing_whitespace 4 | - identifier_name 5 | - function_body_length 6 | - cyclomatic_complexity 7 | - superfluous_disable_command 8 | - force_cast 9 | - type_name 10 | - function_parameter_count 11 | - nesting 12 | #- type_name 13 | 14 | excluded: # paths to ignore during linting. Takes precedence over `included`. 15 | - Carthage 16 | - Pods 17 | - ECISDK/Pods 18 | 19 | file_length: 20 | warning: 1000 21 | error: 2000 22 | 23 | type_body_length: 24 | warning: 500 25 | error: 1000 26 | 27 | nesting: 28 | warning: 500 29 | error: 1000 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 PocketSwift 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /PocketNet.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "PocketNet" 3 | s.version = "2.4.1" 4 | s.homepage = "https://github.com/PocketSwift/PocketNet" 5 | s.summary = "Net with Alamofire implementation" 6 | s.license = { :type => 'MIT', :file => 'LICENSE' } 7 | s.author = { "PocketSwift" => "https://github.com/PocketSwift" } 8 | s.source = { :git => "https://github.com/PocketSwift/PocketNet.git", :tag => s.version } 9 | s.swift_version = '5.0' 10 | s.source_files = 'Classes', 'PocketNet/**/*.swift', 'StaticPods/**/*.swift' 11 | s.platform = :ios, '8.0' 12 | s.requires_arc = true 13 | end -------------------------------------------------------------------------------- /PocketNet.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /PocketNet.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /PocketNet/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | $(MARKETING_VERSION) 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /PocketNet/Net/FormData.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class FormData { 4 | 5 | let apiName: String 6 | let fileName: String 7 | let mimeType: String 8 | let data: Data 9 | 10 | public init(apiName: String, fileName: String, mimeType: String, data: Data) { 11 | self.apiName = apiName 12 | self.fileName = fileName 13 | self.mimeType = mimeType 14 | self.data = data 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /PocketNet/Net/NetErrors.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public enum NetError: Error { 4 | case error(statusErrorCode: Int, errorMessage: String, errorStringObject: String?, headers: [String : String]?) 5 | case noConnection 6 | case emptyResponse 7 | case mappingError 8 | case encodingError 9 | } 10 | 11 | public enum NetErrorDecodable: Error { 12 | case error(statusErrorCode: Int, errorMessage: String, errorObject: T?) 13 | case noConnection 14 | case emptyResponse 15 | case mappingError 16 | case encodingError 17 | } 18 | 19 | public struct IgnoreError: Decodable { 20 | 21 | } 22 | -------------------------------------------------------------------------------- /PocketNet/Net/NetRequest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public typealias PParameters = [String: AnyObject] 4 | 5 | public struct NetRequest { 6 | public let url: String 7 | public let method: Method 8 | public let shouldCache: Bool 9 | public let headers: [String: String] 10 | public let body: Body 11 | 12 | private init(builder: Builder) { 13 | self.url = builder.url 14 | self.method = builder.method 15 | self.shouldCache = builder.shouldCache 16 | self.headers = builder.headers 17 | self.body = Body(parameterEncoding: builder.encoding, params: builder.params) 18 | } 19 | 20 | public class Builder { 21 | 22 | public var url: String = "" 23 | public var method: Method = .get 24 | public var headers: [String: String] = [:] 25 | public var params: PParameters = [:] 26 | public var encoding: PParameterEncoding = .url 27 | public var shouldCache: Bool = true 28 | 29 | public init() { } 30 | 31 | public func url(_ url: String) -> Self { 32 | self.url = url 33 | return self 34 | } 35 | 36 | public func method(_ method: Method) -> Self { 37 | self.method = method 38 | return self 39 | } 40 | 41 | public func parameter(name: String, value: String) -> Self { 42 | self.params[name] = value as AnyObject? 43 | return self 44 | } 45 | 46 | public func body(params: String?) -> Self { 47 | guard let parameters = params else { return self } 48 | if let data = parameters.data(using: .utf8) { 49 | do { 50 | guard let dic = try JSONSerialization.jsonObject(with: data, options: []) as? PParameters 51 | else { return self } 52 | self.params = dic 53 | } catch { 54 | return self 55 | } 56 | } 57 | return self 58 | } 59 | 60 | public func parameterEncoding(_ parameterEncoding: PParameterEncoding) -> Self { 61 | self.encoding = parameterEncoding 62 | return self 63 | } 64 | 65 | public func requestHeader(_ dicRequestHeader: [String: String]) -> Self { 66 | self.headers = dicRequestHeader 67 | return self 68 | } 69 | 70 | public func shouldCache(_ shouldCache: Bool) -> Self { 71 | self.shouldCache = shouldCache 72 | return self 73 | } 74 | 75 | public func build () -> NetRequest { 76 | return NetRequest(builder: self) 77 | } 78 | 79 | } 80 | 81 | } 82 | 83 | public struct Body { 84 | public let parameterEncoding: PParameterEncoding 85 | public let params: PParameters 86 | 87 | public init(parameterEncoding: PParameterEncoding, params: PParameters) { 88 | self.parameterEncoding = parameterEncoding 89 | self.params = params 90 | } 91 | } 92 | 93 | public enum Method { 94 | case get, 95 | post, 96 | put, 97 | delete, 98 | head, 99 | options, 100 | trace, 101 | patch, 102 | connect 103 | } 104 | 105 | public enum PParameterEncoding { 106 | case url, json, form 107 | } 108 | -------------------------------------------------------------------------------- /PocketNet/Net/NetSupport.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class NetSupport { 4 | public var net: PocketNet 5 | 6 | public static var dataFetched: Data? 7 | 8 | public init(net: PocketNet) { 9 | self.net = net 10 | } 11 | } 12 | 13 | //With Data 14 | public extension NetSupport { 15 | 16 | func netJsonMappableRequestWithData(_ request: NetRequest, completion: @escaping ((Swift.Result>, Data?) -> Void)) -> Int { 17 | return net.launchRequest(request, completion: { [weak self] result in 18 | self?.processResponseWithData(completion: completion, result: result) 19 | }) 20 | } 21 | 22 | func processResponseWithData(completion: @escaping ((Swift.Result>, Data?) -> Void), result: Swift.Result) { 23 | switch result { 24 | case .success(let netResponse): 25 | guard netResponse.message != "" else { 26 | completion(Swift.Result.failure(NetErrorDecodable.emptyResponse), nil) 27 | return 28 | } 29 | guard let data: Data = netResponse.message.data(using: String.Encoding.utf8) else { completion(Swift.Result.failure(NetErrorDecodable.mappingError), nil); return } 30 | 31 | guard let object: T = try? JSONDecoder().decode(T.self, from: data) else { completion(Swift.Result.failure(NetErrorDecodable.mappingError), nil); return } 32 | completion(Swift.Result.success(object), data) 33 | case .failure(let netError): 34 | switch netError { 35 | case .emptyResponse: 36 | completion(Swift.Result.failure(.emptyResponse), nil) 37 | case .encodingError: 38 | completion(Swift.Result.failure(.encodingError), nil) 39 | case .mappingError: 40 | completion(Swift.Result.failure(.mappingError), nil) 41 | case .noConnection: 42 | completion(Swift.Result.failure(.noConnection), nil) 43 | case .error(let statusErrorCode, let errorMessage, let errorStringObject, _): 44 | var errorObject: S? 45 | if let stringToData = errorStringObject, let data: Data = stringToData.data(using: String.Encoding.utf8), let object: S = try? JSONDecoder().decode(S.self, from: data) { 46 | errorObject = object 47 | } 48 | completion(Swift.Result.failure(NetErrorDecodable.error(statusErrorCode: statusErrorCode, errorMessage: errorMessage, errorObject: errorObject)), nil) 49 | } 50 | } 51 | } 52 | 53 | func netArrayJsonMappableRequestWithData(_ request: NetRequest, completion: @escaping ((Swift.Result<[T], NetErrorDecodable>, Data?) -> Void)) -> Int { 54 | return net.launchRequest(request, completion: { [weak self] result in 55 | self?.processArrayResponseWithData(completion: completion, result: result) 56 | }) 57 | } 58 | 59 | func processArrayResponseWithData(completion: @escaping ((Swift.Result<[T], NetErrorDecodable>, Data?) -> Void), result: Swift.Result) { 60 | switch result { 61 | case .success(let netResponse): 62 | guard netResponse.message != "" else { 63 | completion(Swift.Result.failure(NetErrorDecodable.emptyResponse), nil) 64 | return 65 | } 66 | guard let data: Data = netResponse.message.data(using: String.Encoding.utf8) else { completion(Swift.Result.failure(NetErrorDecodable.mappingError), nil); return } 67 | 68 | guard let object: [T] = try? JSONDecoder().decode([T].self, from: data) else { completion(Swift.Result.failure(NetErrorDecodable.mappingError), nil); return } 69 | completion(Swift.Result.success(object), data) 70 | case .failure(let netError): 71 | switch netError { 72 | case .emptyResponse: 73 | completion(Swift.Result.failure(.emptyResponse), nil) 74 | case .encodingError: 75 | completion(Swift.Result.failure(.encodingError), nil) 76 | case .mappingError: 77 | completion(Swift.Result.failure(.mappingError), nil) 78 | case .noConnection: 79 | completion(Swift.Result.failure(.noConnection), nil) 80 | case .error(let statusErrorCode, let errorMessage, let errorStringObject, _): 81 | var errorObject: S? 82 | if let stringToData = errorStringObject, let data: Data = stringToData.data(using: String.Encoding.utf8), let object: S = try? JSONDecoder().decode(S.self, from: data) { 83 | errorObject = object 84 | } 85 | completion(Swift.Result.failure(NetErrorDecodable.error(statusErrorCode: statusErrorCode, errorMessage: errorMessage, errorObject: errorObject)), nil) 86 | } 87 | } 88 | } 89 | 90 | } 91 | 92 | //Without Data 93 | public extension NetSupport { 94 | 95 | func netJsonMappableRequest(_ request: NetRequest, completion: @escaping ((Swift.Result>) -> Void)) -> Int { 96 | return net.launchRequest(request, completion: { [weak self] result in 97 | self?.processResponse(completion: completion, result: result) 98 | }) 99 | } 100 | 101 | func processResponse(completion: @escaping ((Swift.Result>) -> Void), result: Swift.Result) { 102 | switch result { 103 | case .success(let netResponse): 104 | guard netResponse.message != "" else { 105 | completion(Swift.Result.failure(NetErrorDecodable.emptyResponse)) 106 | return 107 | } 108 | guard let data: Data = netResponse.message.data(using: String.Encoding.utf8) else { completion(Swift.Result.failure(NetErrorDecodable.mappingError)); return } 109 | 110 | guard let object: T = try? JSONDecoder().decode(T.self, from: data) else { completion(Swift.Result.failure(NetErrorDecodable.mappingError)); return } 111 | completion(Swift.Result.success(object)) 112 | case .failure(let netError): 113 | switch netError { 114 | case .emptyResponse: 115 | completion(Swift.Result.failure(.emptyResponse)) 116 | case .encodingError: 117 | completion(Swift.Result.failure(.encodingError)) 118 | case .mappingError: 119 | completion(Swift.Result.failure(.mappingError)) 120 | case .noConnection: 121 | completion(Swift.Result.failure(.noConnection)) 122 | case .error(let statusErrorCode, let errorMessage, let errorStringObject, _): 123 | var errorObject: S? 124 | if let stringToData = errorStringObject, let data: Data = stringToData.data(using: String.Encoding.utf8), let object: S = try? JSONDecoder().decode(S.self, from: data) { 125 | errorObject = object 126 | } 127 | completion(Swift.Result.failure(NetErrorDecodable.error(statusErrorCode: statusErrorCode, errorMessage: errorMessage, errorObject: errorObject))) 128 | } 129 | } 130 | } 131 | 132 | func netArrayJsonMappableRequest(_ request: NetRequest, completion: @escaping ((Swift.Result<[T], NetErrorDecodable>) -> Void)) -> Int { 133 | return net.launchRequest(request, completion: { [weak self] result in 134 | self?.processArrayResponse(completion: completion, result: result) 135 | }) 136 | } 137 | 138 | func processArrayResponse(completion: @escaping ((Swift.Result<[T], NetErrorDecodable>) -> Void), result: Swift.Result) { 139 | switch result { 140 | case .success(let netResponse): 141 | guard netResponse.message != "" else { 142 | completion(Swift.Result.failure(NetErrorDecodable.emptyResponse)) 143 | return 144 | } 145 | guard let data: Data = netResponse.message.data(using: String.Encoding.utf8) else { completion(Swift.Result.failure(NetErrorDecodable.mappingError)); return } 146 | 147 | guard let object: [T] = try? JSONDecoder().decode([T].self, from: data) else { completion(Swift.Result.failure(NetErrorDecodable.mappingError)); return } 148 | completion(Swift.Result.success(object)) 149 | case .failure(let netError): 150 | switch netError { 151 | case .emptyResponse: 152 | completion(Swift.Result.failure(.emptyResponse)) 153 | case .encodingError: 154 | completion(Swift.Result.failure(.encodingError)) 155 | case .mappingError: 156 | completion(Swift.Result.failure(.mappingError)) 157 | case .noConnection: 158 | completion(Swift.Result.failure(.noConnection)) 159 | case .error(let statusErrorCode, let errorMessage, let errorStringObject, _): 160 | var errorObject: S? 161 | if let stringToData = errorStringObject, let data: Data = stringToData.data(using: String.Encoding.utf8), let object: S = try? JSONDecoder().decode(S.self, from: data) { 162 | errorObject = object 163 | } 164 | completion(Swift.Result.failure(NetErrorDecodable.error(statusErrorCode: statusErrorCode, errorMessage: errorMessage, errorObject: errorObject))) 165 | } 166 | } 167 | } 168 | 169 | func netUploadArchives(_ request: NetRequest, archives: [FormData], jsonKey: String, actualProgress:@escaping ((Double) -> Void), completion: @escaping ((Swift.Result>) -> Void)) -> Int { 170 | return net.uploadRequest(request, archives: archives, jsonKey: jsonKey, 171 | actualProgress: { progress in 172 | actualProgress(progress) 173 | }, 174 | completion: { [weak self] result in 175 | self?.processResponse(completion: completion, result: result) 176 | }) 177 | } 178 | 179 | } 180 | -------------------------------------------------------------------------------- /PocketNet/Net/NetworkResponse.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct NetworkResponse { 4 | public let statusCode: Int 5 | public let message: String 6 | public let headers: [String: String] 7 | 8 | public init(statusCode: Int) { 9 | self.init(statusCode: statusCode, message: "", headers: [:]) 10 | } 11 | 12 | public init(statusCode: Int, message: String, headers: [String: String]) { 13 | self.statusCode = statusCode 14 | self.message = message 15 | self.headers = headers 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /PocketNet/Net/PocketNet.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public typealias ResultNetworkResponse = Swift.Result 4 | 5 | public enum NetworkReachabilityStatus { 6 | case unknown 7 | case notReachable 8 | case reachable(ConnectionType) 9 | } 10 | 11 | public enum ConnectionType { 12 | case ethernetOrWiFi 13 | case wwan 14 | } 15 | 16 | public protocol PocketNet { 17 | var reachabilityListener: ((NetworkReachabilityStatus?) -> Void)? { get set } 18 | func launchRequest(_ request: NetRequest, completion: @escaping ((ResultNetworkResponse) -> Void)) -> Int 19 | func uploadRequest(_ request: NetRequest, archives: [FormData], jsonKey: String, actualProgress:@escaping ((Double) -> Void), completion: @escaping ((ResultNetworkResponse) -> Void)) -> Int 20 | func downloadRequest(_ request: NetRequest, actualProgress:@escaping ((Double) -> Void), completion: @escaping ((ResultNetworkResponse) -> Void)) -> Int 21 | func isReachable() -> Bool 22 | func setupCaching(_ size: Int) 23 | func removeCaching() 24 | func cancelTask(identifier: Int) 25 | func cancelAllTasks() 26 | } 27 | -------------------------------------------------------------------------------- /PocketNet/Net/PocketNetAlamoFire/CustomServerTrustPolicyManager.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | class CustomServerTrustPolicyManager: ServerTrustPolicyManager { 4 | 5 | override func serverTrustPolicy(forHost host: String) -> ServerTrustPolicy? { 6 | if let policy = super.serverTrustPolicy(forHost: host) { 7 | print(policy) 8 | return policy 9 | } else { 10 | return .customEvaluation({ (_, _) -> Bool in 11 | return false 12 | }) 13 | } 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /PocketNet/Net/PocketNetAlamoFire/CustomSessionDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | class CustomSessionDelegate: SessionDelegate { 4 | 5 | let resourceURL: URL 6 | 7 | init?(resourceURL: URL) { 8 | self.resourceURL = resourceURL 9 | super.init() 10 | sessionDidReceiveChallengeWithCompletion = { session, challenge, completion in 11 | guard let trust = challenge.protectionSpace.serverTrust, SecTrustGetCertificateCount(trust) > 0 else { 12 | completion(.cancelAuthenticationChallenge, nil) 13 | return 14 | } 15 | if let serverCertificate = SecTrustGetCertificateAtIndex(trust, 0), let serverCertificateKey = CustomSessionDelegate.publicKey(for: serverCertificate) { 16 | if CustomSessionDelegate.pinnedKeys(resourceURL: self.resourceURL).contains(serverCertificateKey) { 17 | completion(.useCredential, URLCredential(trust: trust)) 18 | return 19 | } 20 | } 21 | completion(.cancelAuthenticationChallenge, nil) 22 | } 23 | } 24 | 25 | private static func pinnedKeys(resourceURL: URL) -> [SecKey] { 26 | var publicKeys: [SecKey] = [] 27 | do { 28 | let pinnedCertificateData = try Data(contentsOf: resourceURL) as CFData 29 | if let pinnedCertificate = SecCertificateCreateWithData(nil, pinnedCertificateData), let key = publicKey(for: pinnedCertificate) { 30 | publicKeys.append(key) 31 | } 32 | } catch (_) {} 33 | return publicKeys 34 | } 35 | 36 | private static func publicKey(for certificate: SecCertificate) -> SecKey? { 37 | var publicKey: SecKey? 38 | let policy = SecPolicyCreateBasicX509() 39 | var trust: SecTrust? 40 | let trustCreationStatus = SecTrustCreateWithCertificates(certificate, policy, &trust) 41 | if let trust = trust, trustCreationStatus == errSecSuccess { 42 | publicKey = SecTrustCopyPublicKey(trust) 43 | } 44 | return publicKey 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /PocketNet/Net/PocketNetAlamoFire/PocketAlamofireAdapter.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class PocketAlamofireAdapter { 4 | 5 | public static func adaptRequest(_ request: NetRequest, manager: SessionManager, completion: @escaping ((ResultNetworkResponse) -> Void)) -> Int { 6 | let afResponse = manager.request( 7 | request.url, 8 | method: self.transformMethod(request.method), 9 | parameters: request.body.params, 10 | encoding: self.transformParameterEncoding(request.body.parameterEncoding), 11 | headers: request.headers).validate().responseString(encoding: .utf8) { afResponse in 12 | guard let responseString = afResponse.result.value, let headers = afResponse.response?.allHeaderFields, let statusCode = afResponse.response?.statusCode else { 13 | var bodyString: String? 14 | if let data = afResponse.data { 15 | bodyString = String(data: data, encoding: String.Encoding.utf8) 16 | } 17 | processErrorResponse(afResponse.error, statusCode: afResponse.response?.statusCode, responseHeaders: afResponse.response?.allHeaderFields, bodyString: bodyString, completion: completion) 18 | return 19 | } 20 | processSuccessResponseString(responseString != "" ? responseString : "{}", responseHeaders: headers, status: statusCode, completion: completion) 21 | } 22 | return (afResponse.task != nil) ? afResponse.task!.taskIdentifier : -1 23 | } 24 | 25 | public static func adaptUploadRequest(_ request: NetRequest, manager: SessionManager, archives: [FormData], jsonKey: String, actualProgress:@escaping ((Double) -> Void), completion: @escaping ((ResultNetworkResponse) -> Void)) -> Int { 26 | var uploadRequest: Request! 27 | var urlRequest: URLRequest! 28 | do { 29 | guard let url = URL(string: request.url) else { return -1 } 30 | urlRequest = try URLRequest(url: url, method: self.transformMethod(request.method), headers: request.headers) 31 | } catch { 32 | return -1 33 | } 34 | 35 | let group = DispatchGroup() 36 | group.enter() 37 | 38 | manager.upload(multipartFormData: { (multipartFormData) in 39 | for archive in archives { 40 | multipartFormData.append(archive.data, withName: archive.apiName, fileName: archive.fileName, mimeType: archive.mimeType) 41 | } 42 | let dataParameters = try! JSONSerialization.data(withJSONObject: request.body.params, options: JSONSerialization.WritingOptions(rawValue: 0)) 43 | multipartFormData.append(dataParameters, withName: jsonKey, mimeType: "application/json") 44 | }, with: urlRequest, encodingCompletion: { encodingResult in 45 | switch encodingResult { 46 | case .success(let upload, _, _): 47 | uploadRequest = upload 48 | group.leave() 49 | upload.uploadProgress(closure: { progress in 50 | actualProgress(progress.fractionCompleted) 51 | }) 52 | upload.validate().responseString(encoding: .utf8) { afResponse in 53 | guard let responseString = afResponse.result.value, let headers = afResponse.response?.allHeaderFields, let statusCode = afResponse.response?.statusCode else { 54 | var bodyString: String? 55 | if let data = afResponse.data { 56 | bodyString = String(data: data, encoding: String.Encoding.utf8) 57 | } 58 | processErrorResponse(afResponse.error, statusCode: afResponse.response?.statusCode, responseHeaders: afResponse.response?.allHeaderFields, bodyString: bodyString, completion: completion) 59 | return 60 | } 61 | processSuccessResponseString(responseString, responseHeaders: headers, status: statusCode, completion: completion) 62 | } 63 | case .failure: 64 | group.leave() 65 | completion(Swift.Result.failure(NetError.encodingError)) 66 | } 67 | }) 68 | group.wait() 69 | return (uploadRequest.task != nil) ? uploadRequest.task!.taskIdentifier : -1 70 | } 71 | 72 | public static func adaptDownloadRequest(_ request: NetRequest, manager: SessionManager, actualProgress:@escaping ((Double) -> Void), completion: @escaping ((ResultNetworkResponse) -> Void)) -> Int { 73 | var urlRequest: URLRequest! 74 | do { 75 | guard let url = URL(string: request.url) else { return -1 } 76 | urlRequest = try URLRequest(url: url, method: self.transformMethod(request.method), headers: request.headers) 77 | } catch { 78 | return -1 79 | } 80 | 81 | let downloadRequest = manager.download(urlRequest) 82 | .downloadProgress { progress in 83 | actualProgress(progress.fractionCompleted) 84 | } 85 | .validate().responseString(encoding: .utf8) { afResponse in 86 | guard let responseString = afResponse.result.value, let headers = afResponse.response?.allHeaderFields, let statusCode = afResponse.response?.statusCode else { 87 | var bodyString: String? 88 | if let data = afResponse.resumeData{ 89 | bodyString = String(data: data, encoding: String.Encoding.utf8) 90 | } 91 | processErrorResponse(afResponse.error, statusCode: afResponse.response?.statusCode, responseHeaders: afResponse.response?.allHeaderFields, bodyString: bodyString, completion: completion) 92 | return 93 | } 94 | processSuccessResponseString(responseString, responseHeaders: headers, status: statusCode, completion: completion) 95 | } 96 | return (downloadRequest.task != nil) ? downloadRequest.task!.taskIdentifier : -1 97 | } 98 | 99 | internal static func processSuccessResponseString(_ responseString: String, responseHeaders: [AnyHashable: Any], status: Int, completion: @escaping ((ResultNetworkResponse) -> Void)) { 100 | completion(Swift.Result.success(NetworkResponse(statusCode: status, message: responseString, headers: adaptHeaders(responseHeaders)))) 101 | } 102 | 103 | internal static func processErrorResponse(_ error: Error?, statusCode: Int?, responseHeaders: [AnyHashable : Any]?, bodyString: String?, completion: @escaping ((ResultNetworkResponse) -> Void)) { 104 | guard let error = error else { 105 | completion(Swift.Result.failure(NetError.error(statusErrorCode: -1, errorMessage: "Unknown error", errorStringObject: bodyString, headers: adaptHeaders(responseHeaders)))) 106 | return 107 | } 108 | switch error._code { 109 | case NSURLErrorNotConnectedToInternet: 110 | completion(Swift.Result.failure(NetError.noConnection)) 111 | default: 112 | completion(Swift.Result.failure(NetError.error(statusErrorCode: statusCode ?? error._code, errorMessage: error.localizedDescription, errorStringObject: bodyString, headers: adaptHeaders(responseHeaders)))) 113 | } 114 | } 115 | 116 | internal static func adaptHeaders(_ headers: [AnyHashable: Any]?) -> [String: String] { 117 | var adaptedHeaders = [String: String]() 118 | for (headerKey, headerValue) in headers ?? [:] { 119 | let key = headerKey as! String 120 | let value = headerValue as! String 121 | adaptedHeaders[key] = value 122 | } 123 | return adaptedHeaders 124 | } 125 | 126 | internal static func transformMethod(_ method: Method) -> HTTPMethod { 127 | switch method { 128 | case .delete: 129 | return HTTPMethod.delete 130 | case .get: 131 | return HTTPMethod.get 132 | case .head: 133 | return HTTPMethod.head 134 | case .options: 135 | return HTTPMethod.options 136 | case .patch: 137 | return HTTPMethod.patch 138 | case .post: 139 | return HTTPMethod.post 140 | case .put: 141 | return HTTPMethod.put 142 | case .trace: 143 | return HTTPMethod.trace 144 | case .connect: 145 | return HTTPMethod.connect 146 | } 147 | } 148 | 149 | internal static func transformParameterEncoding(_ parameterEncoding: PParameterEncoding) -> ParameterEncoding { 150 | switch parameterEncoding { 151 | case .url: 152 | return URLEncoding.default 153 | case .json: 154 | return JSONEncoding.default 155 | case .form: 156 | return URLEncoding.default 157 | } 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /PocketNet/Net/PocketNetAlamoFire/PocketNetAlamofire.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class PocketNetAlamofire: PocketNet { 4 | 5 | public var reachabilityListener: ((NetworkReachabilityStatus?) -> Void)? { 6 | didSet { 7 | self.reachabilityManager.stopListening() 8 | if let reachabilityListener = reachabilityListener { 9 | self.reachabilityManager.listener = { status in 10 | switch status { 11 | case .notReachable: 12 | reachabilityListener(.notReachable) 13 | case .unknown : 14 | reachabilityListener(.unknown) 15 | case .reachable(.ethernetOrWiFi): 16 | reachabilityListener(.reachable(.ethernetOrWiFi)) 17 | case .reachable(.wwan): 18 | reachabilityListener(.reachable(.wwan)) 19 | } 20 | } 21 | self.reachabilityManager.startListening() 22 | } else { 23 | self.reachabilityManager.listener = nil 24 | } 25 | } 26 | } 27 | 28 | let DF_CACHE_SIZE = 4 * 5 * 1024 * 1024 29 | let manager: SessionManager 30 | let reachabilityManager = NetworkReachabilityManager(host: "www.apple.com")! 31 | let sessionDelegate: SessionDelegate! 32 | 33 | public init(requestTimeout: TimeInterval = 20.0, pinningSSLCertURL: URL? = nil, domain: String? = nil, serverTrustPolicies: [String: ServerTrustPolicy] = [:]) { 34 | var configuration = URLSessionConfiguration.default 35 | #if DEBUG 36 | configuration = Reqres.defaultSessionConfiguration() 37 | configuration.httpAdditionalHeaders = SessionManager.defaultHTTPHeaders 38 | #endif 39 | if let certURL = pinningSSLCertURL, let dom = domain, let customSession = CustomSessionDelegate(resourceURL: certURL) { 40 | var serverTrustPolicies: [String: ServerTrustPolicy] = [ 41 | dom: .pinPublicKeys( 42 | publicKeys: ServerTrustPolicy.publicKeys(), 43 | validateCertificateChain: true, 44 | validateHost: true 45 | ) 46 | ] 47 | sessionDelegate = customSession 48 | Reqres.sessionDelegate = sessionDelegate 49 | serverTrustPolicies = serverTrustPolicies.merging(serverTrustPolicies, uniquingKeysWith: { (first, _) in first }) 50 | let policyManager = CustomServerTrustPolicyManager(policies: serverTrustPolicies) 51 | Reqres.policyManager = policyManager 52 | self.manager = SessionManager(configuration: configuration, delegate: customSession, serverTrustPolicyManager: policyManager) 53 | } else { 54 | sessionDelegate = SessionDelegate() 55 | Reqres.sessionDelegate = sessionDelegate 56 | let policyManager = ServerTrustPolicyManager(policies: serverTrustPolicies) 57 | Reqres.policyManager = policyManager 58 | self.manager = SessionManager(configuration: configuration, delegate: sessionDelegate, serverTrustPolicyManager: policyManager) 59 | } 60 | self.manager.session.configuration.timeoutIntervalForRequest = requestTimeout 61 | self.setupCaching(DF_CACHE_SIZE) 62 | } 63 | 64 | public func setupCaching(_ size: Int) { 65 | let URLCache = Foundation.URLCache(memoryCapacity: DF_CACHE_SIZE, diskCapacity: size, diskPath: nil) 66 | Foundation.URLCache.shared = URLCache 67 | } 68 | 69 | public func removeCaching() { 70 | self.manager.session.configuration.requestCachePolicy = .reloadIgnoringLocalCacheData 71 | Foundation.URLCache.shared = URLCache(memoryCapacity: 0, diskCapacity: 0, diskPath: nil) 72 | } 73 | 74 | public func launchRequest(_ request: NetRequest, completion: @escaping ((ResultNetworkResponse) -> Void)) -> Int { 75 | if !request.shouldCache { 76 | self.manager.session.configuration.requestCachePolicy = .reloadIgnoringLocalCacheData 77 | } else { 78 | self.manager.session.configuration.requestCachePolicy = .useProtocolCachePolicy 79 | } 80 | return PocketAlamofireAdapter.adaptRequest(request, manager: self.manager, completion: completion) 81 | } 82 | 83 | public func uploadRequest(_ request: NetRequest, archives: [FormData], jsonKey: String, actualProgress:@escaping ((Double) -> Void), completion: @escaping ((ResultNetworkResponse) -> Void)) -> Int { 84 | return PocketAlamofireAdapter.adaptUploadRequest(request, manager: self.manager, archives: archives, jsonKey: jsonKey, actualProgress: actualProgress, completion: completion) 85 | } 86 | 87 | public func downloadRequest(_ request: NetRequest, actualProgress:@escaping ((Double) -> Void), completion: @escaping ((ResultNetworkResponse) -> Void)) -> Int { 88 | return PocketAlamofireAdapter.adaptDownloadRequest(request, manager: self.manager, actualProgress: actualProgress, completion: completion) 89 | } 90 | 91 | public func cancelTask(identifier: Int) { 92 | self.manager.session.getTasksWithCompletionHandler { (sessionDataTask, uploadData, downloadData) in 93 | var completed = false 94 | sessionDataTask.forEach { 95 | if $0.taskIdentifier == identifier && $0.state == .running { 96 | $0.cancel() 97 | completed = true 98 | return 99 | } 100 | } 101 | if completed { return } 102 | downloadData.forEach { 103 | if $0.taskIdentifier == identifier && $0.state == .running { 104 | $0.cancel() 105 | completed = true 106 | return 107 | } 108 | } 109 | if completed { return } 110 | uploadData.forEach { 111 | if $0.taskIdentifier == identifier && $0.state == .running { 112 | $0.cancel() 113 | return 114 | } 115 | } 116 | } 117 | } 118 | 119 | public func cancelAllTasks() { 120 | self.manager.session.getTasksWithCompletionHandler { (sessionDataTask, uploadData, downloadData) in 121 | var completed = false 122 | sessionDataTask.forEach { 123 | if $0.state == .running { 124 | $0.cancel() 125 | completed = true 126 | return 127 | } 128 | } 129 | if completed { return } 130 | downloadData.forEach { 131 | if $0.state == .running { 132 | $0.cancel() 133 | completed = true 134 | return 135 | } 136 | } 137 | if completed { return } 138 | uploadData.forEach { 139 | if $0.state == .running { 140 | $0.cancel() 141 | return 142 | } 143 | } 144 | } 145 | } 146 | 147 | public func isReachable() -> Bool { 148 | return self.reachabilityManager.isReachable 149 | } 150 | 151 | } 152 | -------------------------------------------------------------------------------- /PocketNet/PocketNet.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | //! Project version number for PocketNet. 4 | FOUNDATION_EXPORT double PocketNetVersionNumber; 5 | 6 | //! Project version string for PocketNet. 7 | FOUNDATION_EXPORT const unsigned char PocketNetVersionString[]; 8 | 9 | // In this header, you should import all the public headers of your framework using statements like #import 10 | -------------------------------------------------------------------------------- /PocketNetTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /PocketNetTests/NetTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import PocketNet 3 | 4 | class PocketNetTests: XCTestCase { 5 | 6 | override func setUp() { 7 | super.setUp() 8 | // Put setup code here. This method is called before the invocation of each test method in the class. 9 | } 10 | 11 | override func tearDown() { 12 | // Put teardown code here. This method is called after the invocation of each test method in the class. 13 | super.tearDown() 14 | } 15 | 16 | func testExample() { 17 | // This is an example of a functional test case. 18 | // Use XCTAssert and related functions to verify your tests produce the correct results. 19 | } 20 | 21 | func testPerformanceExample() { 22 | // This is an example of a performance test case. 23 | self.measure { 24 | // Put the code you want to measure the time of here. 25 | } 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /PocketNet_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PocketSwift/PocketNet/82fd3492fb84d4567352de73f3a1bb401f6b8239/PocketNet_logo.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 |

3 | PocketNet
4 |

5 | 6 | [![CocoaPods Compatible](https://img.shields.io/cocoapods/v/PocketNet.svg)](https://img.shields.io/cocoapods/v/PocketNet.svg) 7 | [![License](https://img.shields.io/cocoapods/l/PocketNet.svg?style=flat)](http://cocoapods.org/pods/PocketNet) 8 | 9 | ## PocketNet 10 | 11 | Elegant net abstraction layer written in Swift 5.0, we provide an integration with Alamofire. 12 | 13 | ## Requirements 14 | 15 | - iOS 8.0+ 16 | 17 | ## Installation 18 | 19 | ### CocoaPods 20 | 21 | [CocoaPods](http://cocoapods.org) is a dependency manager for Cocoa projects. You can install it with the following command: 22 | 23 | ```bash 24 | $ gem install cocoapods 25 | ``` 26 | 27 | > CocoaPods 1.1+ is required to build PocketNet 2.4.0 28 | 29 | To integrate PocketNet into your Xcode project using CocoaPods, specify it in your `Podfile`: 30 | 31 | ```ruby 32 | source 'https://github.com/CocoaPods/Specs.git' 33 | platform :ios, '8.0' 34 | use_frameworks! 35 | 36 | target '' do 37 | pod 'PocketNet' 38 | end 39 | ``` 40 | 41 | Then, run the following command: 42 | 43 | ```bash 44 | $ pod install 45 | ``` 46 | 47 | ## Usage 48 | 49 | ```swift 50 | import PocketNet 51 | 52 | let net: PocketNet = PocketNetAlamofire() /*or for SSL Pinning*/ PocketNetAlamofire(pinningSSLCertURL: Bundle.main.url(forResource: "cert", withExtension: "crt"), domain: "urlDomain") 53 | 54 | let netSupport = NetSupport(net: net) 55 | 56 | let request = NetRequest.Builder() 57 | .method(.post) 58 | .url("url") 59 | .requestHeader([:]) 60 | .parameterEncoding(.json) 61 | .body(params: "") 62 | .shouldCache(false) 63 | .build() 64 | 65 | netSupport.netJsonMappableRequest(request, completion: {(result: Result) in 66 | switch result { 67 | case .success(let decodableObject): 68 | /// do something with decodableObject 69 | case .failure(let error): 70 | /// do something with error 71 | } 72 | }) 73 | 74 | netSupport.netArrayJsonMappableRequest(request, completion: {(result: Result<[DecodableObject], Error>) in 75 | switch result { 76 | case .success(let decodableObject): 77 | /// do something with decodableObject 78 | case .failure(let error): 79 | /// do something with error 80 | } 81 | }) 82 | 83 | ``` 84 | 85 | ## Authors 86 | 87 | * [Jose Antonio Garcia](https://github.com/joseantoniogarciay), joseantoniogarciay@gmail.com 88 | * [Omar Megdadi](https://github.com/NSStudent), omarmn83@gmail.com 89 | 90 | ## Special thanks 91 | 92 | * [Alex Rupérez](https://github.com/alexruperez), contact@alexruperez.com 93 | * [Carlos Manzanas](https://github.com/IGZCarlosManzanas) 94 | * [Roberto Estrada Casarrubios](https://github.com/RobertoEstrada) 95 | 96 | ## Libraries used in this project 97 | 98 | * [Alamofire][1] 99 | * [Reqres][2] 100 | 101 | 102 | ## License 103 | 104 | Net is available under the MIT license. See the LICENSE file for more info. 105 | 106 | 107 | [1]: https://github.com/Alamofire/Alamofire 108 | [2]: https://github.com/AckeeCZ/Reqres 109 | -------------------------------------------------------------------------------- /StaticPods/Alamofire 4.8.1/AlamofireLicense/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /StaticPods/Alamofire 4.8.1/Source/AFError.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AFError.swift 3 | // 4 | // Copyright (c) 2014 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 | 25 | import Foundation 26 | 27 | /// `AFError` is the error type returned by Alamofire. It encompasses a few different types of errors, each with 28 | /// their own associated reasons. 29 | /// 30 | /// - invalidURL: Returned when a `URLConvertible` type fails to create a valid `URL`. 31 | /// - parameterEncodingFailed: Returned when a parameter encoding object throws an error during the encoding process. 32 | /// - multipartEncodingFailed: Returned when some step in the multipart encoding process fails. 33 | /// - responseValidationFailed: Returned when a `validate()` call fails. 34 | /// - responseSerializationFailed: Returned when a response serializer encounters an error in the serialization process. 35 | public enum AFError: Error { 36 | /// The underlying reason the parameter encoding error occurred. 37 | /// 38 | /// - missingURL: The URL request did not have a URL to encode. 39 | /// - jsonEncodingFailed: JSON serialization failed with an underlying system error during the 40 | /// encoding process. 41 | /// - propertyListEncodingFailed: Property list serialization failed with an underlying system error during 42 | /// encoding process. 43 | public enum ParameterEncodingFailureReason { 44 | case missingURL 45 | case jsonEncodingFailed(error: Error) 46 | case propertyListEncodingFailed(error: Error) 47 | } 48 | 49 | /// The underlying reason the multipart encoding error occurred. 50 | /// 51 | /// - bodyPartURLInvalid: The `fileURL` provided for reading an encodable body part isn't a 52 | /// file URL. 53 | /// - bodyPartFilenameInvalid: The filename of the `fileURL` provided has either an empty 54 | /// `lastPathComponent` or `pathExtension. 55 | /// - bodyPartFileNotReachable: The file at the `fileURL` provided was not reachable. 56 | /// - bodyPartFileNotReachableWithError: Attempting to check the reachability of the `fileURL` provided threw 57 | /// an error. 58 | /// - bodyPartFileIsDirectory: The file at the `fileURL` provided is actually a directory. 59 | /// - bodyPartFileSizeNotAvailable: The size of the file at the `fileURL` provided was not returned by 60 | /// the system. 61 | /// - bodyPartFileSizeQueryFailedWithError: The attempt to find the size of the file at the `fileURL` provided 62 | /// threw an error. 63 | /// - bodyPartInputStreamCreationFailed: An `InputStream` could not be created for the provided `fileURL`. 64 | /// - outputStreamCreationFailed: An `OutputStream` could not be created when attempting to write the 65 | /// encoded data to disk. 66 | /// - outputStreamFileAlreadyExists: The encoded body data could not be writtent disk because a file 67 | /// already exists at the provided `fileURL`. 68 | /// - outputStreamURLInvalid: The `fileURL` provided for writing the encoded body data to disk is 69 | /// not a file URL. 70 | /// - outputStreamWriteFailed: The attempt to write the encoded body data to disk failed with an 71 | /// underlying error. 72 | /// - inputStreamReadFailed: The attempt to read an encoded body part `InputStream` failed with 73 | /// underlying system error. 74 | public enum MultipartEncodingFailureReason { 75 | case bodyPartURLInvalid(url: URL) 76 | case bodyPartFilenameInvalid(in: URL) 77 | case bodyPartFileNotReachable(at: URL) 78 | case bodyPartFileNotReachableWithError(atURL: URL, error: Error) 79 | case bodyPartFileIsDirectory(at: URL) 80 | case bodyPartFileSizeNotAvailable(at: URL) 81 | case bodyPartFileSizeQueryFailedWithError(forURL: URL, error: Error) 82 | case bodyPartInputStreamCreationFailed(for: URL) 83 | 84 | case outputStreamCreationFailed(for: URL) 85 | case outputStreamFileAlreadyExists(at: URL) 86 | case outputStreamURLInvalid(url: URL) 87 | case outputStreamWriteFailed(error: Error) 88 | 89 | case inputStreamReadFailed(error: Error) 90 | } 91 | 92 | /// The underlying reason the response validation error occurred. 93 | /// 94 | /// - dataFileNil: The data file containing the server response did not exist. 95 | /// - dataFileReadFailed: The data file containing the server response could not be read. 96 | /// - missingContentType: The response did not contain a `Content-Type` and the `acceptableContentTypes` 97 | /// provided did not contain wildcard type. 98 | /// - unacceptableContentType: The response `Content-Type` did not match any type in the provided 99 | /// `acceptableContentTypes`. 100 | /// - unacceptableStatusCode: The response status code was not acceptable. 101 | public enum ResponseValidationFailureReason { 102 | case dataFileNil 103 | case dataFileReadFailed(at: URL) 104 | case missingContentType(acceptableContentTypes: [String]) 105 | case unacceptableContentType(acceptableContentTypes: [String], responseContentType: String) 106 | case unacceptableStatusCode(code: Int) 107 | } 108 | 109 | /// The underlying reason the response serialization error occurred. 110 | /// 111 | /// - inputDataNil: The server response contained no data. 112 | /// - inputDataNilOrZeroLength: The server response contained no data or the data was zero length. 113 | /// - inputFileNil: The file containing the server response did not exist. 114 | /// - inputFileReadFailed: The file containing the server response could not be read. 115 | /// - stringSerializationFailed: String serialization failed using the provided `String.Encoding`. 116 | /// - jsonSerializationFailed: JSON serialization failed with an underlying system error. 117 | /// - propertyListSerializationFailed: Property list serialization failed with an underlying system error. 118 | public enum ResponseSerializationFailureReason { 119 | case inputDataNil 120 | case inputDataNilOrZeroLength 121 | case inputFileNil 122 | case inputFileReadFailed(at: URL) 123 | case stringSerializationFailed(encoding: String.Encoding) 124 | case jsonSerializationFailed(error: Error) 125 | case propertyListSerializationFailed(error: Error) 126 | } 127 | 128 | case invalidURL(url: URLConvertible) 129 | case parameterEncodingFailed(reason: ParameterEncodingFailureReason) 130 | case multipartEncodingFailed(reason: MultipartEncodingFailureReason) 131 | case responseValidationFailed(reason: ResponseValidationFailureReason) 132 | case responseSerializationFailed(reason: ResponseSerializationFailureReason) 133 | } 134 | 135 | // MARK: - Adapt Error 136 | 137 | struct AdaptError: Error { 138 | let error: Error 139 | } 140 | 141 | extension Error { 142 | var underlyingAdaptError: Error? { return (self as? AdaptError)?.error } 143 | } 144 | 145 | // MARK: - Error Booleans 146 | 147 | extension AFError { 148 | /// Returns whether the AFError is an invalid URL error. 149 | public var isInvalidURLError: Bool { 150 | if case .invalidURL = self { return true } 151 | return false 152 | } 153 | 154 | /// Returns whether the AFError is a parameter encoding error. When `true`, the `underlyingError` property will 155 | /// contain the associated value. 156 | public var isParameterEncodingError: Bool { 157 | if case .parameterEncodingFailed = self { return true } 158 | return false 159 | } 160 | 161 | /// Returns whether the AFError is a multipart encoding error. When `true`, the `url` and `underlyingError` properties 162 | /// will contain the associated values. 163 | public var isMultipartEncodingError: Bool { 164 | if case .multipartEncodingFailed = self { return true } 165 | return false 166 | } 167 | 168 | /// Returns whether the `AFError` is a response validation error. When `true`, the `acceptableContentTypes`, 169 | /// `responseContentType`, and `responseCode` properties will contain the associated values. 170 | public var isResponseValidationError: Bool { 171 | if case .responseValidationFailed = self { return true } 172 | return false 173 | } 174 | 175 | /// Returns whether the `AFError` is a response serialization error. When `true`, the `failedStringEncoding` and 176 | /// `underlyingError` properties will contain the associated values. 177 | public var isResponseSerializationError: Bool { 178 | if case .responseSerializationFailed = self { return true } 179 | return false 180 | } 181 | } 182 | 183 | // MARK: - Convenience Properties 184 | 185 | extension AFError { 186 | /// The `URLConvertible` associated with the error. 187 | public var urlConvertible: URLConvertible? { 188 | switch self { 189 | case .invalidURL(let url): 190 | return url 191 | default: 192 | return nil 193 | } 194 | } 195 | 196 | /// The `URL` associated with the error. 197 | public var url: URL? { 198 | switch self { 199 | case .multipartEncodingFailed(let reason): 200 | return reason.url 201 | default: 202 | return nil 203 | } 204 | } 205 | 206 | /// The `Error` returned by a system framework associated with a `.parameterEncodingFailed`, 207 | /// `.multipartEncodingFailed` or `.responseSerializationFailed` error. 208 | public var underlyingError: Error? { 209 | switch self { 210 | case .parameterEncodingFailed(let reason): 211 | return reason.underlyingError 212 | case .multipartEncodingFailed(let reason): 213 | return reason.underlyingError 214 | case .responseSerializationFailed(let reason): 215 | return reason.underlyingError 216 | default: 217 | return nil 218 | } 219 | } 220 | 221 | /// The acceptable `Content-Type`s of a `.responseValidationFailed` error. 222 | public var acceptableContentTypes: [String]? { 223 | switch self { 224 | case .responseValidationFailed(let reason): 225 | return reason.acceptableContentTypes 226 | default: 227 | return nil 228 | } 229 | } 230 | 231 | /// The response `Content-Type` of a `.responseValidationFailed` error. 232 | public var responseContentType: String? { 233 | switch self { 234 | case .responseValidationFailed(let reason): 235 | return reason.responseContentType 236 | default: 237 | return nil 238 | } 239 | } 240 | 241 | /// The response code of a `.responseValidationFailed` error. 242 | public var responseCode: Int? { 243 | switch self { 244 | case .responseValidationFailed(let reason): 245 | return reason.responseCode 246 | default: 247 | return nil 248 | } 249 | } 250 | 251 | /// The `String.Encoding` associated with a failed `.stringResponse()` call. 252 | public var failedStringEncoding: String.Encoding? { 253 | switch self { 254 | case .responseSerializationFailed(let reason): 255 | return reason.failedStringEncoding 256 | default: 257 | return nil 258 | } 259 | } 260 | } 261 | 262 | extension AFError.ParameterEncodingFailureReason { 263 | var underlyingError: Error? { 264 | switch self { 265 | case .jsonEncodingFailed(let error), .propertyListEncodingFailed(let error): 266 | return error 267 | default: 268 | return nil 269 | } 270 | } 271 | } 272 | 273 | extension AFError.MultipartEncodingFailureReason { 274 | var url: URL? { 275 | switch self { 276 | case .bodyPartURLInvalid(let url), .bodyPartFilenameInvalid(let url), .bodyPartFileNotReachable(let url), 277 | .bodyPartFileIsDirectory(let url), .bodyPartFileSizeNotAvailable(let url), 278 | .bodyPartInputStreamCreationFailed(let url), .outputStreamCreationFailed(let url), 279 | .outputStreamFileAlreadyExists(let url), .outputStreamURLInvalid(let url), 280 | .bodyPartFileNotReachableWithError(let url, _), .bodyPartFileSizeQueryFailedWithError(let url, _): 281 | return url 282 | default: 283 | return nil 284 | } 285 | } 286 | 287 | var underlyingError: Error? { 288 | switch self { 289 | case .bodyPartFileNotReachableWithError(_, let error), .bodyPartFileSizeQueryFailedWithError(_, let error), 290 | .outputStreamWriteFailed(let error), .inputStreamReadFailed(let error): 291 | return error 292 | default: 293 | return nil 294 | } 295 | } 296 | } 297 | 298 | extension AFError.ResponseValidationFailureReason { 299 | var acceptableContentTypes: [String]? { 300 | switch self { 301 | case .missingContentType(let types), .unacceptableContentType(let types, _): 302 | return types 303 | default: 304 | return nil 305 | } 306 | } 307 | 308 | var responseContentType: String? { 309 | switch self { 310 | case .unacceptableContentType(_, let responseType): 311 | return responseType 312 | default: 313 | return nil 314 | } 315 | } 316 | 317 | var responseCode: Int? { 318 | switch self { 319 | case .unacceptableStatusCode(let code): 320 | return code 321 | default: 322 | return nil 323 | } 324 | } 325 | } 326 | 327 | extension AFError.ResponseSerializationFailureReason { 328 | var failedStringEncoding: String.Encoding? { 329 | switch self { 330 | case .stringSerializationFailed(let encoding): 331 | return encoding 332 | default: 333 | return nil 334 | } 335 | } 336 | 337 | var underlyingError: Error? { 338 | switch self { 339 | case .jsonSerializationFailed(let error), .propertyListSerializationFailed(let error): 340 | return error 341 | default: 342 | return nil 343 | } 344 | } 345 | } 346 | 347 | // MARK: - Error Descriptions 348 | 349 | extension AFError: LocalizedError { 350 | public var errorDescription: String? { 351 | switch self { 352 | case .invalidURL(let url): 353 | return "URL is not valid: \(url)" 354 | case .parameterEncodingFailed(let reason): 355 | return reason.localizedDescription 356 | case .multipartEncodingFailed(let reason): 357 | return reason.localizedDescription 358 | case .responseValidationFailed(let reason): 359 | return reason.localizedDescription 360 | case .responseSerializationFailed(let reason): 361 | return reason.localizedDescription 362 | } 363 | } 364 | } 365 | 366 | extension AFError.ParameterEncodingFailureReason { 367 | var localizedDescription: String { 368 | switch self { 369 | case .missingURL: 370 | return "URL request to encode was missing a URL" 371 | case .jsonEncodingFailed(let error): 372 | return "JSON could not be encoded because of error:\n\(error.localizedDescription)" 373 | case .propertyListEncodingFailed(let error): 374 | return "PropertyList could not be encoded because of error:\n\(error.localizedDescription)" 375 | } 376 | } 377 | } 378 | 379 | extension AFError.MultipartEncodingFailureReason { 380 | var localizedDescription: String { 381 | switch self { 382 | case .bodyPartURLInvalid(let url): 383 | return "The URL provided is not a file URL: \(url)" 384 | case .bodyPartFilenameInvalid(let url): 385 | return "The URL provided does not have a valid filename: \(url)" 386 | case .bodyPartFileNotReachable(let url): 387 | return "The URL provided is not reachable: \(url)" 388 | case .bodyPartFileNotReachableWithError(let url, let error): 389 | return ( 390 | "The system returned an error while checking the provided URL for " + 391 | "reachability.\nURL: \(url)\nError: \(error)" 392 | ) 393 | case .bodyPartFileIsDirectory(let url): 394 | return "The URL provided is a directory: \(url)" 395 | case .bodyPartFileSizeNotAvailable(let url): 396 | return "Could not fetch the file size from the provided URL: \(url)" 397 | case .bodyPartFileSizeQueryFailedWithError(let url, let error): 398 | return ( 399 | "The system returned an error while attempting to fetch the file size from the " + 400 | "provided URL.\nURL: \(url)\nError: \(error)" 401 | ) 402 | case .bodyPartInputStreamCreationFailed(let url): 403 | return "Failed to create an InputStream for the provided URL: \(url)" 404 | case .outputStreamCreationFailed(let url): 405 | return "Failed to create an OutputStream for URL: \(url)" 406 | case .outputStreamFileAlreadyExists(let url): 407 | return "A file already exists at the provided URL: \(url)" 408 | case .outputStreamURLInvalid(let url): 409 | return "The provided OutputStream URL is invalid: \(url)" 410 | case .outputStreamWriteFailed(let error): 411 | return "OutputStream write failed with error: \(error)" 412 | case .inputStreamReadFailed(let error): 413 | return "InputStream read failed with error: \(error)" 414 | } 415 | } 416 | } 417 | 418 | extension AFError.ResponseSerializationFailureReason { 419 | var localizedDescription: String { 420 | switch self { 421 | case .inputDataNil: 422 | return "Response could not be serialized, input data was nil." 423 | case .inputDataNilOrZeroLength: 424 | return "Response could not be serialized, input data was nil or zero length." 425 | case .inputFileNil: 426 | return "Response could not be serialized, input file was nil." 427 | case .inputFileReadFailed(let url): 428 | return "Response could not be serialized, input file could not be read: \(url)." 429 | case .stringSerializationFailed(let encoding): 430 | return "String could not be serialized with encoding: \(encoding)." 431 | case .jsonSerializationFailed(let error): 432 | return "JSON could not be serialized because of error:\n\(error.localizedDescription)" 433 | case .propertyListSerializationFailed(let error): 434 | return "PropertyList could not be serialized because of error:\n\(error.localizedDescription)" 435 | } 436 | } 437 | } 438 | 439 | extension AFError.ResponseValidationFailureReason { 440 | var localizedDescription: String { 441 | switch self { 442 | case .dataFileNil: 443 | return "Response could not be validated, data file was nil." 444 | case .dataFileReadFailed(let url): 445 | return "Response could not be validated, data file could not be read: \(url)." 446 | case .missingContentType(let types): 447 | return ( 448 | "Response Content-Type was missing and acceptable content types " + 449 | "(\(types.joined(separator: ","))) do not match \"*/*\"." 450 | ) 451 | case .unacceptableContentType(let acceptableTypes, let responseType): 452 | return ( 453 | "Response Content-Type \"\(responseType)\" does not match any acceptable types: " + 454 | "\(acceptableTypes.joined(separator: ","))." 455 | ) 456 | case .unacceptableStatusCode(let code): 457 | return "Response status code was unacceptable: \(code)." 458 | } 459 | } 460 | } 461 | -------------------------------------------------------------------------------- /StaticPods/Alamofire 4.8.1/Source/Alamofire.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Alamofire.swift 3 | // 4 | // Copyright (c) 2014 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 | 25 | import Foundation 26 | 27 | /// Types adopting the `URLConvertible` protocol can be used to construct URLs, which are then used to construct 28 | /// URL requests. 29 | public protocol URLConvertible { 30 | /// Returns a URL that conforms to RFC 2396 or throws an `Error`. 31 | /// 32 | /// - throws: An `Error` if the type cannot be converted to a `URL`. 33 | /// 34 | /// - returns: A URL or throws an `Error`. 35 | func asURL() throws -> URL 36 | } 37 | 38 | extension String: URLConvertible { 39 | /// Returns a URL if `self` represents a valid URL string that conforms to RFC 2396 or throws an `AFError`. 40 | /// 41 | /// - throws: An `AFError.invalidURL` if `self` is not a valid URL string. 42 | /// 43 | /// - returns: A URL or throws an `AFError`. 44 | public func asURL() throws -> URL { 45 | guard let url = URL(string: self) else { throw AFError.invalidURL(url: self) } 46 | return url 47 | } 48 | } 49 | 50 | extension URL: URLConvertible { 51 | /// Returns self. 52 | public func asURL() throws -> URL { return self } 53 | } 54 | 55 | extension URLComponents: URLConvertible { 56 | /// Returns a URL if `url` is not nil, otherwise throws an `Error`. 57 | /// 58 | /// - throws: An `AFError.invalidURL` if `url` is `nil`. 59 | /// 60 | /// - returns: A URL or throws an `AFError`. 61 | public func asURL() throws -> URL { 62 | guard let url = url else { throw AFError.invalidURL(url: self) } 63 | return url 64 | } 65 | } 66 | 67 | // MARK: - 68 | 69 | /// Types adopting the `URLRequestConvertible` protocol can be used to construct URL requests. 70 | public protocol URLRequestConvertible { 71 | /// Returns a URL request or throws if an `Error` was encountered. 72 | /// 73 | /// - throws: An `Error` if the underlying `URLRequest` is `nil`. 74 | /// 75 | /// - returns: A URL request. 76 | func asURLRequest() throws -> URLRequest 77 | } 78 | 79 | extension URLRequestConvertible { 80 | /// The URL request. 81 | public var urlRequest: URLRequest? { return try? asURLRequest() } 82 | } 83 | 84 | extension URLRequest: URLRequestConvertible { 85 | /// Returns a URL request or throws if an `Error` was encountered. 86 | public func asURLRequest() throws -> URLRequest { return self } 87 | } 88 | 89 | // MARK: - 90 | 91 | extension URLRequest { 92 | /// Creates an instance with the specified `method`, `urlString` and `headers`. 93 | /// 94 | /// - parameter url: The URL. 95 | /// - parameter method: The HTTP method. 96 | /// - parameter headers: The HTTP headers. `nil` by default. 97 | /// 98 | /// - returns: The new `URLRequest` instance. 99 | public init(url: URLConvertible, method: HTTPMethod, headers: HTTPHeaders? = nil) throws { 100 | let url = try url.asURL() 101 | 102 | self.init(url: url) 103 | 104 | httpMethod = method.rawValue 105 | 106 | if let headers = headers { 107 | for (headerField, headerValue) in headers { 108 | setValue(headerValue, forHTTPHeaderField: headerField) 109 | } 110 | } 111 | } 112 | 113 | func adapt(using adapter: RequestAdapter?) throws -> URLRequest { 114 | guard let adapter = adapter else { return self } 115 | return try adapter.adapt(self) 116 | } 117 | } 118 | 119 | // MARK: - Data Request 120 | 121 | /// Creates a `DataRequest` using the default `SessionManager` to retrieve the contents of the specified `url`, 122 | /// `method`, `parameters`, `encoding` and `headers`. 123 | /// 124 | /// - parameter url: The URL. 125 | /// - parameter method: The HTTP method. `.get` by default. 126 | /// - parameter parameters: The parameters. `nil` by default. 127 | /// - parameter encoding: The parameter encoding. `URLEncoding.default` by default. 128 | /// - parameter headers: The HTTP headers. `nil` by default. 129 | /// 130 | /// - returns: The created `DataRequest`. 131 | @discardableResult 132 | public func request( 133 | _ url: URLConvertible, 134 | method: HTTPMethod = .get, 135 | parameters: Parameters? = nil, 136 | encoding: ParameterEncoding = URLEncoding.default, 137 | headers: HTTPHeaders? = nil) 138 | -> DataRequest 139 | { 140 | return SessionManager.default.request( 141 | url, 142 | method: method, 143 | parameters: parameters, 144 | encoding: encoding, 145 | headers: headers 146 | ) 147 | } 148 | 149 | /// Creates a `DataRequest` using the default `SessionManager` to retrieve the contents of a URL based on the 150 | /// specified `urlRequest`. 151 | /// 152 | /// - parameter urlRequest: The URL request 153 | /// 154 | /// - returns: The created `DataRequest`. 155 | @discardableResult 156 | public func request(_ urlRequest: URLRequestConvertible) -> DataRequest { 157 | return SessionManager.default.request(urlRequest) 158 | } 159 | 160 | // MARK: - Download Request 161 | 162 | // MARK: URL Request 163 | 164 | /// Creates a `DownloadRequest` using the default `SessionManager` to retrieve the contents of the specified `url`, 165 | /// `method`, `parameters`, `encoding`, `headers` and save them to the `destination`. 166 | /// 167 | /// If `destination` is not specified, the contents will remain in the temporary location determined by the 168 | /// underlying URL session. 169 | /// 170 | /// - parameter url: The URL. 171 | /// - parameter method: The HTTP method. `.get` by default. 172 | /// - parameter parameters: The parameters. `nil` by default. 173 | /// - parameter encoding: The parameter encoding. `URLEncoding.default` by default. 174 | /// - parameter headers: The HTTP headers. `nil` by default. 175 | /// - parameter destination: The closure used to determine the destination of the downloaded file. `nil` by default. 176 | /// 177 | /// - returns: The created `DownloadRequest`. 178 | @discardableResult 179 | public func download( 180 | _ url: URLConvertible, 181 | method: HTTPMethod = .get, 182 | parameters: Parameters? = nil, 183 | encoding: ParameterEncoding = URLEncoding.default, 184 | headers: HTTPHeaders? = nil, 185 | to destination: DownloadRequest.DownloadFileDestination? = nil) 186 | -> DownloadRequest 187 | { 188 | return SessionManager.default.download( 189 | url, 190 | method: method, 191 | parameters: parameters, 192 | encoding: encoding, 193 | headers: headers, 194 | to: destination 195 | ) 196 | } 197 | 198 | /// Creates a `DownloadRequest` using the default `SessionManager` to retrieve the contents of a URL based on the 199 | /// specified `urlRequest` and save them to the `destination`. 200 | /// 201 | /// If `destination` is not specified, the contents will remain in the temporary location determined by the 202 | /// underlying URL session. 203 | /// 204 | /// - parameter urlRequest: The URL request. 205 | /// - parameter destination: The closure used to determine the destination of the downloaded file. `nil` by default. 206 | /// 207 | /// - returns: The created `DownloadRequest`. 208 | @discardableResult 209 | public func download( 210 | _ urlRequest: URLRequestConvertible, 211 | to destination: DownloadRequest.DownloadFileDestination? = nil) 212 | -> DownloadRequest 213 | { 214 | return SessionManager.default.download(urlRequest, to: destination) 215 | } 216 | 217 | // MARK: Resume Data 218 | 219 | /// Creates a `DownloadRequest` using the default `SessionManager` from the `resumeData` produced from a 220 | /// previous request cancellation to retrieve the contents of the original request and save them to the `destination`. 221 | /// 222 | /// If `destination` is not specified, the contents will remain in the temporary location determined by the 223 | /// underlying URL session. 224 | /// 225 | /// On the latest release of all the Apple platforms (iOS 10, macOS 10.12, tvOS 10, watchOS 3), `resumeData` is broken 226 | /// on background URL session configurations. There's an underlying bug in the `resumeData` generation logic where the 227 | /// data is written incorrectly and will always fail to resume the download. For more information about the bug and 228 | /// possible workarounds, please refer to the following Stack Overflow post: 229 | /// 230 | /// - http://stackoverflow.com/a/39347461/1342462 231 | /// 232 | /// - parameter resumeData: The resume data. This is an opaque data blob produced by `URLSessionDownloadTask` 233 | /// when a task is cancelled. See `URLSession -downloadTask(withResumeData:)` for additional 234 | /// information. 235 | /// - parameter destination: The closure used to determine the destination of the downloaded file. `nil` by default. 236 | /// 237 | /// - returns: The created `DownloadRequest`. 238 | @discardableResult 239 | public func download( 240 | resumingWith resumeData: Data, 241 | to destination: DownloadRequest.DownloadFileDestination? = nil) 242 | -> DownloadRequest 243 | { 244 | return SessionManager.default.download(resumingWith: resumeData, to: destination) 245 | } 246 | 247 | // MARK: - Upload Request 248 | 249 | // MARK: File 250 | 251 | /// Creates an `UploadRequest` using the default `SessionManager` from the specified `url`, `method` and `headers` 252 | /// for uploading the `file`. 253 | /// 254 | /// - parameter file: The file to upload. 255 | /// - parameter url: The URL. 256 | /// - parameter method: The HTTP method. `.post` by default. 257 | /// - parameter headers: The HTTP headers. `nil` by default. 258 | /// 259 | /// - returns: The created `UploadRequest`. 260 | @discardableResult 261 | public func upload( 262 | _ fileURL: URL, 263 | to url: URLConvertible, 264 | method: HTTPMethod = .post, 265 | headers: HTTPHeaders? = nil) 266 | -> UploadRequest 267 | { 268 | return SessionManager.default.upload(fileURL, to: url, method: method, headers: headers) 269 | } 270 | 271 | /// Creates a `UploadRequest` using the default `SessionManager` from the specified `urlRequest` for 272 | /// uploading the `file`. 273 | /// 274 | /// - parameter file: The file to upload. 275 | /// - parameter urlRequest: The URL request. 276 | /// 277 | /// - returns: The created `UploadRequest`. 278 | @discardableResult 279 | public func upload(_ fileURL: URL, with urlRequest: URLRequestConvertible) -> UploadRequest { 280 | return SessionManager.default.upload(fileURL, with: urlRequest) 281 | } 282 | 283 | // MARK: Data 284 | 285 | /// Creates an `UploadRequest` using the default `SessionManager` from the specified `url`, `method` and `headers` 286 | /// for uploading the `data`. 287 | /// 288 | /// - parameter data: The data to upload. 289 | /// - parameter url: The URL. 290 | /// - parameter method: The HTTP method. `.post` by default. 291 | /// - parameter headers: The HTTP headers. `nil` by default. 292 | /// 293 | /// - returns: The created `UploadRequest`. 294 | @discardableResult 295 | public func upload( 296 | _ data: Data, 297 | to url: URLConvertible, 298 | method: HTTPMethod = .post, 299 | headers: HTTPHeaders? = nil) 300 | -> UploadRequest 301 | { 302 | return SessionManager.default.upload(data, to: url, method: method, headers: headers) 303 | } 304 | 305 | /// Creates an `UploadRequest` using the default `SessionManager` from the specified `urlRequest` for 306 | /// uploading the `data`. 307 | /// 308 | /// - parameter data: The data to upload. 309 | /// - parameter urlRequest: The URL request. 310 | /// 311 | /// - returns: The created `UploadRequest`. 312 | @discardableResult 313 | public func upload(_ data: Data, with urlRequest: URLRequestConvertible) -> UploadRequest { 314 | return SessionManager.default.upload(data, with: urlRequest) 315 | } 316 | 317 | // MARK: InputStream 318 | 319 | /// Creates an `UploadRequest` using the default `SessionManager` from the specified `url`, `method` and `headers` 320 | /// for uploading the `stream`. 321 | /// 322 | /// - parameter stream: The stream to upload. 323 | /// - parameter url: The URL. 324 | /// - parameter method: The HTTP method. `.post` by default. 325 | /// - parameter headers: The HTTP headers. `nil` by default. 326 | /// 327 | /// - returns: The created `UploadRequest`. 328 | @discardableResult 329 | public func upload( 330 | _ stream: InputStream, 331 | to url: URLConvertible, 332 | method: HTTPMethod = .post, 333 | headers: HTTPHeaders? = nil) 334 | -> UploadRequest 335 | { 336 | return SessionManager.default.upload(stream, to: url, method: method, headers: headers) 337 | } 338 | 339 | /// Creates an `UploadRequest` using the default `SessionManager` from the specified `urlRequest` for 340 | /// uploading the `stream`. 341 | /// 342 | /// - parameter urlRequest: The URL request. 343 | /// - parameter stream: The stream to upload. 344 | /// 345 | /// - returns: The created `UploadRequest`. 346 | @discardableResult 347 | public func upload(_ stream: InputStream, with urlRequest: URLRequestConvertible) -> UploadRequest { 348 | return SessionManager.default.upload(stream, with: urlRequest) 349 | } 350 | 351 | // MARK: MultipartFormData 352 | 353 | /// Encodes `multipartFormData` using `encodingMemoryThreshold` with the default `SessionManager` and calls 354 | /// `encodingCompletion` with new `UploadRequest` using the `url`, `method` and `headers`. 355 | /// 356 | /// It is important to understand the memory implications of uploading `MultipartFormData`. If the cummulative 357 | /// payload is small, encoding the data in-memory and directly uploading to a server is the by far the most 358 | /// efficient approach. However, if the payload is too large, encoding the data in-memory could cause your app to 359 | /// be terminated. Larger payloads must first be written to disk using input and output streams to keep the memory 360 | /// footprint low, then the data can be uploaded as a stream from the resulting file. Streaming from disk MUST be 361 | /// used for larger payloads such as video content. 362 | /// 363 | /// The `encodingMemoryThreshold` parameter allows Alamofire to automatically determine whether to encode in-memory 364 | /// or stream from disk. If the content length of the `MultipartFormData` is below the `encodingMemoryThreshold`, 365 | /// encoding takes place in-memory. If the content length exceeds the threshold, the data is streamed to disk 366 | /// during the encoding process. Then the result is uploaded as data or as a stream depending on which encoding 367 | /// technique was used. 368 | /// 369 | /// - parameter multipartFormData: The closure used to append body parts to the `MultipartFormData`. 370 | /// - parameter encodingMemoryThreshold: The encoding memory threshold in bytes. 371 | /// `multipartFormDataEncodingMemoryThreshold` by default. 372 | /// - parameter url: The URL. 373 | /// - parameter method: The HTTP method. `.post` by default. 374 | /// - parameter headers: The HTTP headers. `nil` by default. 375 | /// - parameter encodingCompletion: The closure called when the `MultipartFormData` encoding is complete. 376 | public func upload( 377 | multipartFormData: @escaping (MultipartFormData) -> Void, 378 | usingThreshold encodingMemoryThreshold: UInt64 = SessionManager.multipartFormDataEncodingMemoryThreshold, 379 | to url: URLConvertible, 380 | method: HTTPMethod = .post, 381 | headers: HTTPHeaders? = nil, 382 | encodingCompletion: ((SessionManager.MultipartFormDataEncodingResult) -> Void)?) 383 | { 384 | return SessionManager.default.upload( 385 | multipartFormData: multipartFormData, 386 | usingThreshold: encodingMemoryThreshold, 387 | to: url, 388 | method: method, 389 | headers: headers, 390 | encodingCompletion: encodingCompletion 391 | ) 392 | } 393 | 394 | /// Encodes `multipartFormData` using `encodingMemoryThreshold` and the default `SessionManager` and 395 | /// calls `encodingCompletion` with new `UploadRequest` using the `urlRequest`. 396 | /// 397 | /// It is important to understand the memory implications of uploading `MultipartFormData`. If the cummulative 398 | /// payload is small, encoding the data in-memory and directly uploading to a server is the by far the most 399 | /// efficient approach. However, if the payload is too large, encoding the data in-memory could cause your app to 400 | /// be terminated. Larger payloads must first be written to disk using input and output streams to keep the memory 401 | /// footprint low, then the data can be uploaded as a stream from the resulting file. Streaming from disk MUST be 402 | /// used for larger payloads such as video content. 403 | /// 404 | /// The `encodingMemoryThreshold` parameter allows Alamofire to automatically determine whether to encode in-memory 405 | /// or stream from disk. If the content length of the `MultipartFormData` is below the `encodingMemoryThreshold`, 406 | /// encoding takes place in-memory. If the content length exceeds the threshold, the data is streamed to disk 407 | /// during the encoding process. Then the result is uploaded as data or as a stream depending on which encoding 408 | /// technique was used. 409 | /// 410 | /// - parameter multipartFormData: The closure used to append body parts to the `MultipartFormData`. 411 | /// - parameter encodingMemoryThreshold: The encoding memory threshold in bytes. 412 | /// `multipartFormDataEncodingMemoryThreshold` by default. 413 | /// - parameter urlRequest: The URL request. 414 | /// - parameter encodingCompletion: The closure called when the `MultipartFormData` encoding is complete. 415 | public func upload( 416 | multipartFormData: @escaping (MultipartFormData) -> Void, 417 | usingThreshold encodingMemoryThreshold: UInt64 = SessionManager.multipartFormDataEncodingMemoryThreshold, 418 | with urlRequest: URLRequestConvertible, 419 | encodingCompletion: ((SessionManager.MultipartFormDataEncodingResult) -> Void)?) 420 | { 421 | return SessionManager.default.upload( 422 | multipartFormData: multipartFormData, 423 | usingThreshold: encodingMemoryThreshold, 424 | with: urlRequest, 425 | encodingCompletion: encodingCompletion 426 | ) 427 | } 428 | 429 | #if !os(watchOS) 430 | 431 | // MARK: - Stream Request 432 | 433 | // MARK: Hostname and Port 434 | 435 | /// Creates a `StreamRequest` using the default `SessionManager` for bidirectional streaming with the `hostname` 436 | /// and `port`. 437 | /// 438 | /// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned. 439 | /// 440 | /// - parameter hostName: The hostname of the server to connect to. 441 | /// - parameter port: The port of the server to connect to. 442 | /// 443 | /// - returns: The created `StreamRequest`. 444 | @discardableResult 445 | @available(iOS 9.0, macOS 10.11, tvOS 9.0, *) 446 | public func stream(withHostName hostName: String, port: Int) -> StreamRequest { 447 | return SessionManager.default.stream(withHostName: hostName, port: port) 448 | } 449 | 450 | // MARK: NetService 451 | 452 | /// Creates a `StreamRequest` using the default `SessionManager` for bidirectional streaming with the `netService`. 453 | /// 454 | /// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned. 455 | /// 456 | /// - parameter netService: The net service used to identify the endpoint. 457 | /// 458 | /// - returns: The created `StreamRequest`. 459 | @discardableResult 460 | @available(iOS 9.0, macOS 10.11, tvOS 9.0, *) 461 | public func stream(with netService: NetService) -> StreamRequest { 462 | return SessionManager.default.stream(with: netService) 463 | } 464 | 465 | #endif 466 | -------------------------------------------------------------------------------- /StaticPods/Alamofire 4.8.1/Source/DispatchQueue+Alamofire.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DispatchQueue+Alamofire.swift 3 | // 4 | // Copyright (c) 2014 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 | 25 | import Dispatch 26 | import Foundation 27 | 28 | extension DispatchQueue { 29 | static var userInteractive: DispatchQueue { return DispatchQueue.global(qos: .userInteractive) } 30 | static var userInitiated: DispatchQueue { return DispatchQueue.global(qos: .userInitiated) } 31 | static var utility: DispatchQueue { return DispatchQueue.global(qos: .utility) } 32 | static var background: DispatchQueue { return DispatchQueue.global(qos: .background) } 33 | 34 | func after(_ delay: TimeInterval, execute closure: @escaping () -> Void) { 35 | asyncAfter(deadline: .now() + delay, execute: closure) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /StaticPods/Alamofire 4.8.1/Source/NetworkReachabilityManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NetworkReachabilityManager.swift 3 | // 4 | // Copyright (c) 2014 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 | 25 | #if !os(watchOS) 26 | 27 | import Foundation 28 | import SystemConfiguration 29 | 30 | /// The `NetworkReachabilityManager` class listens for reachability changes of hosts and addresses for both WWAN and 31 | /// WiFi network interfaces. 32 | /// 33 | /// Reachability can be used to determine background information about why a network operation failed, or to retry 34 | /// network requests when a connection is established. It should not be used to prevent a user from initiating a network 35 | /// request, as it's possible that an initial request may be required to establish reachability. 36 | open class NetworkReachabilityManager { 37 | /// Defines the various states of network reachability. 38 | /// 39 | /// - unknown: It is unknown whether the network is reachable. 40 | /// - notReachable: The network is not reachable. 41 | /// - reachable: The network is reachable. 42 | public enum NetworkReachabilityStatus { 43 | case unknown 44 | case notReachable 45 | case reachable(ConnectionType) 46 | } 47 | 48 | /// Defines the various connection types detected by reachability flags. 49 | /// 50 | /// - ethernetOrWiFi: The connection type is either over Ethernet or WiFi. 51 | /// - wwan: The connection type is a WWAN connection. 52 | public enum ConnectionType { 53 | case ethernetOrWiFi 54 | case wwan 55 | } 56 | 57 | /// A closure executed when the network reachability status changes. The closure takes a single argument: the 58 | /// network reachability status. 59 | public typealias Listener = (NetworkReachabilityStatus) -> Void 60 | 61 | // MARK: - Properties 62 | 63 | /// Whether the network is currently reachable. 64 | open var isReachable: Bool { return isReachableOnWWAN || isReachableOnEthernetOrWiFi } 65 | 66 | /// Whether the network is currently reachable over the WWAN interface. 67 | open var isReachableOnWWAN: Bool { return networkReachabilityStatus == .reachable(.wwan) } 68 | 69 | /// Whether the network is currently reachable over Ethernet or WiFi interface. 70 | open var isReachableOnEthernetOrWiFi: Bool { return networkReachabilityStatus == .reachable(.ethernetOrWiFi) } 71 | 72 | /// The current network reachability status. 73 | open var networkReachabilityStatus: NetworkReachabilityStatus { 74 | guard let flags = self.flags else { return .unknown } 75 | return networkReachabilityStatusForFlags(flags) 76 | } 77 | 78 | /// The dispatch queue to execute the `listener` closure on. 79 | open var listenerQueue: DispatchQueue = DispatchQueue.main 80 | 81 | /// A closure executed when the network reachability status changes. 82 | open var listener: Listener? 83 | 84 | open var flags: SCNetworkReachabilityFlags? { 85 | var flags = SCNetworkReachabilityFlags() 86 | 87 | if SCNetworkReachabilityGetFlags(reachability, &flags) { 88 | return flags 89 | } 90 | 91 | return nil 92 | } 93 | 94 | private let reachability: SCNetworkReachability 95 | open var previousFlags: SCNetworkReachabilityFlags 96 | 97 | // MARK: - Initialization 98 | 99 | /// Creates a `NetworkReachabilityManager` instance with the specified host. 100 | /// 101 | /// - parameter host: The host used to evaluate network reachability. 102 | /// 103 | /// - returns: The new `NetworkReachabilityManager` instance. 104 | public convenience init?(host: String) { 105 | guard let reachability = SCNetworkReachabilityCreateWithName(nil, host) else { return nil } 106 | self.init(reachability: reachability) 107 | } 108 | 109 | /// Creates a `NetworkReachabilityManager` instance that monitors the address 0.0.0.0. 110 | /// 111 | /// Reachability treats the 0.0.0.0 address as a special token that causes it to monitor the general routing 112 | /// status of the device, both IPv4 and IPv6. 113 | /// 114 | /// - returns: The new `NetworkReachabilityManager` instance. 115 | public convenience init?() { 116 | var address = sockaddr_in() 117 | address.sin_len = UInt8(MemoryLayout.size) 118 | address.sin_family = sa_family_t(AF_INET) 119 | 120 | guard let reachability = withUnsafePointer(to: &address, { pointer in 121 | return pointer.withMemoryRebound(to: sockaddr.self, capacity: MemoryLayout.size) { 122 | return SCNetworkReachabilityCreateWithAddress(nil, $0) 123 | } 124 | }) else { return nil } 125 | 126 | self.init(reachability: reachability) 127 | } 128 | 129 | private init(reachability: SCNetworkReachability) { 130 | self.reachability = reachability 131 | 132 | // Set the previous flags to an unreserved value to represent unknown status 133 | self.previousFlags = SCNetworkReachabilityFlags(rawValue: 1 << 30) 134 | } 135 | 136 | deinit { 137 | stopListening() 138 | } 139 | 140 | // MARK: - Listening 141 | 142 | /// Starts listening for changes in network reachability status. 143 | /// 144 | /// - returns: `true` if listening was started successfully, `false` otherwise. 145 | @discardableResult 146 | open func startListening() -> Bool { 147 | var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil) 148 | context.info = Unmanaged.passUnretained(self).toOpaque() 149 | 150 | let callbackEnabled = SCNetworkReachabilitySetCallback( 151 | reachability, 152 | { (_, flags, info) in 153 | let reachability = Unmanaged.fromOpaque(info!).takeUnretainedValue() 154 | reachability.notifyListener(flags) 155 | }, 156 | &context 157 | ) 158 | 159 | let queueEnabled = SCNetworkReachabilitySetDispatchQueue(reachability, listenerQueue) 160 | 161 | listenerQueue.async { 162 | guard let flags = self.flags else { return } 163 | self.notifyListener(flags) 164 | } 165 | 166 | return callbackEnabled && queueEnabled 167 | } 168 | 169 | /// Stops listening for changes in network reachability status. 170 | open func stopListening() { 171 | SCNetworkReachabilitySetCallback(reachability, nil, nil) 172 | SCNetworkReachabilitySetDispatchQueue(reachability, nil) 173 | } 174 | 175 | // MARK: - Internal - Listener Notification 176 | 177 | func notifyListener(_ flags: SCNetworkReachabilityFlags) { 178 | guard previousFlags != flags else { return } 179 | previousFlags = flags 180 | 181 | listener?(networkReachabilityStatusForFlags(flags)) 182 | } 183 | 184 | // MARK: - Internal - Network Reachability Status 185 | 186 | func networkReachabilityStatusForFlags(_ flags: SCNetworkReachabilityFlags) -> NetworkReachabilityStatus { 187 | guard isNetworkReachable(with: flags) else { return .notReachable } 188 | 189 | var networkStatus: NetworkReachabilityStatus = .reachable(.ethernetOrWiFi) 190 | 191 | #if os(iOS) 192 | if flags.contains(.isWWAN) { networkStatus = .reachable(.wwan) } 193 | #endif 194 | 195 | return networkStatus 196 | } 197 | 198 | func isNetworkReachable(with flags: SCNetworkReachabilityFlags) -> Bool { 199 | let isReachable = flags.contains(.reachable) 200 | let needsConnection = flags.contains(.connectionRequired) 201 | let canConnectAutomatically = flags.contains(.connectionOnDemand) || flags.contains(.connectionOnTraffic) 202 | let canConnectWithoutUserInteraction = canConnectAutomatically && !flags.contains(.interventionRequired) 203 | 204 | return isReachable && (!needsConnection || canConnectWithoutUserInteraction) 205 | } 206 | } 207 | 208 | // MARK: - 209 | 210 | extension NetworkReachabilityManager.NetworkReachabilityStatus: Equatable {} 211 | 212 | /// Returns whether the two network reachability status values are equal. 213 | /// 214 | /// - parameter lhs: The left-hand side value to compare. 215 | /// - parameter rhs: The right-hand side value to compare. 216 | /// 217 | /// - returns: `true` if the two values are equal, `false` otherwise. 218 | public func ==( 219 | lhs: NetworkReachabilityManager.NetworkReachabilityStatus, 220 | rhs: NetworkReachabilityManager.NetworkReachabilityStatus) 221 | -> Bool 222 | { 223 | switch (lhs, rhs) { 224 | case (.unknown, .unknown): 225 | return true 226 | case (.notReachable, .notReachable): 227 | return true 228 | case let (.reachable(lhsConnectionType), .reachable(rhsConnectionType)): 229 | return lhsConnectionType == rhsConnectionType 230 | default: 231 | return false 232 | } 233 | } 234 | 235 | #endif 236 | -------------------------------------------------------------------------------- /StaticPods/Alamofire 4.8.1/Source/Notifications.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Notifications.swift 3 | // 4 | // Copyright (c) 2014 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 | 25 | import Foundation 26 | 27 | extension Notification.Name { 28 | /// Used as a namespace for all `URLSessionTask` related notifications. 29 | public struct Task { 30 | /// Posted when a `URLSessionTask` is resumed. The notification `object` contains the resumed `URLSessionTask`. 31 | public static let DidResume = Notification.Name(rawValue: "org.alamofire.notification.name.task.didResume") 32 | 33 | /// Posted when a `URLSessionTask` is suspended. The notification `object` contains the suspended `URLSessionTask`. 34 | public static let DidSuspend = Notification.Name(rawValue: "org.alamofire.notification.name.task.didSuspend") 35 | 36 | /// Posted when a `URLSessionTask` is cancelled. The notification `object` contains the cancelled `URLSessionTask`. 37 | public static let DidCancel = Notification.Name(rawValue: "org.alamofire.notification.name.task.didCancel") 38 | 39 | /// Posted when a `URLSessionTask` is completed. The notification `object` contains the completed `URLSessionTask`. 40 | public static let DidComplete = Notification.Name(rawValue: "org.alamofire.notification.name.task.didComplete") 41 | } 42 | } 43 | 44 | // MARK: - 45 | 46 | extension Notification { 47 | /// Used as a namespace for all `Notification` user info dictionary keys. 48 | public struct Key { 49 | /// User info dictionary key representing the `URLSessionTask` associated with the notification. 50 | public static let Task = "org.alamofire.notification.key.task" 51 | 52 | /// User info dictionary key representing the responseData associated with the notification. 53 | public static let ResponseData = "org.alamofire.notification.key.responseData" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /StaticPods/Alamofire 4.8.1/Source/ParameterEncoding.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ParameterEncoding.swift 3 | // 4 | // Copyright (c) 2014 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 | 25 | import Foundation 26 | 27 | /// HTTP method definitions. 28 | /// 29 | /// See https://tools.ietf.org/html/rfc7231#section-4.3 30 | public enum HTTPMethod: String { 31 | case options = "OPTIONS" 32 | case get = "GET" 33 | case head = "HEAD" 34 | case post = "POST" 35 | case put = "PUT" 36 | case patch = "PATCH" 37 | case delete = "DELETE" 38 | case trace = "TRACE" 39 | case connect = "CONNECT" 40 | } 41 | 42 | // MARK: - 43 | 44 | /// A dictionary of parameters to apply to a `URLRequest`. 45 | public typealias Parameters = [String: Any] 46 | 47 | /// A type used to define how a set of parameters are applied to a `URLRequest`. 48 | public protocol ParameterEncoding { 49 | /// Creates a URL request by encoding parameters and applying them onto an existing request. 50 | /// 51 | /// - parameter urlRequest: The request to have parameters applied. 52 | /// - parameter parameters: The parameters to apply. 53 | /// 54 | /// - throws: An `AFError.parameterEncodingFailed` error if encoding fails. 55 | /// 56 | /// - returns: The encoded request. 57 | func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest 58 | } 59 | 60 | // MARK: - 61 | 62 | /// Creates a url-encoded query string to be set as or appended to any existing URL query string or set as the HTTP 63 | /// body of the URL request. Whether the query string is set or appended to any existing URL query string or set as 64 | /// the HTTP body depends on the destination of the encoding. 65 | /// 66 | /// The `Content-Type` HTTP header field of an encoded request with HTTP body is set to 67 | /// `application/x-www-form-urlencoded; charset=utf-8`. 68 | /// 69 | /// There is no published specification for how to encode collection types. By default the convention of appending 70 | /// `[]` to the key for array values (`foo[]=1&foo[]=2`), and appending the key surrounded by square brackets for 71 | /// nested dictionary values (`foo[bar]=baz`) is used. Optionally, `ArrayEncoding` can be used to omit the 72 | /// square brackets appended to array keys. 73 | /// 74 | /// `BoolEncoding` can be used to configure how boolean values are encoded. The default behavior is to encode 75 | /// `true` as 1 and `false` as 0. 76 | public struct URLEncoding: ParameterEncoding { 77 | 78 | // MARK: Helper Types 79 | 80 | /// Defines whether the url-encoded query string is applied to the existing query string or HTTP body of the 81 | /// resulting URL request. 82 | /// 83 | /// - methodDependent: Applies encoded query string result to existing query string for `GET`, `HEAD` and `DELETE` 84 | /// requests and sets as the HTTP body for requests with any other HTTP method. 85 | /// - queryString: Sets or appends encoded query string result to existing query string. 86 | /// - httpBody: Sets encoded query string result as the HTTP body of the URL request. 87 | public enum Destination { 88 | case methodDependent, queryString, httpBody 89 | } 90 | 91 | /// Configures how `Array` parameters are encoded. 92 | /// 93 | /// - brackets: An empty set of square brackets is appended to the key for every value. 94 | /// This is the default behavior. 95 | /// - noBrackets: No brackets are appended. The key is encoded as is. 96 | public enum ArrayEncoding { 97 | case brackets, noBrackets 98 | 99 | func encode(key: String) -> String { 100 | switch self { 101 | case .brackets: 102 | return "\(key)[]" 103 | case .noBrackets: 104 | return key 105 | } 106 | } 107 | } 108 | 109 | /// Configures how `Bool` parameters are encoded. 110 | /// 111 | /// - numeric: Encode `true` as `1` and `false` as `0`. This is the default behavior. 112 | /// - literal: Encode `true` and `false` as string literals. 113 | public enum BoolEncoding { 114 | case numeric, literal 115 | 116 | func encode(value: Bool) -> String { 117 | switch self { 118 | case .numeric: 119 | return value ? "1" : "0" 120 | case .literal: 121 | return value ? "true" : "false" 122 | } 123 | } 124 | } 125 | 126 | // MARK: Properties 127 | 128 | /// Returns a default `URLEncoding` instance. 129 | public static var `default`: URLEncoding { return URLEncoding() } 130 | 131 | /// Returns a `URLEncoding` instance with a `.methodDependent` destination. 132 | public static var methodDependent: URLEncoding { return URLEncoding() } 133 | 134 | /// Returns a `URLEncoding` instance with a `.queryString` destination. 135 | public static var queryString: URLEncoding { return URLEncoding(destination: .queryString) } 136 | 137 | /// Returns a `URLEncoding` instance with an `.httpBody` destination. 138 | public static var httpBody: URLEncoding { return URLEncoding(destination: .httpBody) } 139 | 140 | /// The destination defining where the encoded query string is to be applied to the URL request. 141 | public let destination: Destination 142 | 143 | /// The encoding to use for `Array` parameters. 144 | public let arrayEncoding: ArrayEncoding 145 | 146 | /// The encoding to use for `Bool` parameters. 147 | public let boolEncoding: BoolEncoding 148 | 149 | // MARK: Initialization 150 | 151 | /// Creates a `URLEncoding` instance using the specified destination. 152 | /// 153 | /// - parameter destination: The destination defining where the encoded query string is to be applied. 154 | /// - parameter arrayEncoding: The encoding to use for `Array` parameters. 155 | /// - parameter boolEncoding: The encoding to use for `Bool` parameters. 156 | /// 157 | /// - returns: The new `URLEncoding` instance. 158 | public init(destination: Destination = .methodDependent, arrayEncoding: ArrayEncoding = .brackets, boolEncoding: BoolEncoding = .numeric) { 159 | self.destination = destination 160 | self.arrayEncoding = arrayEncoding 161 | self.boolEncoding = boolEncoding 162 | } 163 | 164 | // MARK: Encoding 165 | 166 | /// Creates a URL request by encoding parameters and applying them onto an existing request. 167 | /// 168 | /// - parameter urlRequest: The request to have parameters applied. 169 | /// - parameter parameters: The parameters to apply. 170 | /// 171 | /// - throws: An `Error` if the encoding process encounters an error. 172 | /// 173 | /// - returns: The encoded request. 174 | public func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest { 175 | var urlRequest = try urlRequest.asURLRequest() 176 | 177 | guard let parameters = parameters else { return urlRequest } 178 | 179 | if let method = HTTPMethod(rawValue: urlRequest.httpMethod ?? "GET"), encodesParametersInURL(with: method) { 180 | guard let url = urlRequest.url else { 181 | throw AFError.parameterEncodingFailed(reason: .missingURL) 182 | } 183 | 184 | if var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false), !parameters.isEmpty { 185 | let percentEncodedQuery = (urlComponents.percentEncodedQuery.map { $0 + "&" } ?? "") + query(parameters) 186 | urlComponents.percentEncodedQuery = percentEncodedQuery 187 | urlRequest.url = urlComponents.url 188 | } 189 | } else { 190 | if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil { 191 | urlRequest.setValue("application/x-www-form-urlencoded; charset=utf-8", forHTTPHeaderField: "Content-Type") 192 | } 193 | 194 | urlRequest.httpBody = query(parameters).data(using: .utf8, allowLossyConversion: false) 195 | } 196 | 197 | return urlRequest 198 | } 199 | 200 | /// Creates percent-escaped, URL encoded query string components from the given key-value pair using recursion. 201 | /// 202 | /// - parameter key: The key of the query component. 203 | /// - parameter value: The value of the query component. 204 | /// 205 | /// - returns: The percent-escaped, URL encoded query string components. 206 | public func queryComponents(fromKey key: String, value: Any) -> [(String, String)] { 207 | var components: [(String, String)] = [] 208 | 209 | if let dictionary = value as? [String: Any] { 210 | for (nestedKey, value) in dictionary { 211 | components += queryComponents(fromKey: "\(key)[\(nestedKey)]", value: value) 212 | } 213 | } else if let array = value as? [Any] { 214 | for value in array { 215 | components += queryComponents(fromKey: arrayEncoding.encode(key: key), value: value) 216 | } 217 | } else if let value = value as? NSNumber { 218 | if value.isBool { 219 | components.append((escape(key), escape(boolEncoding.encode(value: value.boolValue)))) 220 | } else { 221 | components.append((escape(key), escape("\(value)"))) 222 | } 223 | } else if let bool = value as? Bool { 224 | components.append((escape(key), escape(boolEncoding.encode(value: bool)))) 225 | } else { 226 | components.append((escape(key), escape("\(value)"))) 227 | } 228 | 229 | return components 230 | } 231 | 232 | /// Returns a percent-escaped string following RFC 3986 for a query string key or value. 233 | /// 234 | /// RFC 3986 states that the following characters are "reserved" characters. 235 | /// 236 | /// - General Delimiters: ":", "#", "[", "]", "@", "?", "/" 237 | /// - Sub-Delimiters: "!", "$", "&", "'", "(", ")", "*", "+", ",", ";", "=" 238 | /// 239 | /// In RFC 3986 - Section 3.4, it states that the "?" and "/" characters should not be escaped to allow 240 | /// query strings to include a URL. Therefore, all "reserved" characters with the exception of "?" and "/" 241 | /// should be percent-escaped in the query string. 242 | /// 243 | /// - parameter string: The string to be percent-escaped. 244 | /// 245 | /// - returns: The percent-escaped string. 246 | public func escape(_ string: String) -> String { 247 | let generalDelimitersToEncode = ":#[]@" // does not include "?" or "/" due to RFC 3986 - Section 3.4 248 | let subDelimitersToEncode = "!$&'()*+,;=" 249 | 250 | var allowedCharacterSet = CharacterSet.urlQueryAllowed 251 | allowedCharacterSet.remove(charactersIn: "\(generalDelimitersToEncode)\(subDelimitersToEncode)") 252 | 253 | var escaped = "" 254 | 255 | //========================================================================================================== 256 | // 257 | // Batching is required for escaping due to an internal bug in iOS 8.1 and 8.2. Encoding more than a few 258 | // hundred Chinese characters causes various malloc error crashes. To avoid this issue until iOS 8 is no 259 | // longer supported, batching MUST be used for encoding. This introduces roughly a 20% overhead. For more 260 | // info, please refer to: 261 | // 262 | // - https://github.com/Alamofire/Alamofire/issues/206 263 | // 264 | //========================================================================================================== 265 | 266 | if #available(iOS 8.3, *) { 267 | escaped = string.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet) ?? string 268 | } else { 269 | let batchSize = 50 270 | var index = string.startIndex 271 | 272 | while index != string.endIndex { 273 | let startIndex = index 274 | let endIndex = string.index(index, offsetBy: batchSize, limitedBy: string.endIndex) ?? string.endIndex 275 | let range = startIndex.. String { 289 | var components: [(String, String)] = [] 290 | 291 | for key in parameters.keys.sorted(by: <) { 292 | let value = parameters[key]! 293 | components += queryComponents(fromKey: key, value: value) 294 | } 295 | return components.map { "\($0)=\($1)" }.joined(separator: "&") 296 | } 297 | 298 | private func encodesParametersInURL(with method: HTTPMethod) -> Bool { 299 | switch destination { 300 | case .queryString: 301 | return true 302 | case .httpBody: 303 | return false 304 | default: 305 | break 306 | } 307 | 308 | switch method { 309 | case .get, .head, .delete: 310 | return true 311 | default: 312 | return false 313 | } 314 | } 315 | } 316 | 317 | // MARK: - 318 | 319 | /// Uses `JSONSerialization` to create a JSON representation of the parameters object, which is set as the body of the 320 | /// request. The `Content-Type` HTTP header field of an encoded request is set to `application/json`. 321 | public struct JSONEncoding: ParameterEncoding { 322 | 323 | // MARK: Properties 324 | 325 | /// Returns a `JSONEncoding` instance with default writing options. 326 | public static var `default`: JSONEncoding { return JSONEncoding() } 327 | 328 | /// Returns a `JSONEncoding` instance with `.prettyPrinted` writing options. 329 | public static var prettyPrinted: JSONEncoding { return JSONEncoding(options: .prettyPrinted) } 330 | 331 | /// The options for writing the parameters as JSON data. 332 | public let options: JSONSerialization.WritingOptions 333 | 334 | // MARK: Initialization 335 | 336 | /// Creates a `JSONEncoding` instance using the specified options. 337 | /// 338 | /// - parameter options: The options for writing the parameters as JSON data. 339 | /// 340 | /// - returns: The new `JSONEncoding` instance. 341 | public init(options: JSONSerialization.WritingOptions = []) { 342 | self.options = options 343 | } 344 | 345 | // MARK: Encoding 346 | 347 | /// Creates a URL request by encoding parameters and applying them onto an existing request. 348 | /// 349 | /// - parameter urlRequest: The request to have parameters applied. 350 | /// - parameter parameters: The parameters to apply. 351 | /// 352 | /// - throws: An `Error` if the encoding process encounters an error. 353 | /// 354 | /// - returns: The encoded request. 355 | public func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest { 356 | var urlRequest = try urlRequest.asURLRequest() 357 | 358 | guard let parameters = parameters else { return urlRequest } 359 | 360 | do { 361 | let data = try JSONSerialization.data(withJSONObject: parameters, options: options) 362 | 363 | if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil { 364 | urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type") 365 | } 366 | 367 | urlRequest.httpBody = data 368 | } catch { 369 | throw AFError.parameterEncodingFailed(reason: .jsonEncodingFailed(error: error)) 370 | } 371 | 372 | return urlRequest 373 | } 374 | 375 | /// Creates a URL request by encoding the JSON object and setting the resulting data on the HTTP body. 376 | /// 377 | /// - parameter urlRequest: The request to apply the JSON object to. 378 | /// - parameter jsonObject: The JSON object to apply to the request. 379 | /// 380 | /// - throws: An `Error` if the encoding process encounters an error. 381 | /// 382 | /// - returns: The encoded request. 383 | public func encode(_ urlRequest: URLRequestConvertible, withJSONObject jsonObject: Any? = nil) throws -> URLRequest { 384 | var urlRequest = try urlRequest.asURLRequest() 385 | 386 | guard let jsonObject = jsonObject else { return urlRequest } 387 | 388 | do { 389 | let data = try JSONSerialization.data(withJSONObject: jsonObject, options: options) 390 | 391 | if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil { 392 | urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type") 393 | } 394 | 395 | urlRequest.httpBody = data 396 | } catch { 397 | throw AFError.parameterEncodingFailed(reason: .jsonEncodingFailed(error: error)) 398 | } 399 | 400 | return urlRequest 401 | } 402 | } 403 | 404 | // MARK: - 405 | 406 | /// Uses `PropertyListSerialization` to create a plist representation of the parameters object, according to the 407 | /// associated format and write options values, which is set as the body of the request. The `Content-Type` HTTP header 408 | /// field of an encoded request is set to `application/x-plist`. 409 | public struct PropertyListEncoding: ParameterEncoding { 410 | 411 | // MARK: Properties 412 | 413 | /// Returns a default `PropertyListEncoding` instance. 414 | public static var `default`: PropertyListEncoding { return PropertyListEncoding() } 415 | 416 | /// Returns a `PropertyListEncoding` instance with xml formatting and default writing options. 417 | public static var xml: PropertyListEncoding { return PropertyListEncoding(format: .xml) } 418 | 419 | /// Returns a `PropertyListEncoding` instance with binary formatting and default writing options. 420 | public static var binary: PropertyListEncoding { return PropertyListEncoding(format: .binary) } 421 | 422 | /// The property list serialization format. 423 | public let format: PropertyListSerialization.PropertyListFormat 424 | 425 | /// The options for writing the parameters as plist data. 426 | public let options: PropertyListSerialization.WriteOptions 427 | 428 | // MARK: Initialization 429 | 430 | /// Creates a `PropertyListEncoding` instance using the specified format and options. 431 | /// 432 | /// - parameter format: The property list serialization format. 433 | /// - parameter options: The options for writing the parameters as plist data. 434 | /// 435 | /// - returns: The new `PropertyListEncoding` instance. 436 | public init( 437 | format: PropertyListSerialization.PropertyListFormat = .xml, 438 | options: PropertyListSerialization.WriteOptions = 0) 439 | { 440 | self.format = format 441 | self.options = options 442 | } 443 | 444 | // MARK: Encoding 445 | 446 | /// Creates a URL request by encoding parameters and applying them onto an existing request. 447 | /// 448 | /// - parameter urlRequest: The request to have parameters applied. 449 | /// - parameter parameters: The parameters to apply. 450 | /// 451 | /// - throws: An `Error` if the encoding process encounters an error. 452 | /// 453 | /// - returns: The encoded request. 454 | public func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest { 455 | var urlRequest = try urlRequest.asURLRequest() 456 | 457 | guard let parameters = parameters else { return urlRequest } 458 | 459 | do { 460 | let data = try PropertyListSerialization.data( 461 | fromPropertyList: parameters, 462 | format: format, 463 | options: options 464 | ) 465 | 466 | if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil { 467 | urlRequest.setValue("application/x-plist", forHTTPHeaderField: "Content-Type") 468 | } 469 | 470 | urlRequest.httpBody = data 471 | } catch { 472 | throw AFError.parameterEncodingFailed(reason: .propertyListEncodingFailed(error: error)) 473 | } 474 | 475 | return urlRequest 476 | } 477 | } 478 | 479 | // MARK: - 480 | 481 | extension NSNumber { 482 | fileprivate var isBool: Bool { return CFBooleanGetTypeID() == CFGetTypeID(self) } 483 | } 484 | -------------------------------------------------------------------------------- /StaticPods/Alamofire 4.8.1/Source/Response.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Response.swift 3 | // 4 | // Copyright (c) 2014 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 | 25 | import Foundation 26 | 27 | /// Used to store all data associated with an non-serialized response of a data or upload request. 28 | public struct DefaultDataResponse { 29 | /// The URL request sent to the server. 30 | public let request: URLRequest? 31 | 32 | /// The server's response to the URL request. 33 | public let response: HTTPURLResponse? 34 | 35 | /// The data returned by the server. 36 | public let data: Data? 37 | 38 | /// The error encountered while executing or validating the request. 39 | public let error: Error? 40 | 41 | /// The timeline of the complete lifecycle of the request. 42 | public let timeline: Timeline 43 | 44 | var _metrics: AnyObject? 45 | 46 | /// Creates a `DefaultDataResponse` instance from the specified parameters. 47 | /// 48 | /// - Parameters: 49 | /// - request: The URL request sent to the server. 50 | /// - response: The server's response to the URL request. 51 | /// - data: The data returned by the server. 52 | /// - error: The error encountered while executing or validating the request. 53 | /// - timeline: The timeline of the complete lifecycle of the request. `Timeline()` by default. 54 | /// - metrics: The task metrics containing the request / response statistics. `nil` by default. 55 | public init( 56 | request: URLRequest?, 57 | response: HTTPURLResponse?, 58 | data: Data?, 59 | error: Error?, 60 | timeline: Timeline = Timeline(), 61 | metrics: AnyObject? = nil) 62 | { 63 | self.request = request 64 | self.response = response 65 | self.data = data 66 | self.error = error 67 | self.timeline = timeline 68 | } 69 | } 70 | 71 | // MARK: - 72 | 73 | /// Used to store all data associated with a serialized response of a data or upload request. 74 | public struct DataResponse { 75 | /// The URL request sent to the server. 76 | public let request: URLRequest? 77 | 78 | /// The server's response to the URL request. 79 | public let response: HTTPURLResponse? 80 | 81 | /// The data returned by the server. 82 | public let data: Data? 83 | 84 | /// The result of response serialization. 85 | internal let result: Result 86 | 87 | /// The timeline of the complete lifecycle of the request. 88 | public let timeline: Timeline 89 | 90 | /// Returns the associated value of the result if it is a success, `nil` otherwise. 91 | public var value: Value? { return result.value } 92 | 93 | /// Returns the associated error value if the result if it is a failure, `nil` otherwise. 94 | public var error: Error? { return result.error } 95 | 96 | var _metrics: AnyObject? 97 | 98 | /// Creates a `DataResponse` instance with the specified parameters derived from response serialization. 99 | /// 100 | /// - parameter request: The URL request sent to the server. 101 | /// - parameter response: The server's response to the URL request. 102 | /// - parameter data: The data returned by the server. 103 | /// - parameter result: The result of response serialization. 104 | /// - parameter timeline: The timeline of the complete lifecycle of the `Request`. Defaults to `Timeline()`. 105 | /// 106 | /// - returns: The new `DataResponse` instance. 107 | internal init( 108 | request: URLRequest?, 109 | response: HTTPURLResponse?, 110 | data: Data?, 111 | result: Result, 112 | timeline: Timeline = Timeline()) 113 | { 114 | self.request = request 115 | self.response = response 116 | self.data = data 117 | self.result = result 118 | self.timeline = timeline 119 | } 120 | } 121 | 122 | // MARK: - 123 | 124 | extension DataResponse: CustomStringConvertible, CustomDebugStringConvertible { 125 | /// The textual representation used when written to an output stream, which includes whether the result was a 126 | /// success or failure. 127 | public var description: String { 128 | return result.debugDescription 129 | } 130 | 131 | /// The debug textual representation used when written to an output stream, which includes the URL request, the URL 132 | /// response, the server data, the response serialization result and the timeline. 133 | public var debugDescription: String { 134 | var output: [String] = [] 135 | 136 | output.append(request != nil ? "[Request]: \(request!.httpMethod ?? "GET") \(request!)" : "[Request]: nil") 137 | output.append(response != nil ? "[Response]: \(response!)" : "[Response]: nil") 138 | output.append("[Data]: \(data?.count ?? 0) bytes") 139 | output.append("[Result]: \(result.debugDescription)") 140 | output.append("[Timeline]: \(timeline.debugDescription)") 141 | 142 | return output.joined(separator: "\n") 143 | } 144 | } 145 | 146 | // MARK: - 147 | 148 | extension DataResponse { 149 | /// Evaluates the specified closure when the result of this `DataResponse` is a success, passing the unwrapped 150 | /// result value as a parameter. 151 | /// 152 | /// Use the `map` method with a closure that does not throw. For example: 153 | /// 154 | /// let possibleData: DataResponse = ... 155 | /// let possibleInt = possibleData.map { $0.count } 156 | /// 157 | /// - parameter transform: A closure that takes the success value of the instance's result. 158 | /// 159 | /// - returns: A `DataResponse` whose result wraps the value returned by the given closure. If this instance's 160 | /// result is a failure, returns a response wrapping the same failure. 161 | public func map(_ transform: (Value) -> T) -> DataResponse { 162 | var response = DataResponse( 163 | request: request, 164 | response: self.response, 165 | data: data, 166 | result: result.map(transform), 167 | timeline: timeline 168 | ) 169 | 170 | response._metrics = _metrics 171 | 172 | return response 173 | } 174 | 175 | /// Evaluates the given closure when the result of this `DataResponse` is a success, passing the unwrapped result 176 | /// value as a parameter. 177 | /// 178 | /// Use the `flatMap` method with a closure that may throw an error. For example: 179 | /// 180 | /// let possibleData: DataResponse = ... 181 | /// let possibleObject = possibleData.flatMap { 182 | /// try JSONSerialization.jsonObject(with: $0) 183 | /// } 184 | /// 185 | /// - parameter transform: A closure that takes the success value of the instance's result. 186 | /// 187 | /// - returns: A success or failure `DataResponse` depending on the result of the given closure. If this instance's 188 | /// result is a failure, returns the same failure. 189 | public func flatMap(_ transform: (Value) throws -> T) -> DataResponse { 190 | var response = DataResponse( 191 | request: request, 192 | response: self.response, 193 | data: data, 194 | result: result.flatMap(transform), 195 | timeline: timeline 196 | ) 197 | 198 | response._metrics = _metrics 199 | 200 | return response 201 | } 202 | 203 | /// Evaluates the specified closure when the `DataResponse` is a failure, passing the unwrapped error as a parameter. 204 | /// 205 | /// Use the `mapError` function with a closure that does not throw. For example: 206 | /// 207 | /// let possibleData: DataResponse = ... 208 | /// let withMyError = possibleData.mapError { MyError.error($0) } 209 | /// 210 | /// - Parameter transform: A closure that takes the error of the instance. 211 | /// - Returns: A `DataResponse` instance containing the result of the transform. 212 | public func mapError(_ transform: (Error) -> E) -> DataResponse { 213 | var response = DataResponse( 214 | request: request, 215 | response: self.response, 216 | data: data, 217 | result: result.mapError(transform), 218 | timeline: timeline 219 | ) 220 | 221 | response._metrics = _metrics 222 | 223 | return response 224 | } 225 | 226 | /// Evaluates the specified closure when the `DataResponse` is a failure, passing the unwrapped error as a parameter. 227 | /// 228 | /// Use the `flatMapError` function with a closure that may throw an error. For example: 229 | /// 230 | /// let possibleData: DataResponse = ... 231 | /// let possibleObject = possibleData.flatMapError { 232 | /// try someFailableFunction(taking: $0) 233 | /// } 234 | /// 235 | /// - Parameter transform: A throwing closure that takes the error of the instance. 236 | /// 237 | /// - Returns: A `DataResponse` instance containing the result of the transform. 238 | public func flatMapError(_ transform: (Error) throws -> E) -> DataResponse { 239 | var response = DataResponse( 240 | request: request, 241 | response: self.response, 242 | data: data, 243 | result: result.flatMapError(transform), 244 | timeline: timeline 245 | ) 246 | 247 | response._metrics = _metrics 248 | 249 | return response 250 | } 251 | } 252 | 253 | // MARK: - 254 | 255 | /// Used to store all data associated with an non-serialized response of a download request. 256 | public struct DefaultDownloadResponse { 257 | /// The URL request sent to the server. 258 | public let request: URLRequest? 259 | 260 | /// The server's response to the URL request. 261 | public let response: HTTPURLResponse? 262 | 263 | /// The temporary destination URL of the data returned from the server. 264 | public let temporaryURL: URL? 265 | 266 | /// The final destination URL of the data returned from the server if it was moved. 267 | public let destinationURL: URL? 268 | 269 | /// The resume data generated if the request was cancelled. 270 | public let resumeData: Data? 271 | 272 | /// The error encountered while executing or validating the request. 273 | public let error: Error? 274 | 275 | /// The timeline of the complete lifecycle of the request. 276 | public let timeline: Timeline 277 | 278 | var _metrics: AnyObject? 279 | 280 | /// Creates a `DefaultDownloadResponse` instance from the specified parameters. 281 | /// 282 | /// - Parameters: 283 | /// - request: The URL request sent to the server. 284 | /// - response: The server's response to the URL request. 285 | /// - temporaryURL: The temporary destination URL of the data returned from the server. 286 | /// - destinationURL: The final destination URL of the data returned from the server if it was moved. 287 | /// - resumeData: The resume data generated if the request was cancelled. 288 | /// - error: The error encountered while executing or validating the request. 289 | /// - timeline: The timeline of the complete lifecycle of the request. `Timeline()` by default. 290 | /// - metrics: The task metrics containing the request / response statistics. `nil` by default. 291 | public init( 292 | request: URLRequest?, 293 | response: HTTPURLResponse?, 294 | temporaryURL: URL?, 295 | destinationURL: URL?, 296 | resumeData: Data?, 297 | error: Error?, 298 | timeline: Timeline = Timeline(), 299 | metrics: AnyObject? = nil) 300 | { 301 | self.request = request 302 | self.response = response 303 | self.temporaryURL = temporaryURL 304 | self.destinationURL = destinationURL 305 | self.resumeData = resumeData 306 | self.error = error 307 | self.timeline = timeline 308 | } 309 | } 310 | 311 | // MARK: - 312 | 313 | /// Used to store all data associated with a serialized response of a download request. 314 | public struct DownloadResponse { 315 | /// The URL request sent to the server. 316 | public let request: URLRequest? 317 | 318 | /// The server's response to the URL request. 319 | public let response: HTTPURLResponse? 320 | 321 | /// The temporary destination URL of the data returned from the server. 322 | public let temporaryURL: URL? 323 | 324 | /// The final destination URL of the data returned from the server if it was moved. 325 | public let destinationURL: URL? 326 | 327 | /// The resume data generated if the request was cancelled. 328 | public let resumeData: Data? 329 | 330 | /// The result of response serialization. 331 | internal let result: Result 332 | 333 | /// The timeline of the complete lifecycle of the request. 334 | public let timeline: Timeline 335 | 336 | /// Returns the associated value of the result if it is a success, `nil` otherwise. 337 | public var value: Value? { return result.value } 338 | 339 | /// Returns the associated error value if the result if it is a failure, `nil` otherwise. 340 | public var error: Error? { return result.error } 341 | 342 | var _metrics: AnyObject? 343 | 344 | /// Creates a `DownloadResponse` instance with the specified parameters derived from response serialization. 345 | /// 346 | /// - parameter request: The URL request sent to the server. 347 | /// - parameter response: The server's response to the URL request. 348 | /// - parameter temporaryURL: The temporary destination URL of the data returned from the server. 349 | /// - parameter destinationURL: The final destination URL of the data returned from the server if it was moved. 350 | /// - parameter resumeData: The resume data generated if the request was cancelled. 351 | /// - parameter result: The result of response serialization. 352 | /// - parameter timeline: The timeline of the complete lifecycle of the `Request`. Defaults to `Timeline()`. 353 | /// 354 | /// - returns: The new `DownloadResponse` instance. 355 | internal init( 356 | request: URLRequest?, 357 | response: HTTPURLResponse?, 358 | temporaryURL: URL?, 359 | destinationURL: URL?, 360 | resumeData: Data?, 361 | result: Result, 362 | timeline: Timeline = Timeline()) 363 | { 364 | self.request = request 365 | self.response = response 366 | self.temporaryURL = temporaryURL 367 | self.destinationURL = destinationURL 368 | self.resumeData = resumeData 369 | self.result = result 370 | self.timeline = timeline 371 | } 372 | } 373 | 374 | // MARK: - 375 | 376 | extension DownloadResponse: CustomStringConvertible, CustomDebugStringConvertible { 377 | /// The textual representation used when written to an output stream, which includes whether the result was a 378 | /// success or failure. 379 | public var description: String { 380 | return result.debugDescription 381 | } 382 | 383 | /// The debug textual representation used when written to an output stream, which includes the URL request, the URL 384 | /// response, the temporary and destination URLs, the resume data, the response serialization result and the 385 | /// timeline. 386 | public var debugDescription: String { 387 | var output: [String] = [] 388 | 389 | output.append(request != nil ? "[Request]: \(request!.httpMethod ?? "GET") \(request!)" : "[Request]: nil") 390 | output.append(response != nil ? "[Response]: \(response!)" : "[Response]: nil") 391 | output.append("[TemporaryURL]: \(temporaryURL?.path ?? "nil")") 392 | output.append("[DestinationURL]: \(destinationURL?.path ?? "nil")") 393 | output.append("[ResumeData]: \(resumeData?.count ?? 0) bytes") 394 | output.append("[Result]: \(result.debugDescription)") 395 | output.append("[Timeline]: \(timeline.debugDescription)") 396 | 397 | return output.joined(separator: "\n") 398 | } 399 | } 400 | 401 | // MARK: - 402 | 403 | extension DownloadResponse { 404 | /// Evaluates the given closure when the result of this `DownloadResponse` is a success, passing the unwrapped 405 | /// result value as a parameter. 406 | /// 407 | /// Use the `map` method with a closure that does not throw. For example: 408 | /// 409 | /// let possibleData: DownloadResponse = ... 410 | /// let possibleInt = possibleData.map { $0.count } 411 | /// 412 | /// - parameter transform: A closure that takes the success value of the instance's result. 413 | /// 414 | /// - returns: A `DownloadResponse` whose result wraps the value returned by the given closure. If this instance's 415 | /// result is a failure, returns a response wrapping the same failure. 416 | public func map(_ transform: (Value) -> T) -> DownloadResponse { 417 | var response = DownloadResponse( 418 | request: request, 419 | response: self.response, 420 | temporaryURL: temporaryURL, 421 | destinationURL: destinationURL, 422 | resumeData: resumeData, 423 | result: result.map(transform), 424 | timeline: timeline 425 | ) 426 | 427 | response._metrics = _metrics 428 | 429 | return response 430 | } 431 | 432 | /// Evaluates the given closure when the result of this `DownloadResponse` is a success, passing the unwrapped 433 | /// result value as a parameter. 434 | /// 435 | /// Use the `flatMap` method with a closure that may throw an error. For example: 436 | /// 437 | /// let possibleData: DownloadResponse = ... 438 | /// let possibleObject = possibleData.flatMap { 439 | /// try JSONSerialization.jsonObject(with: $0) 440 | /// } 441 | /// 442 | /// - parameter transform: A closure that takes the success value of the instance's result. 443 | /// 444 | /// - returns: A success or failure `DownloadResponse` depending on the result of the given closure. If this 445 | /// instance's result is a failure, returns the same failure. 446 | public func flatMap(_ transform: (Value) throws -> T) -> DownloadResponse { 447 | var response = DownloadResponse( 448 | request: request, 449 | response: self.response, 450 | temporaryURL: temporaryURL, 451 | destinationURL: destinationURL, 452 | resumeData: resumeData, 453 | result: result.flatMap(transform), 454 | timeline: timeline 455 | ) 456 | 457 | response._metrics = _metrics 458 | 459 | return response 460 | } 461 | 462 | /// Evaluates the specified closure when the `DownloadResponse` is a failure, passing the unwrapped error as a parameter. 463 | /// 464 | /// Use the `mapError` function with a closure that does not throw. For example: 465 | /// 466 | /// let possibleData: DownloadResponse = ... 467 | /// let withMyError = possibleData.mapError { MyError.error($0) } 468 | /// 469 | /// - Parameter transform: A closure that takes the error of the instance. 470 | /// - Returns: A `DownloadResponse` instance containing the result of the transform. 471 | public func mapError(_ transform: (Error) -> E) -> DownloadResponse { 472 | var response = DownloadResponse( 473 | request: request, 474 | response: self.response, 475 | temporaryURL: temporaryURL, 476 | destinationURL: destinationURL, 477 | resumeData: resumeData, 478 | result: result.mapError(transform), 479 | timeline: timeline 480 | ) 481 | 482 | response._metrics = _metrics 483 | 484 | return response 485 | } 486 | 487 | /// Evaluates the specified closure when the `DownloadResponse` is a failure, passing the unwrapped error as a parameter. 488 | /// 489 | /// Use the `flatMapError` function with a closure that may throw an error. For example: 490 | /// 491 | /// let possibleData: DownloadResponse = ... 492 | /// let possibleObject = possibleData.flatMapError { 493 | /// try someFailableFunction(taking: $0) 494 | /// } 495 | /// 496 | /// - Parameter transform: A throwing closure that takes the error of the instance. 497 | /// 498 | /// - Returns: A `DownloadResponse` instance containing the result of the transform. 499 | public func flatMapError(_ transform: (Error) throws -> E) -> DownloadResponse { 500 | var response = DownloadResponse( 501 | request: request, 502 | response: self.response, 503 | temporaryURL: temporaryURL, 504 | destinationURL: destinationURL, 505 | resumeData: resumeData, 506 | result: result.flatMapError(transform), 507 | timeline: timeline 508 | ) 509 | 510 | response._metrics = _metrics 511 | 512 | return response 513 | } 514 | } 515 | 516 | // MARK: - 517 | 518 | protocol Response { 519 | /// The task metrics containing the request / response statistics. 520 | var _metrics: AnyObject? { get set } 521 | mutating func add(_ metrics: AnyObject?) 522 | } 523 | 524 | extension Response { 525 | mutating func add(_ metrics: AnyObject?) { 526 | #if !os(watchOS) 527 | guard #available(iOS 10.0, macOS 10.12, tvOS 10.0, *) else { return } 528 | guard let metrics = metrics as? URLSessionTaskMetrics else { return } 529 | 530 | _metrics = metrics 531 | #endif 532 | } 533 | } 534 | 535 | // MARK: - 536 | 537 | @available(iOS 10.0, macOS 10.12, tvOS 10.0, *) 538 | extension DefaultDataResponse: Response { 539 | #if !os(watchOS) 540 | /// The task metrics containing the request / response statistics. 541 | public var metrics: URLSessionTaskMetrics? { return _metrics as? URLSessionTaskMetrics } 542 | #endif 543 | } 544 | 545 | @available(iOS 10.0, macOS 10.12, tvOS 10.0, *) 546 | extension DataResponse: Response { 547 | #if !os(watchOS) 548 | /// The task metrics containing the request / response statistics. 549 | public var metrics: URLSessionTaskMetrics? { return _metrics as? URLSessionTaskMetrics } 550 | #endif 551 | } 552 | 553 | @available(iOS 10.0, macOS 10.12, tvOS 10.0, *) 554 | extension DefaultDownloadResponse: Response { 555 | #if !os(watchOS) 556 | /// The task metrics containing the request / response statistics. 557 | public var metrics: URLSessionTaskMetrics? { return _metrics as? URLSessionTaskMetrics } 558 | #endif 559 | } 560 | 561 | @available(iOS 10.0, macOS 10.12, tvOS 10.0, *) 562 | extension DownloadResponse: Response { 563 | #if !os(watchOS) 564 | /// The task metrics containing the request / response statistics. 565 | public var metrics: URLSessionTaskMetrics? { return _metrics as? URLSessionTaskMetrics } 566 | #endif 567 | } 568 | -------------------------------------------------------------------------------- /StaticPods/Alamofire 4.8.1/Source/Result.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Result.swift 3 | // 4 | // Copyright (c) 2014 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 | 25 | import Foundation 26 | 27 | /// Used to represent whether a request was successful or encountered an error. 28 | /// 29 | /// - success: The request and all post processing operations were successful resulting in the serialization of the 30 | /// provided associated value. 31 | /// 32 | /// - failure: The request encountered an error resulting in a failure. The associated values are the original data 33 | /// provided by the server as well as the error that caused the failure. 34 | internal enum Result { 35 | case success(Value) 36 | case failure(Error) 37 | 38 | /// Returns `true` if the result is a success, `false` otherwise. 39 | public var isSuccess: Bool { 40 | switch self { 41 | case .success: 42 | return true 43 | case .failure: 44 | return false 45 | } 46 | } 47 | 48 | /// Returns `true` if the result is a failure, `false` otherwise. 49 | public var isFailure: Bool { 50 | return !isSuccess 51 | } 52 | 53 | /// Returns the associated value if the result is a success, `nil` otherwise. 54 | public var value: Value? { 55 | switch self { 56 | case .success(let value): 57 | return value 58 | case .failure: 59 | return nil 60 | } 61 | } 62 | 63 | /// Returns the associated error value if the result is a failure, `nil` otherwise. 64 | public var error: Error? { 65 | switch self { 66 | case .success: 67 | return nil 68 | case .failure(let error): 69 | return error 70 | } 71 | } 72 | } 73 | 74 | // MARK: - CustomStringConvertible 75 | 76 | extension Result: CustomStringConvertible { 77 | /// The textual representation used when written to an output stream, which includes whether the result was a 78 | /// success or failure. 79 | public var description: String { 80 | switch self { 81 | case .success: 82 | return "SUCCESS" 83 | case .failure: 84 | return "FAILURE" 85 | } 86 | } 87 | } 88 | 89 | // MARK: - CustomDebugStringConvertible 90 | 91 | extension Result: CustomDebugStringConvertible { 92 | /// The debug textual representation used when written to an output stream, which includes whether the result was a 93 | /// success or failure in addition to the value or error. 94 | public var debugDescription: String { 95 | switch self { 96 | case .success(let value): 97 | return "SUCCESS: \(value)" 98 | case .failure(let error): 99 | return "FAILURE: \(error)" 100 | } 101 | } 102 | } 103 | 104 | // MARK: - Functional APIs 105 | 106 | extension Result { 107 | /// Creates a `Result` instance from the result of a closure. 108 | /// 109 | /// A failure result is created when the closure throws, and a success result is created when the closure 110 | /// succeeds without throwing an error. 111 | /// 112 | /// func someString() throws -> String { ... } 113 | /// 114 | /// let result = Result(value: { 115 | /// return try someString() 116 | /// }) 117 | /// 118 | /// // The type of result is Result 119 | /// 120 | /// The trailing closure syntax is also supported: 121 | /// 122 | /// let result = Result { try someString() } 123 | /// 124 | /// - parameter value: The closure to execute and create the result for. 125 | public init(value: () throws -> Value) { 126 | do { 127 | self = try .success(value()) 128 | } catch { 129 | self = .failure(error) 130 | } 131 | } 132 | 133 | /// Returns the success value, or throws the failure error. 134 | /// 135 | /// let possibleString: Result = .success("success") 136 | /// try print(possibleString.unwrap()) 137 | /// // Prints "success" 138 | /// 139 | /// let noString: Result = .failure(error) 140 | /// try print(noString.unwrap()) 141 | /// // Throws error 142 | public func unwrap() throws -> Value { 143 | switch self { 144 | case .success(let value): 145 | return value 146 | case .failure(let error): 147 | throw error 148 | } 149 | } 150 | 151 | /// Evaluates the specified closure when the `Result` is a success, passing the unwrapped value as a parameter. 152 | /// 153 | /// Use the `map` method with a closure that does not throw. For example: 154 | /// 155 | /// let possibleData: Result = .success(Data()) 156 | /// let possibleInt = possibleData.map { $0.count } 157 | /// try print(possibleInt.unwrap()) 158 | /// // Prints "0" 159 | /// 160 | /// let noData: Result = .failure(error) 161 | /// let noInt = noData.map { $0.count } 162 | /// try print(noInt.unwrap()) 163 | /// // Throws error 164 | /// 165 | /// - parameter transform: A closure that takes the success value of the `Result` instance. 166 | /// 167 | /// - returns: A `Result` containing the result of the given closure. If this instance is a failure, returns the 168 | /// same failure. 169 | public func map(_ transform: (Value) -> T) -> Result { 170 | switch self { 171 | case .success(let value): 172 | return .success(transform(value)) 173 | case .failure(let error): 174 | return .failure(error) 175 | } 176 | } 177 | 178 | /// Evaluates the specified closure when the `Result` is a success, passing the unwrapped value as a parameter. 179 | /// 180 | /// Use the `flatMap` method with a closure that may throw an error. For example: 181 | /// 182 | /// let possibleData: Result = .success(Data(...)) 183 | /// let possibleObject = possibleData.flatMap { 184 | /// try JSONSerialization.jsonObject(with: $0) 185 | /// } 186 | /// 187 | /// - parameter transform: A closure that takes the success value of the instance. 188 | /// 189 | /// - returns: A `Result` containing the result of the given closure. If this instance is a failure, returns the 190 | /// same failure. 191 | public func flatMap(_ transform: (Value) throws -> T) -> Result { 192 | switch self { 193 | case .success(let value): 194 | do { 195 | return try .success(transform(value)) 196 | } catch { 197 | return .failure(error) 198 | } 199 | case .failure(let error): 200 | return .failure(error) 201 | } 202 | } 203 | 204 | /// Evaluates the specified closure when the `Result` is a failure, passing the unwrapped error as a parameter. 205 | /// 206 | /// Use the `mapError` function with a closure that does not throw. For example: 207 | /// 208 | /// let possibleData: Result = .failure(someError) 209 | /// let withMyError: Result = possibleData.mapError { MyError.error($0) } 210 | /// 211 | /// - Parameter transform: A closure that takes the error of the instance. 212 | /// - Returns: A `Result` instance containing the result of the transform. If this instance is a success, returns 213 | /// the same instance. 214 | public func mapError(_ transform: (Error) -> T) -> Result { 215 | switch self { 216 | case .failure(let error): 217 | return .failure(transform(error)) 218 | case .success: 219 | return self 220 | } 221 | } 222 | 223 | /// Evaluates the specified closure when the `Result` is a failure, passing the unwrapped error as a parameter. 224 | /// 225 | /// Use the `flatMapError` function with a closure that may throw an error. For example: 226 | /// 227 | /// let possibleData: Result = .success(Data(...)) 228 | /// let possibleObject = possibleData.flatMapError { 229 | /// try someFailableFunction(taking: $0) 230 | /// } 231 | /// 232 | /// - Parameter transform: A throwing closure that takes the error of the instance. 233 | /// 234 | /// - Returns: A `Result` instance containing the result of the transform. If this instance is a success, returns 235 | /// the same instance. 236 | public func flatMapError(_ transform: (Error) throws -> T) -> Result { 237 | switch self { 238 | case .failure(let error): 239 | do { 240 | return try .failure(transform(error)) 241 | } catch { 242 | return .failure(error) 243 | } 244 | case .success: 245 | return self 246 | } 247 | } 248 | 249 | /// Evaluates the specified closure when the `Result` is a success, passing the unwrapped value as a parameter. 250 | /// 251 | /// Use the `withValue` function to evaluate the passed closure without modifying the `Result` instance. 252 | /// 253 | /// - Parameter closure: A closure that takes the success value of this instance. 254 | /// - Returns: This `Result` instance, unmodified. 255 | @discardableResult 256 | public func withValue(_ closure: (Value) throws -> Void) rethrows -> Result { 257 | if case let .success(value) = self { try closure(value) } 258 | 259 | return self 260 | } 261 | 262 | /// Evaluates the specified closure when the `Result` is a failure, passing the unwrapped error as a parameter. 263 | /// 264 | /// Use the `withError` function to evaluate the passed closure without modifying the `Result` instance. 265 | /// 266 | /// - Parameter closure: A closure that takes the success value of this instance. 267 | /// - Returns: This `Result` instance, unmodified. 268 | @discardableResult 269 | public func withError(_ closure: (Error) throws -> Void) rethrows -> Result { 270 | if case let .failure(error) = self { try closure(error) } 271 | 272 | return self 273 | } 274 | 275 | /// Evaluates the specified closure when the `Result` is a success. 276 | /// 277 | /// Use the `ifSuccess` function to evaluate the passed closure without modifying the `Result` instance. 278 | /// 279 | /// - Parameter closure: A `Void` closure. 280 | /// - Returns: This `Result` instance, unmodified. 281 | @discardableResult 282 | public func ifSuccess(_ closure: () throws -> Void) rethrows -> Result { 283 | if isSuccess { try closure() } 284 | 285 | return self 286 | } 287 | 288 | /// Evaluates the specified closure when the `Result` is a failure. 289 | /// 290 | /// Use the `ifFailure` function to evaluate the passed closure without modifying the `Result` instance. 291 | /// 292 | /// - Parameter closure: A `Void` closure. 293 | /// - Returns: This `Result` instance, unmodified. 294 | @discardableResult 295 | public func ifFailure(_ closure: () throws -> Void) rethrows -> Result { 296 | if isFailure { try closure() } 297 | 298 | return self 299 | } 300 | } 301 | -------------------------------------------------------------------------------- /StaticPods/Alamofire 4.8.1/Source/ServerTrustPolicy.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ServerTrustPolicy.swift 3 | // 4 | // Copyright (c) 2014 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 | 25 | import Foundation 26 | 27 | /// Responsible for managing the mapping of `ServerTrustPolicy` objects to a given host. 28 | open class ServerTrustPolicyManager { 29 | /// The dictionary of policies mapped to a particular host. 30 | public let policies: [String: ServerTrustPolicy] 31 | 32 | /// Initializes the `ServerTrustPolicyManager` instance with the given policies. 33 | /// 34 | /// Since different servers and web services can have different leaf certificates, intermediate and even root 35 | /// certficates, it is important to have the flexibility to specify evaluation policies on a per host basis. This 36 | /// allows for scenarios such as using default evaluation for host1, certificate pinning for host2, public key 37 | /// pinning for host3 and disabling evaluation for host4. 38 | /// 39 | /// - parameter policies: A dictionary of all policies mapped to a particular host. 40 | /// 41 | /// - returns: The new `ServerTrustPolicyManager` instance. 42 | public init(policies: [String: ServerTrustPolicy]) { 43 | self.policies = policies 44 | } 45 | 46 | /// Returns the `ServerTrustPolicy` for the given host if applicable. 47 | /// 48 | /// By default, this method will return the policy that perfectly matches the given host. Subclasses could override 49 | /// this method and implement more complex mapping implementations such as wildcards. 50 | /// 51 | /// - parameter host: The host to use when searching for a matching policy. 52 | /// 53 | /// - returns: The server trust policy for the given host if found. 54 | open func serverTrustPolicy(forHost host: String) -> ServerTrustPolicy? { 55 | return policies[host] 56 | } 57 | } 58 | 59 | // MARK: - 60 | 61 | extension URLSession { 62 | private struct AssociatedKeys { 63 | static var managerKey = "URLSession.ServerTrustPolicyManager" 64 | } 65 | 66 | public var serverTrustPolicyManager: ServerTrustPolicyManager? { 67 | get { 68 | return objc_getAssociatedObject(self, &AssociatedKeys.managerKey) as? ServerTrustPolicyManager 69 | } 70 | set (manager) { 71 | objc_setAssociatedObject(self, &AssociatedKeys.managerKey, manager, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) 72 | } 73 | } 74 | } 75 | 76 | // MARK: - ServerTrustPolicy 77 | 78 | /// The `ServerTrustPolicy` evaluates the server trust generally provided by an `NSURLAuthenticationChallenge` when 79 | /// connecting to a server over a secure HTTPS connection. The policy configuration then evaluates the server trust 80 | /// with a given set of criteria to determine whether the server trust is valid and the connection should be made. 81 | /// 82 | /// Using pinned certificates or public keys for evaluation helps prevent man-in-the-middle (MITM) attacks and other 83 | /// vulnerabilities. Applications dealing with sensitive customer data or financial information are strongly encouraged 84 | /// to route all communication over an HTTPS connection with pinning enabled. 85 | /// 86 | /// - performDefaultEvaluation: Uses the default server trust evaluation while allowing you to control whether to 87 | /// validate the host provided by the challenge. Applications are encouraged to always 88 | /// validate the host in production environments to guarantee the validity of the server's 89 | /// certificate chain. 90 | /// 91 | /// - performRevokedEvaluation: Uses the default and revoked server trust evaluations allowing you to control whether to 92 | /// validate the host provided by the challenge as well as specify the revocation flags for 93 | /// testing for revoked certificates. Apple platforms did not start testing for revoked 94 | /// certificates automatically until iOS 10.1, macOS 10.12 and tvOS 10.1 which is 95 | /// demonstrated in our TLS tests. Applications are encouraged to always validate the host 96 | /// in production environments to guarantee the validity of the server's certificate chain. 97 | /// 98 | /// - pinCertificates: Uses the pinned certificates to validate the server trust. The server trust is 99 | /// considered valid if one of the pinned certificates match one of the server certificates. 100 | /// By validating both the certificate chain and host, certificate pinning provides a very 101 | /// secure form of server trust validation mitigating most, if not all, MITM attacks. 102 | /// Applications are encouraged to always validate the host and require a valid certificate 103 | /// chain in production environments. 104 | /// 105 | /// - pinPublicKeys: Uses the pinned public keys to validate the server trust. The server trust is considered 106 | /// valid if one of the pinned public keys match one of the server certificate public keys. 107 | /// By validating both the certificate chain and host, public key pinning provides a very 108 | /// secure form of server trust validation mitigating most, if not all, MITM attacks. 109 | /// Applications are encouraged to always validate the host and require a valid certificate 110 | /// chain in production environments. 111 | /// 112 | /// - disableEvaluation: Disables all evaluation which in turn will always consider any server trust as valid. 113 | /// 114 | /// - customEvaluation: Uses the associated closure to evaluate the validity of the server trust. 115 | public enum ServerTrustPolicy { 116 | case performDefaultEvaluation(validateHost: Bool) 117 | case performRevokedEvaluation(validateHost: Bool, revocationFlags: CFOptionFlags) 118 | case pinCertificates(certificates: [SecCertificate], validateCertificateChain: Bool, validateHost: Bool) 119 | case pinPublicKeys(publicKeys: [SecKey], validateCertificateChain: Bool, validateHost: Bool) 120 | case disableEvaluation 121 | case customEvaluation((_ serverTrust: SecTrust, _ host: String) -> Bool) 122 | 123 | // MARK: - Bundle Location 124 | 125 | /// Returns all certificates within the given bundle with a `.cer` file extension. 126 | /// 127 | /// - parameter bundle: The bundle to search for all `.cer` files. 128 | /// 129 | /// - returns: All certificates within the given bundle. 130 | public static func certificates(in bundle: Bundle = Bundle.main) -> [SecCertificate] { 131 | var certificates: [SecCertificate] = [] 132 | 133 | let paths = Set([".cer", ".CER", ".crt", ".CRT", ".der", ".DER"].map { fileExtension in 134 | bundle.paths(forResourcesOfType: fileExtension, inDirectory: nil) 135 | }.joined()) 136 | 137 | for path in paths { 138 | if 139 | let certificateData = try? Data(contentsOf: URL(fileURLWithPath: path)) as CFData, 140 | let certificate = SecCertificateCreateWithData(nil, certificateData) 141 | { 142 | certificates.append(certificate) 143 | } 144 | } 145 | 146 | return certificates 147 | } 148 | 149 | /// Returns all public keys within the given bundle with a `.cer` file extension. 150 | /// 151 | /// - parameter bundle: The bundle to search for all `*.cer` files. 152 | /// 153 | /// - returns: All public keys within the given bundle. 154 | public static func publicKeys(in bundle: Bundle = Bundle.main) -> [SecKey] { 155 | var publicKeys: [SecKey] = [] 156 | 157 | for certificate in certificates(in: bundle) { 158 | if let publicKey = publicKey(for: certificate) { 159 | publicKeys.append(publicKey) 160 | } 161 | } 162 | 163 | return publicKeys 164 | } 165 | 166 | // MARK: - Evaluation 167 | 168 | /// Evaluates whether the server trust is valid for the given host. 169 | /// 170 | /// - parameter serverTrust: The server trust to evaluate. 171 | /// - parameter host: The host of the challenge protection space. 172 | /// 173 | /// - returns: Whether the server trust is valid. 174 | public func evaluate(_ serverTrust: SecTrust, forHost host: String) -> Bool { 175 | var serverTrustIsValid = false 176 | 177 | switch self { 178 | case let .performDefaultEvaluation(validateHost): 179 | let policy = SecPolicyCreateSSL(true, validateHost ? host as CFString : nil) 180 | SecTrustSetPolicies(serverTrust, policy) 181 | 182 | serverTrustIsValid = trustIsValid(serverTrust) 183 | case let .performRevokedEvaluation(validateHost, revocationFlags): 184 | let defaultPolicy = SecPolicyCreateSSL(true, validateHost ? host as CFString : nil) 185 | let revokedPolicy = SecPolicyCreateRevocation(revocationFlags) 186 | SecTrustSetPolicies(serverTrust, [defaultPolicy, revokedPolicy] as CFTypeRef) 187 | 188 | serverTrustIsValid = trustIsValid(serverTrust) 189 | case let .pinCertificates(pinnedCertificates, validateCertificateChain, validateHost): 190 | if validateCertificateChain { 191 | let policy = SecPolicyCreateSSL(true, validateHost ? host as CFString : nil) 192 | SecTrustSetPolicies(serverTrust, policy) 193 | 194 | SecTrustSetAnchorCertificates(serverTrust, pinnedCertificates as CFArray) 195 | SecTrustSetAnchorCertificatesOnly(serverTrust, true) 196 | 197 | serverTrustIsValid = trustIsValid(serverTrust) 198 | } else { 199 | let serverCertificatesDataArray = certificateData(for: serverTrust) 200 | let pinnedCertificatesDataArray = certificateData(for: pinnedCertificates) 201 | 202 | outerLoop: for serverCertificateData in serverCertificatesDataArray { 203 | for pinnedCertificateData in pinnedCertificatesDataArray { 204 | if serverCertificateData == pinnedCertificateData { 205 | serverTrustIsValid = true 206 | break outerLoop 207 | } 208 | } 209 | } 210 | } 211 | case let .pinPublicKeys(pinnedPublicKeys, validateCertificateChain, validateHost): 212 | var certificateChainEvaluationPassed = true 213 | 214 | if validateCertificateChain { 215 | let policy = SecPolicyCreateSSL(true, validateHost ? host as CFString : nil) 216 | SecTrustSetPolicies(serverTrust, policy) 217 | 218 | certificateChainEvaluationPassed = trustIsValid(serverTrust) 219 | } 220 | 221 | if certificateChainEvaluationPassed { 222 | outerLoop: for serverPublicKey in ServerTrustPolicy.publicKeys(for: serverTrust) as [AnyObject] { 223 | for pinnedPublicKey in pinnedPublicKeys as [AnyObject] { 224 | if serverPublicKey.isEqual(pinnedPublicKey) { 225 | serverTrustIsValid = true 226 | break outerLoop 227 | } 228 | } 229 | } 230 | } 231 | case .disableEvaluation: 232 | serverTrustIsValid = true 233 | case let .customEvaluation(closure): 234 | serverTrustIsValid = closure(serverTrust, host) 235 | } 236 | 237 | return serverTrustIsValid 238 | } 239 | 240 | // MARK: - Private - Trust Validation 241 | 242 | private func trustIsValid(_ trust: SecTrust) -> Bool { 243 | var isValid = false 244 | 245 | var result = SecTrustResultType.invalid 246 | let status = SecTrustEvaluate(trust, &result) 247 | 248 | if status == errSecSuccess { 249 | let unspecified = SecTrustResultType.unspecified 250 | let proceed = SecTrustResultType.proceed 251 | 252 | 253 | isValid = result == unspecified || result == proceed 254 | } 255 | 256 | return isValid 257 | } 258 | 259 | // MARK: - Private - Certificate Data 260 | 261 | private func certificateData(for trust: SecTrust) -> [Data] { 262 | var certificates: [SecCertificate] = [] 263 | 264 | for index in 0.. [Data] { 274 | return certificates.map { SecCertificateCopyData($0) as Data } 275 | } 276 | 277 | // MARK: - Private - Public Key Extraction 278 | 279 | private static func publicKeys(for trust: SecTrust) -> [SecKey] { 280 | var publicKeys: [SecKey] = [] 281 | 282 | for index in 0.. SecKey? { 295 | var publicKey: SecKey? 296 | 297 | let policy = SecPolicyCreateBasicX509() 298 | var trust: SecTrust? 299 | let trustCreationStatus = SecTrustCreateWithCertificates(certificate, policy, &trust) 300 | 301 | if let trust = trust, trustCreationStatus == errSecSuccess { 302 | publicKey = SecTrustCopyPublicKey(trust) 303 | } 304 | 305 | return publicKey 306 | } 307 | } 308 | -------------------------------------------------------------------------------- /StaticPods/Alamofire 4.8.1/Source/TaskDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TaskDelegate.swift 3 | // 4 | // Copyright (c) 2014 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 | 25 | import Foundation 26 | 27 | /// The task delegate is responsible for handling all delegate callbacks for the underlying task as well as 28 | /// executing all operations attached to the serial operation queue upon task completion. 29 | open class TaskDelegate: NSObject { 30 | 31 | // MARK: Properties 32 | 33 | /// The serial operation queue used to execute all operations after the task completes. 34 | public let queue: OperationQueue 35 | 36 | /// The data returned by the server. 37 | public var data: Data? { return nil } 38 | 39 | /// The error generated throughout the lifecyle of the task. 40 | public var error: Error? 41 | 42 | var task: URLSessionTask? { 43 | set { 44 | taskLock.lock(); defer { taskLock.unlock() } 45 | _task = newValue 46 | } 47 | get { 48 | taskLock.lock(); defer { taskLock.unlock() } 49 | return _task 50 | } 51 | } 52 | 53 | var initialResponseTime: CFAbsoluteTime? 54 | var credential: URLCredential? 55 | var metrics: AnyObject? // URLSessionTaskMetrics 56 | 57 | private var _task: URLSessionTask? { 58 | didSet { reset() } 59 | } 60 | 61 | private let taskLock = NSLock() 62 | 63 | // MARK: Lifecycle 64 | 65 | init(task: URLSessionTask?) { 66 | _task = task 67 | 68 | self.queue = { 69 | let operationQueue = OperationQueue() 70 | 71 | operationQueue.maxConcurrentOperationCount = 1 72 | operationQueue.isSuspended = true 73 | operationQueue.qualityOfService = .utility 74 | 75 | return operationQueue 76 | }() 77 | } 78 | 79 | func reset() { 80 | error = nil 81 | initialResponseTime = nil 82 | } 83 | 84 | // MARK: URLSessionTaskDelegate 85 | 86 | var taskWillPerformHTTPRedirection: ((URLSession, URLSessionTask, HTTPURLResponse, URLRequest) -> URLRequest?)? 87 | var taskDidReceiveChallenge: ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))? 88 | var taskNeedNewBodyStream: ((URLSession, URLSessionTask) -> InputStream?)? 89 | var taskDidCompleteWithError: ((URLSession, URLSessionTask, Error?) -> Void)? 90 | 91 | @objc(URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:) 92 | func urlSession( 93 | _ session: URLSession, 94 | task: URLSessionTask, 95 | willPerformHTTPRedirection response: HTTPURLResponse, 96 | newRequest request: URLRequest, 97 | completionHandler: @escaping (URLRequest?) -> Void) 98 | { 99 | var redirectRequest: URLRequest? = request 100 | 101 | if let taskWillPerformHTTPRedirection = taskWillPerformHTTPRedirection { 102 | redirectRequest = taskWillPerformHTTPRedirection(session, task, response, request) 103 | } 104 | 105 | completionHandler(redirectRequest) 106 | } 107 | 108 | @objc(URLSession:task:didReceiveChallenge:completionHandler:) 109 | func urlSession( 110 | _ session: URLSession, 111 | task: URLSessionTask, 112 | didReceive challenge: URLAuthenticationChallenge, 113 | completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) 114 | { 115 | var disposition: URLSession.AuthChallengeDisposition = .performDefaultHandling 116 | var credential: URLCredential? 117 | 118 | if let taskDidReceiveChallenge = taskDidReceiveChallenge { 119 | (disposition, credential) = taskDidReceiveChallenge(session, task, challenge) 120 | } else if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust { 121 | let host = challenge.protectionSpace.host 122 | 123 | if 124 | let serverTrustPolicy = session.serverTrustPolicyManager?.serverTrustPolicy(forHost: host), 125 | let serverTrust = challenge.protectionSpace.serverTrust 126 | { 127 | if serverTrustPolicy.evaluate(serverTrust, forHost: host) { 128 | disposition = .useCredential 129 | credential = URLCredential(trust: serverTrust) 130 | } else { 131 | disposition = .cancelAuthenticationChallenge 132 | } 133 | } 134 | } else { 135 | if challenge.previousFailureCount > 0 { 136 | disposition = .rejectProtectionSpace 137 | } else { 138 | credential = self.credential ?? session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace) 139 | 140 | if credential != nil { 141 | disposition = .useCredential 142 | } 143 | } 144 | } 145 | 146 | completionHandler(disposition, credential) 147 | } 148 | 149 | @objc(URLSession:task:needNewBodyStream:) 150 | func urlSession( 151 | _ session: URLSession, 152 | task: URLSessionTask, 153 | needNewBodyStream completionHandler: @escaping (InputStream?) -> Void) 154 | { 155 | var bodyStream: InputStream? 156 | 157 | if let taskNeedNewBodyStream = taskNeedNewBodyStream { 158 | bodyStream = taskNeedNewBodyStream(session, task) 159 | } 160 | 161 | completionHandler(bodyStream) 162 | } 163 | 164 | @objc(URLSession:task:didCompleteWithError:) 165 | func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { 166 | if let taskDidCompleteWithError = taskDidCompleteWithError { 167 | taskDidCompleteWithError(session, task, error) 168 | } else { 169 | if let error = error { 170 | if self.error == nil { self.error = error } 171 | 172 | if 173 | let downloadDelegate = self as? DownloadTaskDelegate, 174 | let resumeData = (error as NSError).userInfo[NSURLSessionDownloadTaskResumeData] as? Data 175 | { 176 | downloadDelegate.resumeData = resumeData 177 | } 178 | } 179 | 180 | queue.isSuspended = false 181 | } 182 | } 183 | } 184 | 185 | // MARK: - 186 | 187 | class DataTaskDelegate: TaskDelegate, URLSessionDataDelegate { 188 | 189 | // MARK: Properties 190 | 191 | var dataTask: URLSessionDataTask { return task as! URLSessionDataTask } 192 | 193 | override var data: Data? { 194 | if dataStream != nil { 195 | return nil 196 | } else { 197 | return mutableData 198 | } 199 | } 200 | 201 | var progress: Progress 202 | var progressHandler: (closure: Request.ProgressHandler, queue: DispatchQueue)? 203 | 204 | var dataStream: ((_ data: Data) -> Void)? 205 | 206 | private var totalBytesReceived: Int64 = 0 207 | private var mutableData: Data 208 | 209 | private var expectedContentLength: Int64? 210 | 211 | // MARK: Lifecycle 212 | 213 | override init(task: URLSessionTask?) { 214 | mutableData = Data() 215 | progress = Progress(totalUnitCount: 0) 216 | 217 | super.init(task: task) 218 | } 219 | 220 | override func reset() { 221 | super.reset() 222 | 223 | progress = Progress(totalUnitCount: 0) 224 | totalBytesReceived = 0 225 | mutableData = Data() 226 | expectedContentLength = nil 227 | } 228 | 229 | // MARK: URLSessionDataDelegate 230 | 231 | var dataTaskDidReceiveResponse: ((URLSession, URLSessionDataTask, URLResponse) -> URLSession.ResponseDisposition)? 232 | var dataTaskDidBecomeDownloadTask: ((URLSession, URLSessionDataTask, URLSessionDownloadTask) -> Void)? 233 | var dataTaskDidReceiveData: ((URLSession, URLSessionDataTask, Data) -> Void)? 234 | var dataTaskWillCacheResponse: ((URLSession, URLSessionDataTask, CachedURLResponse) -> CachedURLResponse?)? 235 | 236 | func urlSession( 237 | _ session: URLSession, 238 | dataTask: URLSessionDataTask, 239 | didReceive response: URLResponse, 240 | completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) 241 | { 242 | var disposition: URLSession.ResponseDisposition = .allow 243 | 244 | expectedContentLength = response.expectedContentLength 245 | 246 | if let dataTaskDidReceiveResponse = dataTaskDidReceiveResponse { 247 | disposition = dataTaskDidReceiveResponse(session, dataTask, response) 248 | } 249 | 250 | completionHandler(disposition) 251 | } 252 | 253 | func urlSession( 254 | _ session: URLSession, 255 | dataTask: URLSessionDataTask, 256 | didBecome downloadTask: URLSessionDownloadTask) 257 | { 258 | dataTaskDidBecomeDownloadTask?(session, dataTask, downloadTask) 259 | } 260 | 261 | func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) { 262 | if initialResponseTime == nil { initialResponseTime = CFAbsoluteTimeGetCurrent() } 263 | 264 | if let dataTaskDidReceiveData = dataTaskDidReceiveData { 265 | dataTaskDidReceiveData(session, dataTask, data) 266 | } else { 267 | if let dataStream = dataStream { 268 | dataStream(data) 269 | } else { 270 | mutableData.append(data) 271 | } 272 | 273 | let bytesReceived = Int64(data.count) 274 | totalBytesReceived += bytesReceived 275 | let totalBytesExpected = dataTask.response?.expectedContentLength ?? NSURLSessionTransferSizeUnknown 276 | 277 | progress.totalUnitCount = totalBytesExpected 278 | progress.completedUnitCount = totalBytesReceived 279 | 280 | if let progressHandler = progressHandler { 281 | progressHandler.queue.async { progressHandler.closure(self.progress) } 282 | } 283 | } 284 | } 285 | 286 | func urlSession( 287 | _ session: URLSession, 288 | dataTask: URLSessionDataTask, 289 | willCacheResponse proposedResponse: CachedURLResponse, 290 | completionHandler: @escaping (CachedURLResponse?) -> Void) 291 | { 292 | var cachedResponse: CachedURLResponse? = proposedResponse 293 | 294 | if let dataTaskWillCacheResponse = dataTaskWillCacheResponse { 295 | cachedResponse = dataTaskWillCacheResponse(session, dataTask, proposedResponse) 296 | } 297 | 298 | completionHandler(cachedResponse) 299 | } 300 | } 301 | 302 | // MARK: - 303 | 304 | class DownloadTaskDelegate: TaskDelegate, URLSessionDownloadDelegate { 305 | 306 | // MARK: Properties 307 | 308 | var downloadTask: URLSessionDownloadTask { return task as! URLSessionDownloadTask } 309 | 310 | var progress: Progress 311 | var progressHandler: (closure: Request.ProgressHandler, queue: DispatchQueue)? 312 | 313 | var resumeData: Data? 314 | override var data: Data? { return resumeData } 315 | 316 | var destination: DownloadRequest.DownloadFileDestination? 317 | 318 | var temporaryURL: URL? 319 | var destinationURL: URL? 320 | 321 | var fileURL: URL? { return destination != nil ? destinationURL : temporaryURL } 322 | 323 | // MARK: Lifecycle 324 | 325 | override init(task: URLSessionTask?) { 326 | progress = Progress(totalUnitCount: 0) 327 | super.init(task: task) 328 | } 329 | 330 | override func reset() { 331 | super.reset() 332 | 333 | progress = Progress(totalUnitCount: 0) 334 | resumeData = nil 335 | } 336 | 337 | // MARK: URLSessionDownloadDelegate 338 | 339 | var downloadTaskDidFinishDownloadingToURL: ((URLSession, URLSessionDownloadTask, URL) -> URL)? 340 | var downloadTaskDidWriteData: ((URLSession, URLSessionDownloadTask, Int64, Int64, Int64) -> Void)? 341 | var downloadTaskDidResumeAtOffset: ((URLSession, URLSessionDownloadTask, Int64, Int64) -> Void)? 342 | 343 | func urlSession( 344 | _ session: URLSession, 345 | downloadTask: URLSessionDownloadTask, 346 | didFinishDownloadingTo location: URL) 347 | { 348 | temporaryURL = location 349 | 350 | guard 351 | let destination = destination, 352 | let response = downloadTask.response as? HTTPURLResponse 353 | else { return } 354 | 355 | let result = destination(location, response) 356 | let destinationURL = result.destinationURL 357 | let options = result.options 358 | 359 | self.destinationURL = destinationURL 360 | 361 | do { 362 | if options.contains(.removePreviousFile), FileManager.default.fileExists(atPath: destinationURL.path) { 363 | try FileManager.default.removeItem(at: destinationURL) 364 | } 365 | 366 | if options.contains(.createIntermediateDirectories) { 367 | let directory = destinationURL.deletingLastPathComponent() 368 | try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true) 369 | } 370 | 371 | try FileManager.default.moveItem(at: location, to: destinationURL) 372 | } catch { 373 | self.error = error 374 | } 375 | } 376 | 377 | func urlSession( 378 | _ session: URLSession, 379 | downloadTask: URLSessionDownloadTask, 380 | didWriteData bytesWritten: Int64, 381 | totalBytesWritten: Int64, 382 | totalBytesExpectedToWrite: Int64) 383 | { 384 | if initialResponseTime == nil { initialResponseTime = CFAbsoluteTimeGetCurrent() } 385 | 386 | if let downloadTaskDidWriteData = downloadTaskDidWriteData { 387 | downloadTaskDidWriteData( 388 | session, 389 | downloadTask, 390 | bytesWritten, 391 | totalBytesWritten, 392 | totalBytesExpectedToWrite 393 | ) 394 | } else { 395 | progress.totalUnitCount = totalBytesExpectedToWrite 396 | progress.completedUnitCount = totalBytesWritten 397 | 398 | if let progressHandler = progressHandler { 399 | progressHandler.queue.async { progressHandler.closure(self.progress) } 400 | } 401 | } 402 | } 403 | 404 | func urlSession( 405 | _ session: URLSession, 406 | downloadTask: URLSessionDownloadTask, 407 | didResumeAtOffset fileOffset: Int64, 408 | expectedTotalBytes: Int64) 409 | { 410 | if let downloadTaskDidResumeAtOffset = downloadTaskDidResumeAtOffset { 411 | downloadTaskDidResumeAtOffset(session, downloadTask, fileOffset, expectedTotalBytes) 412 | } else { 413 | progress.totalUnitCount = expectedTotalBytes 414 | progress.completedUnitCount = fileOffset 415 | } 416 | } 417 | } 418 | 419 | // MARK: - 420 | 421 | class UploadTaskDelegate: DataTaskDelegate { 422 | 423 | // MARK: Properties 424 | 425 | var uploadTask: URLSessionUploadTask { return task as! URLSessionUploadTask } 426 | 427 | var uploadProgress: Progress 428 | var uploadProgressHandler: (closure: Request.ProgressHandler, queue: DispatchQueue)? 429 | 430 | // MARK: Lifecycle 431 | 432 | override init(task: URLSessionTask?) { 433 | uploadProgress = Progress(totalUnitCount: 0) 434 | super.init(task: task) 435 | } 436 | 437 | override func reset() { 438 | super.reset() 439 | uploadProgress = Progress(totalUnitCount: 0) 440 | } 441 | 442 | // MARK: URLSessionTaskDelegate 443 | 444 | var taskDidSendBodyData: ((URLSession, URLSessionTask, Int64, Int64, Int64) -> Void)? 445 | 446 | func URLSession( 447 | _ session: URLSession, 448 | task: URLSessionTask, 449 | didSendBodyData bytesSent: Int64, 450 | totalBytesSent: Int64, 451 | totalBytesExpectedToSend: Int64) 452 | { 453 | if initialResponseTime == nil { initialResponseTime = CFAbsoluteTimeGetCurrent() } 454 | 455 | if let taskDidSendBodyData = taskDidSendBodyData { 456 | taskDidSendBodyData(session, task, bytesSent, totalBytesSent, totalBytesExpectedToSend) 457 | } else { 458 | uploadProgress.totalUnitCount = totalBytesExpectedToSend 459 | uploadProgress.completedUnitCount = totalBytesSent 460 | 461 | if let uploadProgressHandler = uploadProgressHandler { 462 | uploadProgressHandler.queue.async { uploadProgressHandler.closure(self.uploadProgress) } 463 | } 464 | } 465 | } 466 | } 467 | -------------------------------------------------------------------------------- /StaticPods/Alamofire 4.8.1/Source/Timeline.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Timeline.swift 3 | // 4 | // Copyright (c) 2014 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 | 25 | import Foundation 26 | 27 | /// Responsible for computing the timing metrics for the complete lifecycle of a `Request`. 28 | public struct Timeline { 29 | /// The time the request was initialized. 30 | public let requestStartTime: CFAbsoluteTime 31 | 32 | /// The time the first bytes were received from or sent to the server. 33 | public let initialResponseTime: CFAbsoluteTime 34 | 35 | /// The time when the request was completed. 36 | public let requestCompletedTime: CFAbsoluteTime 37 | 38 | /// The time when the response serialization was completed. 39 | public let serializationCompletedTime: CFAbsoluteTime 40 | 41 | /// The time interval in seconds from the time the request started to the initial response from the server. 42 | public let latency: TimeInterval 43 | 44 | /// The time interval in seconds from the time the request started to the time the request completed. 45 | public let requestDuration: TimeInterval 46 | 47 | /// The time interval in seconds from the time the request completed to the time response serialization completed. 48 | public let serializationDuration: TimeInterval 49 | 50 | /// The time interval in seconds from the time the request started to the time response serialization completed. 51 | public let totalDuration: TimeInterval 52 | 53 | /// Creates a new `Timeline` instance with the specified request times. 54 | /// 55 | /// - parameter requestStartTime: The time the request was initialized. Defaults to `0.0`. 56 | /// - parameter initialResponseTime: The time the first bytes were received from or sent to the server. 57 | /// Defaults to `0.0`. 58 | /// - parameter requestCompletedTime: The time when the request was completed. Defaults to `0.0`. 59 | /// - parameter serializationCompletedTime: The time when the response serialization was completed. Defaults 60 | /// to `0.0`. 61 | /// 62 | /// - returns: The new `Timeline` instance. 63 | public init( 64 | requestStartTime: CFAbsoluteTime = 0.0, 65 | initialResponseTime: CFAbsoluteTime = 0.0, 66 | requestCompletedTime: CFAbsoluteTime = 0.0, 67 | serializationCompletedTime: CFAbsoluteTime = 0.0) 68 | { 69 | self.requestStartTime = requestStartTime 70 | self.initialResponseTime = initialResponseTime 71 | self.requestCompletedTime = requestCompletedTime 72 | self.serializationCompletedTime = serializationCompletedTime 73 | 74 | self.latency = initialResponseTime - requestStartTime 75 | self.requestDuration = requestCompletedTime - requestStartTime 76 | self.serializationDuration = serializationCompletedTime - requestCompletedTime 77 | self.totalDuration = serializationCompletedTime - requestStartTime 78 | } 79 | } 80 | 81 | // MARK: - CustomStringConvertible 82 | 83 | extension Timeline: CustomStringConvertible { 84 | /// The textual representation used when written to an output stream, which includes the latency, the request 85 | /// duration and the total duration. 86 | public var description: String { 87 | let latency = String(format: "%.3f", self.latency) 88 | let requestDuration = String(format: "%.3f", self.requestDuration) 89 | let serializationDuration = String(format: "%.3f", self.serializationDuration) 90 | let totalDuration = String(format: "%.3f", self.totalDuration) 91 | 92 | // NOTE: Had to move to string concatenation due to memory leak filed as rdar://26761490. Once memory leak is 93 | // fixed, we should move back to string interpolation by reverting commit 7d4a43b1. 94 | let timings = [ 95 | "\"Latency\": " + latency + " secs", 96 | "\"Request Duration\": " + requestDuration + " secs", 97 | "\"Serialization Duration\": " + serializationDuration + " secs", 98 | "\"Total Duration\": " + totalDuration + " secs" 99 | ] 100 | 101 | return "Timeline: { " + timings.joined(separator: ", ") + " }" 102 | } 103 | } 104 | 105 | // MARK: - CustomDebugStringConvertible 106 | 107 | extension Timeline: CustomDebugStringConvertible { 108 | /// The textual representation used when written to an output stream, which includes the request start time, the 109 | /// initial response time, the request completed time, the serialization completed time, the latency, the request 110 | /// duration and the total duration. 111 | public var debugDescription: String { 112 | let requestStartTime = String(format: "%.3f", self.requestStartTime) 113 | let initialResponseTime = String(format: "%.3f", self.initialResponseTime) 114 | let requestCompletedTime = String(format: "%.3f", self.requestCompletedTime) 115 | let serializationCompletedTime = String(format: "%.3f", self.serializationCompletedTime) 116 | let latency = String(format: "%.3f", self.latency) 117 | let requestDuration = String(format: "%.3f", self.requestDuration) 118 | let serializationDuration = String(format: "%.3f", self.serializationDuration) 119 | let totalDuration = String(format: "%.3f", self.totalDuration) 120 | 121 | // NOTE: Had to move to string concatenation due to memory leak filed as rdar://26761490. Once memory leak is 122 | // fixed, we should move back to string interpolation by reverting commit 7d4a43b1. 123 | let timings = [ 124 | "\"Request Start Time\": " + requestStartTime, 125 | "\"Initial Response Time\": " + initialResponseTime, 126 | "\"Request Completed Time\": " + requestCompletedTime, 127 | "\"Serialization Completed Time\": " + serializationCompletedTime, 128 | "\"Latency\": " + latency + " secs", 129 | "\"Request Duration\": " + requestDuration + " secs", 130 | "\"Serialization Duration\": " + serializationDuration + " secs", 131 | "\"Total Duration\": " + totalDuration + " secs" 132 | ] 133 | 134 | return "Timeline: { " + timings.joined(separator: ", ") + " }" 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /StaticPods/Alamofire 4.8.1/Source/Validation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Validation.swift 3 | // 4 | // Copyright (c) 2014 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 | 25 | import Foundation 26 | 27 | extension Request { 28 | 29 | // MARK: Helper Types 30 | 31 | fileprivate typealias ErrorReason = AFError.ResponseValidationFailureReason 32 | 33 | /// Used to represent whether validation was successful or encountered an error resulting in a failure. 34 | /// 35 | /// - success: The validation was successful. 36 | /// - failure: The validation failed encountering the provided error. 37 | public enum ValidationResult { 38 | case success 39 | case failure(Error) 40 | } 41 | 42 | fileprivate struct MIMEType { 43 | let type: String 44 | let subtype: String 45 | 46 | var isWildcard: Bool { return type == "*" && subtype == "*" } 47 | 48 | init?(_ string: String) { 49 | let components: [String] = { 50 | let stripped = string.trimmingCharacters(in: .whitespacesAndNewlines) 51 | 52 | #if swift(>=3.2) 53 | let split = stripped[..<(stripped.range(of: ";")?.lowerBound ?? stripped.endIndex)] 54 | #else 55 | let split = stripped.substring(to: stripped.range(of: ";")?.lowerBound ?? stripped.endIndex) 56 | #endif 57 | 58 | return split.components(separatedBy: "/") 59 | }() 60 | 61 | if let type = components.first, let subtype = components.last { 62 | self.type = type 63 | self.subtype = subtype 64 | } else { 65 | return nil 66 | } 67 | } 68 | 69 | func matches(_ mime: MIMEType) -> Bool { 70 | switch (type, subtype) { 71 | case (mime.type, mime.subtype), (mime.type, "*"), ("*", mime.subtype), ("*", "*"): 72 | return true 73 | default: 74 | return false 75 | } 76 | } 77 | } 78 | 79 | // MARK: Properties 80 | 81 | fileprivate var acceptableStatusCodes: [Int] { return Array(200..<300) } 82 | 83 | fileprivate var acceptableContentTypes: [String] { 84 | if let accept = request?.value(forHTTPHeaderField: "Accept") { 85 | return accept.components(separatedBy: ",") 86 | } 87 | 88 | return ["*/*"] 89 | } 90 | 91 | // MARK: Status Code 92 | 93 | fileprivate func validate( 94 | statusCode acceptableStatusCodes: S, 95 | response: HTTPURLResponse) 96 | -> ValidationResult 97 | where S.Iterator.Element == Int 98 | { 99 | if acceptableStatusCodes.contains(response.statusCode) { 100 | return .success 101 | } else { 102 | let reason: ErrorReason = .unacceptableStatusCode(code: response.statusCode) 103 | return .failure(AFError.responseValidationFailed(reason: reason)) 104 | } 105 | } 106 | 107 | // MARK: Content Type 108 | 109 | fileprivate func validate( 110 | contentType acceptableContentTypes: S, 111 | response: HTTPURLResponse, 112 | data: Data?) 113 | -> ValidationResult 114 | where S.Iterator.Element == String 115 | { 116 | guard let data = data, data.count > 0 else { return .success } 117 | 118 | guard 119 | let responseContentType = response.mimeType, 120 | let responseMIMEType = MIMEType(responseContentType) 121 | else { 122 | for contentType in acceptableContentTypes { 123 | if let mimeType = MIMEType(contentType), mimeType.isWildcard { 124 | return .success 125 | } 126 | } 127 | 128 | let error: AFError = { 129 | let reason: ErrorReason = .missingContentType(acceptableContentTypes: Array(acceptableContentTypes)) 130 | return AFError.responseValidationFailed(reason: reason) 131 | }() 132 | 133 | return .failure(error) 134 | } 135 | 136 | for contentType in acceptableContentTypes { 137 | if let acceptableMIMEType = MIMEType(contentType), acceptableMIMEType.matches(responseMIMEType) { 138 | return .success 139 | } 140 | } 141 | 142 | let error: AFError = { 143 | let reason: ErrorReason = .unacceptableContentType( 144 | acceptableContentTypes: Array(acceptableContentTypes), 145 | responseContentType: responseContentType 146 | ) 147 | 148 | return AFError.responseValidationFailed(reason: reason) 149 | }() 150 | 151 | return .failure(error) 152 | } 153 | } 154 | 155 | // MARK: - 156 | 157 | extension DataRequest { 158 | /// A closure used to validate a request that takes a URL request, a URL response and data, and returns whether the 159 | /// request was valid. 160 | public typealias Validation = (URLRequest?, HTTPURLResponse, Data?) -> ValidationResult 161 | 162 | /// Validates the request, using the specified closure. 163 | /// 164 | /// If validation fails, subsequent calls to response handlers will have an associated error. 165 | /// 166 | /// - parameter validation: A closure to validate the request. 167 | /// 168 | /// - returns: The request. 169 | @discardableResult 170 | public func validate(_ validation: @escaping Validation) -> Self { 171 | let validationExecution: () -> Void = { [unowned self] in 172 | if 173 | let response = self.response, 174 | self.delegate.error == nil, 175 | case let .failure(error) = validation(self.request, response, self.delegate.data) 176 | { 177 | self.delegate.error = error 178 | } 179 | } 180 | 181 | validations.append(validationExecution) 182 | 183 | return self 184 | } 185 | 186 | /// Validates that the response has a status code in the specified sequence. 187 | /// 188 | /// If validation fails, subsequent calls to response handlers will have an associated error. 189 | /// 190 | /// - parameter range: The range of acceptable status codes. 191 | /// 192 | /// - returns: The request. 193 | @discardableResult 194 | public func validate(statusCode acceptableStatusCodes: S) -> Self where S.Iterator.Element == Int { 195 | return validate { [unowned self] _, response, _ in 196 | return self.validate(statusCode: acceptableStatusCodes, response: response) 197 | } 198 | } 199 | 200 | /// Validates that the response has a content type in the specified sequence. 201 | /// 202 | /// If validation fails, subsequent calls to response handlers will have an associated error. 203 | /// 204 | /// - parameter contentType: The acceptable content types, which may specify wildcard types and/or subtypes. 205 | /// 206 | /// - returns: The request. 207 | @discardableResult 208 | public func validate(contentType acceptableContentTypes: S) -> Self where S.Iterator.Element == String { 209 | return validate { [unowned self] _, response, data in 210 | return self.validate(contentType: acceptableContentTypes, response: response, data: data) 211 | } 212 | } 213 | 214 | /// Validates that the response has a status code in the default acceptable range of 200...299, and that the content 215 | /// type matches any specified in the Accept HTTP header field. 216 | /// 217 | /// If validation fails, subsequent calls to response handlers will have an associated error. 218 | /// 219 | /// - returns: The request. 220 | @discardableResult 221 | public func validate() -> Self { 222 | return validate(statusCode: self.acceptableStatusCodes).validate(contentType: self.acceptableContentTypes) 223 | } 224 | } 225 | 226 | // MARK: - 227 | 228 | extension DownloadRequest { 229 | /// A closure used to validate a request that takes a URL request, a URL response, a temporary URL and a 230 | /// destination URL, and returns whether the request was valid. 231 | public typealias Validation = ( 232 | _ request: URLRequest?, 233 | _ response: HTTPURLResponse, 234 | _ temporaryURL: URL?, 235 | _ destinationURL: URL?) 236 | -> ValidationResult 237 | 238 | /// Validates the request, using the specified closure. 239 | /// 240 | /// If validation fails, subsequent calls to response handlers will have an associated error. 241 | /// 242 | /// - parameter validation: A closure to validate the request. 243 | /// 244 | /// - returns: The request. 245 | @discardableResult 246 | public func validate(_ validation: @escaping Validation) -> Self { 247 | let validationExecution: () -> Void = { [unowned self] in 248 | let request = self.request 249 | let temporaryURL = self.downloadDelegate.temporaryURL 250 | let destinationURL = self.downloadDelegate.destinationURL 251 | 252 | if 253 | let response = self.response, 254 | self.delegate.error == nil, 255 | case let .failure(error) = validation(request, response, temporaryURL, destinationURL) 256 | { 257 | self.delegate.error = error 258 | } 259 | } 260 | 261 | validations.append(validationExecution) 262 | 263 | return self 264 | } 265 | 266 | /// Validates that the response has a status code in the specified sequence. 267 | /// 268 | /// If validation fails, subsequent calls to response handlers will have an associated error. 269 | /// 270 | /// - parameter range: The range of acceptable status codes. 271 | /// 272 | /// - returns: The request. 273 | @discardableResult 274 | public func validate(statusCode acceptableStatusCodes: S) -> Self where S.Iterator.Element == Int { 275 | return validate { [unowned self] _, response, _, _ in 276 | return self.validate(statusCode: acceptableStatusCodes, response: response) 277 | } 278 | } 279 | 280 | /// Validates that the response has a content type in the specified sequence. 281 | /// 282 | /// If validation fails, subsequent calls to response handlers will have an associated error. 283 | /// 284 | /// - parameter contentType: The acceptable content types, which may specify wildcard types and/or subtypes. 285 | /// 286 | /// - returns: The request. 287 | @discardableResult 288 | public func validate(contentType acceptableContentTypes: S) -> Self where S.Iterator.Element == String { 289 | return validate { [unowned self] _, response, _, _ in 290 | let fileURL = self.downloadDelegate.fileURL 291 | 292 | guard let validFileURL = fileURL else { 293 | return .failure(AFError.responseValidationFailed(reason: .dataFileNil)) 294 | } 295 | 296 | do { 297 | let data = try Data(contentsOf: validFileURL) 298 | return self.validate(contentType: acceptableContentTypes, response: response, data: data) 299 | } catch { 300 | return .failure(AFError.responseValidationFailed(reason: .dataFileReadFailed(at: validFileURL))) 301 | } 302 | } 303 | } 304 | 305 | /// Validates that the response has a status code in the default acceptable range of 200...299, and that the content 306 | /// type matches any specified in the Accept HTTP header field. 307 | /// 308 | /// If validation fails, subsequent calls to response handlers will have an associated error. 309 | /// 310 | /// - returns: The request. 311 | @discardableResult 312 | public func validate() -> Self { 313 | return validate(statusCode: self.acceptableStatusCodes).validate(contentType: self.acceptableContentTypes) 314 | } 315 | } 316 | -------------------------------------------------------------------------------- /StaticPods/Reqres/ReqresLicense/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Jan Mísař 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /StaticPods/Reqres/Source/Reqres.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Reqres.swift 3 | // Reqres 4 | // 5 | // Created by Jan Mísař on 05/27/2016. 6 | // Copyright (c) 2016 Jan Mísař. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | let ReqresRequestHandledKey = "ReqresRequestHandledKey" 12 | let ReqresRequestTimeKey = "ReqresRequestTimeKey" 13 | 14 | open class Reqres: URLProtocol, URLSessionDelegate { 15 | var dataTask: URLSessionDataTask? 16 | var newRequest: NSMutableURLRequest? 17 | 18 | public static var sessionDelegate: URLSessionDelegate? 19 | 20 | public static var policyManager: ServerTrustPolicyManager? 21 | 22 | public static var allowUTF8Emoji: Bool = true 23 | 24 | public static var logger: ReqresLogging = ReqresDefaultLogger() 25 | 26 | open class func register() { 27 | URLProtocol.registerClass(self) 28 | } 29 | 30 | open class func unregister() { 31 | URLProtocol.unregisterClass(self) 32 | } 33 | 34 | open class func defaultSessionConfiguration() -> URLSessionConfiguration { 35 | let config = URLSessionConfiguration.default 36 | config.protocolClasses?.insert(Reqres.self, at: 0) 37 | return config 38 | } 39 | 40 | // MARK: - NSURLProtocol 41 | 42 | open override class func canInit(with request: URLRequest) -> Bool { 43 | guard self.property(forKey: ReqresRequestHandledKey, in: request) == nil && self.logger.logLevel != .none else { 44 | return false 45 | } 46 | return true 47 | } 48 | 49 | open override class func canonicalRequest(for request: URLRequest) -> URLRequest { 50 | return request 51 | } 52 | 53 | open override class func requestIsCacheEquivalent(_ a: URLRequest, to b: URLRequest) -> Bool { 54 | return super.requestIsCacheEquivalent(a, to: b) 55 | } 56 | 57 | open override func startLoading() { 58 | guard let req = (request as NSURLRequest).mutableCopy() as? NSMutableURLRequest, newRequest == nil else { return } 59 | 60 | self.newRequest = req 61 | 62 | URLProtocol.setProperty(true, forKey: ReqresRequestHandledKey, in: newRequest!) 63 | URLProtocol.setProperty(Date(), forKey: ReqresRequestTimeKey, in: newRequest!) 64 | 65 | let session = URLSession(configuration: .default, delegate: Reqres.sessionDelegate ?? self, delegateQueue: nil) 66 | session.serverTrustPolicyManager = Reqres.policyManager 67 | dataTask = session.dataTask(with: request) { [weak self] data, response, error in 68 | guard let `self` = self else { return } 69 | 70 | if let error = error { 71 | self.client?.urlProtocol(self, didFailWithError: error) 72 | self.logError(self.request, error: error as NSError) 73 | 74 | return 75 | } 76 | 77 | guard let response = response, let data = data else { return } 78 | 79 | self.client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .allowed) 80 | self.client?.urlProtocol(self, didLoad: data) 81 | self.client?.urlProtocolDidFinishLoading(self) 82 | self.logResponse(response, method: nil, data: data) 83 | } 84 | dataTask?.resume() 85 | 86 | logRequest(newRequest! as URLRequest) 87 | } 88 | 89 | open override func stopLoading() { 90 | dataTask?.cancel() 91 | } 92 | 93 | // MARK: - Logging 94 | 95 | open func logError(_ request: URLRequest, error: NSError) { 96 | 97 | var s = "" 98 | 99 | if type(of: self).allowUTF8Emoji { 100 | s += "⚠️ " 101 | } 102 | 103 | if let method = request.httpMethod { 104 | s += "\(method) " 105 | } 106 | 107 | if let url = request.url?.absoluteString { 108 | s += "\(url) " 109 | } 110 | 111 | s += "ERROR: \(error.localizedDescription)" 112 | 113 | if let reason = error.localizedFailureReason { 114 | s += "\nReason: \(reason)" 115 | } 116 | 117 | if let suggestion = error.localizedRecoverySuggestion { 118 | s += "\nSuggestion: \(suggestion)" 119 | } 120 | 121 | type(of: self).logger.logError(s) 122 | } 123 | 124 | open func logRequest(_ request: URLRequest) { 125 | 126 | var s = "" 127 | 128 | if type(of: self).allowUTF8Emoji { 129 | s += "⬆️ " 130 | } 131 | 132 | if let method = request.httpMethod { 133 | s += "\(method) " 134 | } 135 | 136 | if let url = request.url?.absoluteString { 137 | s += "'\(url)' " 138 | } 139 | 140 | if type(of: self).logger.logLevel == .verbose { 141 | 142 | if let headers = request.allHTTPHeaderFields, headers.count > 0 { 143 | s += "\n" + logHeaders(headers as [String : AnyObject]) 144 | } 145 | 146 | s += "\nBody: \(bodyString(request.httpBodyData))" 147 | 148 | type(of: self).logger.logVerbose(s) 149 | } else { 150 | 151 | type(of: self).logger.logLight(s) 152 | } 153 | } 154 | 155 | open func logResponse(_ response: URLResponse, method: String?, data: Data? = nil) { 156 | 157 | var s = "" 158 | 159 | if type(of: self).allowUTF8Emoji { 160 | s += "⬇️ " 161 | } 162 | 163 | if let method = method { 164 | s += "\(method)" 165 | } else if let method = newRequest?.httpMethod { 166 | s += "\(method) " 167 | } 168 | 169 | if let url = response.url?.absoluteString { 170 | s += "'\(url)' " 171 | } 172 | 173 | if let httpResponse = response as? HTTPURLResponse { 174 | s += "(" 175 | if type(of: self).allowUTF8Emoji { 176 | let iconNumber = Int(floor(Double(httpResponse.statusCode) / 100.0)) 177 | if let iconString = statusIcons[iconNumber] { 178 | s += "\(iconString) " 179 | } 180 | } 181 | 182 | s += "\(httpResponse.statusCode)" 183 | if let statusString = statusStrings[httpResponse.statusCode] { 184 | s += " \(statusString)" 185 | } 186 | s += ")" 187 | 188 | if let startDate = URLProtocol.property(forKey: ReqresRequestTimeKey, in: newRequest! as URLRequest) as? Date { 189 | let difference = fabs(startDate.timeIntervalSinceNow) 190 | s += String(format: " [time: %.5f s]", difference) 191 | } 192 | } 193 | 194 | if type(of: self).logger.logLevel == .verbose { 195 | 196 | if let headers = (response as? HTTPURLResponse)?.allHeaderFields as? [String: AnyObject], headers.count > 0 { 197 | s += "\n" + logHeaders(headers) 198 | } 199 | 200 | s += "\nBody: \(bodyString(data))" 201 | 202 | type(of: self).logger.logVerbose(s) 203 | } else { 204 | 205 | type(of: self).logger.logLight(s) 206 | } 207 | } 208 | 209 | open func logHeaders(_ headers: [String: AnyObject]) -> String { 210 | var s = "Headers: [\n" 211 | for (key, value) in headers { 212 | s += "\t\(key) : \(value)\n" 213 | } 214 | s += "]" 215 | return s 216 | } 217 | 218 | func bodyString(_ body: Data?) -> String { 219 | 220 | if let body = body { 221 | if let json = try? JSONSerialization.jsonObject(with: body, options: .mutableContainers), 222 | let pretty = try? JSONSerialization.data(withJSONObject: json, options: .prettyPrinted), 223 | let string = String(data: pretty, encoding: String.Encoding.utf8) { 224 | return string 225 | } else if let string = String(data: body, encoding: String.Encoding.utf8) { 226 | return string 227 | } else { 228 | return body.description 229 | } 230 | } else { 231 | return "nil" 232 | } 233 | } 234 | } 235 | 236 | extension URLRequest { 237 | var httpBodyData: Data? { 238 | 239 | guard let stream = httpBodyStream else { 240 | return httpBody 241 | } 242 | 243 | let data = NSMutableData() 244 | stream.open() 245 | let bufferSize = 4_096 246 | let buffer = UnsafeMutablePointer.allocate(capacity: bufferSize) 247 | while stream.hasBytesAvailable { 248 | let bytesRead = stream.read(buffer, maxLength: bufferSize) 249 | if bytesRead > 0 { 250 | let readData = Data(bytes: UnsafePointer(buffer), count: bytesRead) 251 | data.append(readData) 252 | } else if bytesRead < 0 { 253 | print("error occured while reading HTTPBodyStream: \(bytesRead)") 254 | } else { 255 | break 256 | } 257 | } 258 | stream.close() 259 | return data as Data 260 | } 261 | } 262 | 263 | let statusIcons = [ 264 | 1: "ℹ️", 265 | 2: "✅", 266 | 3: "⤴️", 267 | 4: "⛔️", 268 | 5: "❌" 269 | ] 270 | 271 | let statusStrings = [ 272 | // 1xx (Informational) 273 | 100: "Continue", 274 | 101: "Switching Protocols", 275 | 102: "Processing", 276 | 277 | // 2xx (Success) 278 | 200: "OK", 279 | 201: "Created", 280 | 202: "Accepted", 281 | 203: "Non-Authoritative Information", 282 | 204: "No Content", 283 | 205: "Reset Content", 284 | 206: "Partial Content", 285 | 207: "Multi-Status", 286 | 208: "Already Reported", 287 | 226: "IM Used", 288 | 289 | // 3xx (Redirection) 290 | 300: "Multiple Choices", 291 | 301: "Moved Permanently", 292 | 302: "Found", 293 | 303: "See Other", 294 | 304: "Not Modified", 295 | 305: "Use Proxy", 296 | 306: "Switch Proxy", 297 | 307: "Temporary Redirect", 298 | 308: "Permanent Redirect", 299 | 300 | // 4xx (Client Error) 301 | 400: "Bad Request", 302 | 401: "Unauthorized", 303 | 402: "Payment Required", 304 | 403: "Forbidden", 305 | 404: "Not Found", 306 | 405: "Method Not Allowed", 307 | 406: "Not Acceptable", 308 | 407: "Proxy Authentication Required", 309 | 408: "Request Timeout", 310 | 409: "Conflict", 311 | 410: "Gone", 312 | 411: "Length Required", 313 | 412: "Precondition Failed", 314 | 413: "Request Entity Too Large", 315 | 414: "Request-URI Too Long", 316 | 415: "Unsupported Media Type", 317 | 416: "Requested Range Not Satisfiable", 318 | 417: "Expectation Failed", 319 | 418: "I'm a teapot", 320 | 420: "Enhance Your Calm", 321 | 422: "Unprocessable Entity", 322 | 423: "Locked", 323 | 424: "Method Failure", 324 | 425: "Unordered Collection", 325 | 426: "Upgrade Required", 326 | 428: "Precondition Required", 327 | 429: "Too Many Requests", 328 | 431: "Request Header Fields Too Large", 329 | 451: "Unavailable For Legal Reasons", 330 | 331 | // 5xx (Server Error) 332 | 500: "Internal Server Error", 333 | 501: "Not Implemented", 334 | 502: "Bad Gateway", 335 | 503: "Service Unavailable", 336 | 504: "Gateway Timeout", 337 | 505: "HTTP Version Not Supported", 338 | 506: "Variant Also Negotiates", 339 | 507: "Insufficient Storage", 340 | 508: "Loop Detected", 341 | 509: "Bandwidth Limit Exceeded", 342 | 510: "Not Extended", 343 | 511: "Network Authentication Required" 344 | ] 345 | -------------------------------------------------------------------------------- /StaticPods/Reqres/Source/ReqresDefaultLogger.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ReqresDefaultLogger.swift 3 | // Reqres 4 | // 5 | // Created by Jan Mísař on 02.08.16. 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | open class ReqresDefaultLogger: ReqresLogging { 12 | 13 | private let dateFormatter: DateFormatter = { 14 | let df = DateFormatter() 15 | df.dateFormat = "YYYY-MM-dd HH:mm:ss.SSS" 16 | return df 17 | }() 18 | 19 | open var logLevel: LogLevel = .verbose 20 | 21 | open func logVerbose(_ message: String) { 22 | logMessage(message) 23 | } 24 | 25 | open func logLight(_ message: String) { 26 | logMessage(message) 27 | } 28 | 29 | open func logError(_ message: String) { 30 | logMessage(message) 31 | } 32 | 33 | private func logMessage(_ message: String) { 34 | print("[" + dateFormatter.string(from: Date()) + "] " + message) 35 | } 36 | } 37 | 38 | open class ReqresDefaultNSLogger: ReqresLogging { 39 | 40 | open var logLevel: LogLevel = .verbose 41 | 42 | open func logVerbose(_ message: String) { 43 | print(message) 44 | } 45 | 46 | open func logLight(_ message: String) { 47 | print(message) 48 | } 49 | 50 | open func logError(_ message: String) { 51 | print(message) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /StaticPods/Reqres/Source/ReqresLogging.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ReqresLogging.swift 3 | // Reqres 4 | // 5 | // Created by Jan Mísař on 02.08.16. 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | public enum LogLevel { 12 | case none 13 | case light 14 | case verbose 15 | } 16 | 17 | public protocol ReqresLogging { 18 | var logLevel: LogLevel { get set } 19 | 20 | func logVerbose(_ message: String) 21 | func logLight(_ message: String) 22 | func logError(_ message: String) 23 | } 24 | --------------------------------------------------------------------------------