├── .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 | 
4 |
5 |
6 | [](https://img.shields.io/cocoapods/v/PocketNet.svg)
7 | [](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 |
--------------------------------------------------------------------------------