diff --git a/OrderScheduling.xcworkspace/xcuserdata/zd.xcuserdatad/UserInterfaceState.xcuserstate b/OrderScheduling.xcworkspace/xcuserdata/zd.xcuserdatad/UserInterfaceState.xcuserstate index c186676..9dc74de 100644 Binary files a/OrderScheduling.xcworkspace/xcuserdata/zd.xcuserdatad/UserInterfaceState.xcuserstate and b/OrderScheduling.xcworkspace/xcuserdata/zd.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/OrderScheduling.xcworkspace/xcuserdata/zd.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/OrderScheduling.xcworkspace/xcuserdata/zd.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist index e22a5af..f15e02e 100644 --- a/OrderScheduling.xcworkspace/xcuserdata/zd.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/OrderScheduling.xcworkspace/xcuserdata/zd.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -3569,22 +3569,6 @@ landmarkType = "7"> - - - - - - - - - - - - @@ -4903,8 +4855,8 @@ filePath = "OrderScheduling/Global/User/UserPermission.swift" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "36" - endingLineNumber = "36" + startingLineNumber = "33" + endingLineNumber = "33" landmarkName = "init()" landmarkType = "7"> @@ -4941,5 +4893,101 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/OrderScheduling/Assets.xcassets/Login/login_backgroundImage.imageset/login_backgroundImage.png b/OrderScheduling/Assets.xcassets/Login/login_backgroundImage.imageset/login_backgroundImage.png index 2e3df52..6be712b 100644 Binary files a/OrderScheduling/Assets.xcassets/Login/login_backgroundImage.imageset/login_backgroundImage.png and b/OrderScheduling/Assets.xcassets/Login/login_backgroundImage.imageset/login_backgroundImage.png differ diff --git a/OrderScheduling/Assets.xcassets/Login/login_backgroundImage.imageset/login_backgroundImage@2x.png b/OrderScheduling/Assets.xcassets/Login/login_backgroundImage.imageset/login_backgroundImage@2x.png index bf049ef..d95ed3f 100644 Binary files a/OrderScheduling/Assets.xcassets/Login/login_backgroundImage.imageset/login_backgroundImage@2x.png and b/OrderScheduling/Assets.xcassets/Login/login_backgroundImage.imageset/login_backgroundImage@2x.png differ diff --git a/OrderScheduling/Assets.xcassets/Login/login_backgroundImage.imageset/login_backgroundImage@3x.png b/OrderScheduling/Assets.xcassets/Login/login_backgroundImage.imageset/login_backgroundImage@3x.png index b878d6a..e17f572 100644 Binary files a/OrderScheduling/Assets.xcassets/Login/login_backgroundImage.imageset/login_backgroundImage@3x.png and b/OrderScheduling/Assets.xcassets/Login/login_backgroundImage.imageset/login_backgroundImage@3x.png differ diff --git a/OrderScheduling/Global/User/UserPermission.swift b/OrderScheduling/Global/User/UserPermission.swift index ad3211e..923b066 100644 --- a/OrderScheduling/Global/User/UserPermission.swift +++ b/OrderScheduling/Global/User/UserPermission.swift @@ -25,103 +25,94 @@ open class UserPermission { public var canSupplierRemarkBtn : Bool = false public var canSupplierAuditEditCostBtn : Bool = false public var canSupplierAuditUploadPhotoBtn : Bool = false - lazy private var alert = CommonAlertView() + private let maxRetryCount = 120 + init() { Observable.combineLatest(relay, USER.refreshTokenSub) - .observe(on: MainScheduler.instance) - .do(onNext: { (_,_) in - UIApplication.shared.dd_keyWindow.rootViewController?.view.dd_showHUD() - }) .flatMapLatest { (_,_) in return RQ.userOperationPermissions() } - .observe(on: MainScheduler.instance) - .do(onNext: { _ in - UIApplication.shared.dd_keyWindow.rootViewController?.view.dd_hideHUD() + .retry(when: { (rxError: Observable) -> Observable in + return rxError.enumerated().flatMap({[weak self] (index,error) -> Observable in + guard index < (self?.maxRetryCount ?? 0) else { + return Observable.error(error) + } + return Observable.timer(RxTimeInterval.seconds(5), scheduler: MainScheduler.instance) + + }) }) .observe(on: MainScheduler.instance) .subscribe(onNext: {[weak self] response in if response?.success == true { - self?.canRejectDispatchHandle = false if response?.data?.contains(where: { value in value == UserOperationPermissionsDataModel.DataEnum.rejectDispatchHandle.rawValue }) == true { self?.canRejectDispatchHandle = true + }else{ + self?.canRejectDispatchHandle = false } - self?.canAcceptDispatchHandle = false if response?.data?.contains(where: { value in value == UserOperationPermissionsDataModel.DataEnum.acceptDispatchHandle.rawValue }) == true { self?.canAcceptDispatchHandle = true + }else{ + self?.canAcceptDispatchHandle = false } - self?.canWaitdispatchBtn = false if response?.data?.contains(where: { value in value == UserOperationPermissionsDataModel.DataEnum.waitdispatchBtn.rawValue }) == true { self?.canWaitdispatchBtn = true + }else{ + self?.canWaitdispatchBtn = false } - self?.canWaitModifyDispatchBtn = false if response?.data?.contains(where: { value in value == UserOperationPermissionsDataModel.DataEnum.waitModifyDispatchBtn.rawValue }) == true { self?.canWaitModifyDispatchBtn = true + }else{ + self?.canWaitModifyDispatchBtn = false } - self?.canDealWith = false if response?.data?.contains(where: { value in value == UserOperationPermissionsDataModel.DataEnum.dealWith.rawValue }) == true { self?.canDealWith = true + }else{ + self?.canDealWith = false } - self?.canSupplierRemarkBtn = false if response?.data?.contains(where: { value in value == UserOperationPermissionsDataModel.DataEnum.supplierRemarkBtn.rawValue }) == true { self?.canSupplierRemarkBtn = true + }else{ + self?.canSupplierRemarkBtn = false } - self?.canSupplierAuditEditCostBtn = false if response?.data?.contains(where: { value in value == UserOperationPermissionsDataModel.DataEnum.supplierAuditEditCostBtn.rawValue }) == true { self?.canSupplierAuditEditCostBtn = true + }else{ + self?.canSupplierAuditEditCostBtn = false } - self?.canSupplierAuditUploadPhotoBtn = false if response?.data?.contains(where: { value in value == UserOperationPermissionsDataModel.DataEnum.supplierAuditUploadPhotoBtn.rawValue }) == true { self?.canSupplierAuditUploadPhotoBtn = true + }else{ + self?.canSupplierAuditUploadPhotoBtn = false } self?.userPermissionRelay.accept(response?.data) - }else{ - if let alert = self?.alert { - alert.contentLabel.text = notObtainUserPermissions - ENTRY.showUserPermissionsEntry(view: alert,name: notObtainUserPermissionsEntry) - } } - }) - .disposed(by: disposeBag) - - alert.sureButton.rx.tap - .observe(on: MainScheduler.instance) - .subscribe(onNext: {[weak self] _ in - ENTRY.dismiss(name: notObtainUserPermissionsEntry) {[weak self] in - self?.relay.accept(nil) - } - }) - .disposed(by: disposeBag) - - alert.cancelButton.rx.tap - .observe(on: MainScheduler.instance) - .subscribe(onNext: { _ in - exit(0) + },onError: { error in + }) .disposed(by: disposeBag) } diff --git a/OrderScheduling/HttpRequestCenter/RequestList.swift b/OrderScheduling/HttpRequestCenter/RequestList.swift index 75a3be6..b8beef3 100644 --- a/OrderScheduling/HttpRequestCenter/RequestList.swift +++ b/OrderScheduling/HttpRequestCenter/RequestList.swift @@ -15,6 +15,9 @@ public let RQ = RequestList.default open class RequestList { public static let `default` = RequestList() + struct DDError : Error { + } + func tokenHeader() -> HTTPHeader { let httpHeader = HTTPHeader.init(name: "Authorization", value: USER.token ?? "") return httpHeader @@ -109,7 +112,13 @@ open class RequestList { } func userOperationPermissions() -> Single?> { - return DDAF.post(urlString: HOST+API.userOperationPermissions,encoding: URLEncodedFormParameterEncoder.default,headers: [tokenHeader()],responseType: ResponseModel<[String]>.self) + return DDAF.post(urlString: HOST+API.userOperationPermissions,encoding: URLEncodedFormParameterEncoder.default,headers: [tokenHeader()],responseType: ResponseModel<[String]>.self) { single, response in + if response.value?.success == true { + single(.success(response.value)) + }else{ + single(.failure(DDError())) + } + } } func vehicleLogout(parameters:P) -> Single?> { diff --git a/Podfile.lock b/Podfile.lock index c26efa5..9a0af78 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,5 +1,5 @@ PODS: - - Alamofire (5.7.1) + - Alamofire (5.8.1) - AMapFoundation-NO-IDFA (1.8.2) - AMapLocation-NO-IDFA (2.9.0): - AMapFoundation-NO-IDFA (>= 1.7.0) @@ -270,7 +270,7 @@ PODS: - DDLogKit_Private - DDMAMapKit_Private/DDMAUtil (0.1.5): - DDMAMapKit_Private/DDMAMap - - DDNetworkingOfAlamofireKit_Private (0.1.8): + - DDNetworkingOfAlamofireKit_Private (0.2.1): - Alamofire - DDLogKit_Private - RxSwift @@ -412,7 +412,7 @@ SPEC REPOS: - ZLPhotoBrowser SPEC CHECKSUMS: - Alamofire: 0123a34370cb170936ae79a8df46cc62b2edeb88 + Alamofire: 3ca42e259043ee0dc5c0cdd76c4bc568b8e42af7 AMapFoundation-NO-IDFA: 6ce0ef596d4eb8d934ff498e56747b6de1247b05 AMapLocation-NO-IDFA: 6839d1543b3138ae594ddd36ab72741dc87df66f AMapNavi-NO-IDFA: 70c724400376bfadcb8ec08b9761f526096cfdb6 @@ -430,7 +430,7 @@ SPEC CHECKSUMS: DDFontKit_Private: 7b8f4ebf0f60622874036202734d8460dc7b3806 DDLogKit_Private: 1ed442cc7be004bd05f27bfda9b525e113df54e0 DDMAMapKit_Private: b378d69f693d6998d136155cd5c81be2e4545fae - DDNetworkingOfAlamofireKit_Private: d65c96f99bc59311d374e7b7a7e8a9e042d9b5ea + DDNetworkingOfAlamofireKit_Private: 652eb70a7d8bac81d77d036fabeb52f807120f6d DDPersistenceKit_Private: c150822543ffa6ece3900178629812f64902ed90 DDProgressHUDKit_Private: 1e219062ddeb7801a4bb13b367efa1f3fbf17f1e DDTimerSwiftKit_Private: cce3fe58b1b581fe4cddb3fb84fcde31b4e83541 diff --git a/Pods/Alamofire/README.md b/Pods/Alamofire/README.md index b0ba4d5..c9adb9f 100644 --- a/Pods/Alamofire/README.md +++ b/Pods/Alamofire/README.md @@ -1,11 +1,10 @@ ![Alamofire: Elegant Networking in Swift](https://raw.githubusercontent.com/Alamofire/Alamofire/master/Resources/AlamofireLogo.png) -[![Swift](https://img.shields.io/badge/Swift-5.5_5.6_5.7_5.8-orange?style=flat-square)](https://img.shields.io/badge/Swift-5.5_5.6_5.7_5.8-Orange?style=flat-square) -[![Platforms](https://img.shields.io/badge/Platforms-macOS_iOS_tvOS_watchOS_Linux_Windows-yellowgreen?style=flat-square)](https://img.shields.io/badge/Platforms-macOS_iOS_tvOS_watchOS_Linux_Windows-Green?style=flat-square) +[![Swift](https://img.shields.io/badge/Swift-5.6_5.7_5.8_5.9-orange?style=flat-square)](https://img.shields.io/badge/Swift-5.6_5.7_5.8_5.9-Orange?style=flat-square) +[![Platforms](https://img.shields.io/badge/Platforms-macOS_iOS_tvOS_watchOS_visionOS_Linux_Windows_Android-yellowgreen?style=flat-square)](https://img.shields.io/badge/Platforms-macOS_iOS_tvOS_watchOS_vision_OS_Linux_Windows_Android-Green?style=flat-square) [![CocoaPods Compatible](https://img.shields.io/cocoapods/v/Alamofire.svg?style=flat-square)](https://img.shields.io/cocoapods/v/Alamofire.svg) [![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat-square)](https://github.com/Carthage/Carthage) [![Swift Package Manager](https://img.shields.io/badge/Swift_Package_Manager-compatible-orange?style=flat-square)](https://img.shields.io/badge/Swift_Package_Manager-compatible-orange?style=flat-square) -[![Twitter](https://img.shields.io/badge/twitter-@AlamofireSF-blue.svg?style=flat-square)](https://twitter.com/AlamofireSF) [![Swift Forums](https://img.shields.io/badge/Swift_Forums-Alamofire-orange?style=flat-square)](https://forums.swift.org/c/related-projects/alamofire/37) Alamofire is an HTTP networking library written in Swift. @@ -52,6 +51,33 @@ Alamofire is an HTTP networking library written in Swift. - [x] Comprehensive Unit and Integration Test Coverage - [x] [Complete Documentation](https://alamofire.github.io/Alamofire) +## Write Requests Fast! + +Alamofire's compact syntax and extensive feature set allow requests with powerful features like automatic retry to be written in just a few lines of code. + +```swift +// Automatic String to URL conversion, Swift concurrency support, and automatic retry. +let response = await AF.request("https://httpbin.org/get", interceptor: .retryPolicy) + // Automatic HTTP Basic Auth. + .authenticate(username: "user", password: "pass") + // Caching customization. + .cacheResponse(using: .cache) + // Redirect customization. + .redirect(using: .follow) + // Validate response code and Content-Type. + .validate() + // Produce a cURL command for the request. + .cURLDescription { description in + print(description) + } + // Automatic Decodable support with background parsing. + .serializingDecodable(DecodableType.self) + // Await the full response with metrics and a parsed body. + .response +// Detailed response description for easy debugging. +debugPrint(response) +``` + ## Component Libraries In order to keep Alamofire focused specifically on core networking implementations, additional component libraries have been created by the [Alamofire Software Foundation](https://github.com/Alamofire/Foundation) to bring additional functionality to the Alamofire ecosystem. @@ -61,21 +87,23 @@ In order to keep Alamofire focused specifically on core networking implementatio ## Requirements -| Platform | Minimum Swift Version | Installation | Status | -| --- | --- | --- | --- | -| iOS 10.0+ / macOS 10.12+ / tvOS 10.0+ / watchOS 3.0+ | 5.5 | [CocoaPods](#cocoapods), [Carthage](#carthage), [Swift Package Manager](#swift-package-manager), [Manual](#manually) | Fully Tested | -| Linux | Latest Only | [Swift Package Manager](#swift-package-manager) | Building But Unsupported | -| Windows | Latest Only | [Swift Package Manager](#swift-package-manager) | Building But Unsupported | +| Platform | Minimum Swift Version | Installation | Status | +| ---------------------------------------------------- | --------------------- | -------------------------------------------------------------------------------------------------------------------- | ------------------------ | +| iOS 10.0+ / macOS 10.12+ / tvOS 10.0+ / watchOS 3.0+ | 5.6 | [CocoaPods](#cocoapods), [Carthage](#carthage), [Swift Package Manager](#swift-package-manager), [Manual](#manually) | Fully Tested | +| Linux | Latest Only | [Swift Package Manager](#swift-package-manager) | Building But Unsupported | +| Windows | Latest Only | [Swift Package Manager](#swift-package-manager) | Building But Unsupported | +| Android | Latest Only | [Swift Package Manager](#swift-package-manager) | Building But Unsupported | #### Known Issues on Linux and Windows -Alamofire builds on Linux and Windows but there are missing features and many issues in the underlying `swift-corelibs-foundation` that prevent full functionality and may cause crashes. These include: +Alamofire builds on Linux, Windows, and Android but there are missing features and many issues in the underlying `swift-corelibs-foundation` that prevent full functionality and may cause crashes. These include: + - `ServerTrustManager` and associated certificate functionality is unavailable, so there is no certificate pinning and no client certificate support. - Various methods of HTTP authentication may crash, including HTTP Basic and HTTP Digest. Crashes may occur if responses contain server challenges. - Cache control through `CachedResponseHandler` and associated APIs is unavailable, as the underlying delegate methods aren't called. - `URLSessionTaskMetrics` are never gathered. -Due to these issues, Alamofire is unsupported on Linux and Windows. Please report any crashes to the [Swift bug reporter](https://bugs.swift.org). +Due to these issues, Alamofire is unsupported on Linux, Windows, and Android. Please report any crashes to the [Swift bug reporter](https://bugs.swift.org). ## Migration Guides @@ -85,11 +113,12 @@ Due to these issues, Alamofire is unsupported on Linux and Windows. Please repor - [Alamofire 2.0 Migration Guide](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Alamofire%202.0%20Migration%20Guide.md) ## Communication + - If you **need help with making network requests** using Alamofire, use [Stack Overflow](https://stackoverflow.com/questions/tagged/alamofire) and tag `alamofire`. - If you need to **find or understand an API**, check [our documentation](http://alamofire.github.io/Alamofire/) or [Apple's documentation for `URLSession`](https://developer.apple.com/documentation/foundation/url_loading_system), on top of which Alamofire is built. - If you need **help with an Alamofire feature**, use [our forum on swift.org](https://forums.swift.org/c/related-projects/alamofire). - If you'd like to **discuss Alamofire best practices**, use [our forum on swift.org](https://forums.swift.org/c/related-projects/alamofire). -- If you'd like to **discuss a feature request**, use [our forum on swift.org](https://forums.swift.org/c/related-projects/alamofire). +- If you'd like to **discuss a feature request**, use [our forum on swift.org](https://forums.swift.org/c/related-projects/alamofire). - If you **found a bug**, open an issue here on GitHub and follow the guide. The more detail the better! ## Installation @@ -112,13 +141,13 @@ github "Alamofire/Alamofire" ### Swift Package Manager -The [Swift Package Manager](https://swift.org/package-manager/) is a tool for automating the distribution of Swift code and is integrated into the `swift` compiler. +The [Swift Package Manager](https://swift.org/package-manager/) is a tool for automating the distribution of Swift code and is integrated into the `swift` compiler. Once you have your Swift package set up, adding Alamofire as a dependency is as easy as adding it to the `dependencies` value of your `Package.swift`. ```swift dependencies: [ - .package(url: "https://github.com/Alamofire/Alamofire.git", .upToNextMajor(from: "5.6.4")) + .package(url: "https://github.com/Alamofire/Alamofire.git", .upToNextMajor(from: "5.8.1")) ] ``` @@ -142,7 +171,7 @@ If you prefer not to use any of the aforementioned dependency managers, you can - Open the new `Alamofire` folder, and drag the `Alamofire.xcodeproj` into the Project Navigator of your application's Xcode project. - > It should appear nested underneath your application's blue project icon. Whether it is above or below all the other Xcode groups does not matter. + > It should appear nested underneath your application's blue project icon. Whether it is above or below all the other Xcode groups does not matter. - Select the `Alamofire.xcodeproj` in the Project Navigator and verify the deployment target matches that of your application target. - Next, select your application project in the Project Navigator (blue project icon) to navigate to the target configuration window and select the application target under the "Targets" heading in the sidebar. @@ -150,11 +179,11 @@ If you prefer not to use any of the aforementioned dependency managers, you can - Click on the `+` button under the "Embedded Binaries" section. - You will see two different `Alamofire.xcodeproj` folders each with two different versions of the `Alamofire.framework` nested inside a `Products` folder. - > It does not matter which `Products` folder you choose from, but it does matter whether you choose the top or bottom `Alamofire.framework`. + > It does not matter which `Products` folder you choose from, but it does matter whether you choose the top or bottom `Alamofire.framework`. - Select the top `Alamofire.framework` for iOS and the bottom one for macOS. - > You can verify which one you selected by inspecting the build log for your project. The build target for `Alamofire` will be listed as `Alamofire iOS`, `Alamofire macOS`, `Alamofire tvOS`, or `Alamofire watchOS`. + > You can verify which one you selected by inspecting the build log for your project. The build target for `Alamofire` will be listed as `Alamofire iOS`, `Alamofire macOS`, `Alamofire tvOS`, or `Alamofire watchOS`. - And that's it! diff --git a/Pods/Alamofire/Source/AFError.swift b/Pods/Alamofire/Source/AFError.swift index 8cd60c7..82a75b5 100644 --- a/Pods/Alamofire/Source/AFError.swift +++ b/Pods/Alamofire/Source/AFError.swift @@ -24,6 +24,10 @@ import Foundation +#if canImport(Security) +import Security +#endif + /// `AFError` is the error type returned by Alamofire. It encompasses a few different types of errors, each with /// their own associated reasons. public enum AFError: Error { @@ -129,7 +133,7 @@ public enum AFError: Error { case invalidEmptyResponse(type: String) } - #if !(os(Linux) || os(Windows)) + #if canImport(Security) /// Underlying reason a server trust evaluation error occurred. public enum ServerTrustFailureReason { /// The output of a server trust evaluation. @@ -211,7 +215,7 @@ public enum AFError: Error { case responseValidationFailed(reason: ResponseValidationFailureReason) /// Response serialization failed. case responseSerializationFailed(reason: ResponseSerializationFailureReason) - #if !(os(Linux) || os(Windows)) + #if canImport(Security) /// `ServerTrustEvaluating` instance threw an error during trust evaluation. case serverTrustEvaluationFailed(reason: ServerTrustFailureReason) #endif @@ -314,7 +318,7 @@ extension AFError { return false } - #if !(os(Linux) || os(Windows)) + #if canImport(Security) /// Returns whether the instance is `.serverTrustEvaluationFailed`. When `true`, the `underlyingError` property will /// contain the associated value. public var isServerTrustEvaluationError: Bool { @@ -393,7 +397,7 @@ extension AFError { return reason.underlyingError case let .responseSerializationFailed(reason): return reason.underlyingError - #if !(os(Linux) || os(Windows)) + #if canImport(Security) case let .serverTrustEvaluationFailed(reason): return reason.underlyingError #endif @@ -451,7 +455,7 @@ extension AFError { return destination } - #if !(os(Linux) || os(Windows)) + #if canImport(Security) /// The download resume data of any underlying network error. Only produced by `DownloadRequest`s. public var downloadResumeData: Data? { (underlyingError as? URLError)?.userInfo[NSURLSessionDownloadTaskResumeData] as? Data @@ -610,7 +614,7 @@ extension AFError.ResponseSerializationFailureReason { } } -#if !(os(Linux) || os(Windows)) +#if canImport(Security) extension AFError.ServerTrustFailureReason { var output: AFError.ServerTrustFailureReason.Output? { switch self { @@ -688,7 +692,7 @@ extension AFError: LocalizedError { """ case let .sessionInvalidated(error): return "Session was invalidated with error: \(error?.localizedDescription ?? "No description.")" - #if !(os(Linux) || os(Windows)) + #if canImport(Security) case let .serverTrustEvaluationFailed(reason): return "Server trust evaluation failed due to reason: \(reason.localizedDescription)" #endif @@ -822,7 +826,7 @@ extension AFError.ResponseValidationFailureReason { } } -#if !(os(Linux) || os(Windows)) +#if canImport(Security) extension AFError.ServerTrustFailureReason { var localizedDescription: String { switch self { diff --git a/Pods/Alamofire/Source/Alamofire.swift b/Pods/Alamofire/Source/Alamofire.swift index 52ea3de..c99fe49 100644 --- a/Pods/Alamofire/Source/Alamofire.swift +++ b/Pods/Alamofire/Source/Alamofire.swift @@ -37,4 +37,4 @@ import Foundation public let AF = Session.default /// Current Alamofire version. Necessary since SPM doesn't use dynamic libraries. Plus this will be more accurate. -let version = "5.7.1" +let version = "5.8.0" diff --git a/Pods/Alamofire/Source/AuthenticationInterceptor.swift b/Pods/Alamofire/Source/AuthenticationInterceptor.swift index c3a3f31..5c88287 100644 --- a/Pods/Alamofire/Source/AuthenticationInterceptor.swift +++ b/Pods/Alamofire/Source/AuthenticationInterceptor.swift @@ -217,15 +217,14 @@ public class AuthenticationInterceptor: RequestInterceptor wh /// The `Credential` used to authenticate requests. public var credential: Credential? { - get { $mutableState.credential } - set { $mutableState.credential = newValue } + get { mutableState.credential } + set { mutableState.credential = newValue } } let authenticator: AuthenticatorType let queue = DispatchQueue(label: "org.alamofire.authentication.inspector") - @Protected - private var mutableState: MutableState + private let mutableState: Protected // MARK: Initialization @@ -242,13 +241,13 @@ public class AuthenticationInterceptor: RequestInterceptor wh credential: Credential? = nil, refreshWindow: RefreshWindow? = RefreshWindow()) { self.authenticator = authenticator - mutableState = MutableState(credential: credential, refreshWindow: refreshWindow) + mutableState = Protected(MutableState(credential: credential, refreshWindow: refreshWindow)) } // MARK: Adapt public func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result) -> Void) { - let adaptResult: AdaptResult = $mutableState.write { mutableState in + let adaptResult: AdaptResult = mutableState.write { mutableState in // Queue the adapt operation if a refresh is already in place. guard !mutableState.isRefreshing else { let operation = AdaptOperation(urlRequest: urlRequest, session: session, completion: completion) @@ -316,7 +315,7 @@ public class AuthenticationInterceptor: RequestInterceptor wh return } - $mutableState.write { mutableState in + mutableState.write { mutableState in mutableState.requestsToRetry.append(completion) guard !mutableState.isRefreshing else { return } @@ -340,7 +339,7 @@ public class AuthenticationInterceptor: RequestInterceptor wh // Dispatch to queue to hop out of the lock in case authenticator.refresh is implemented synchronously. queue.async { self.authenticator.refresh(credential, for: session) { result in - self.$mutableState.write { mutableState in + self.mutableState.write { mutableState in switch result { case let .success(credential): self.handleRefreshSuccess(credential, insideLock: &mutableState) diff --git a/Pods/Alamofire/Source/Combine.swift b/Pods/Alamofire/Source/Combine.swift index 08329fc..79fce0d 100644 --- a/Pods/Alamofire/Source/Combine.swift +++ b/Pods/Alamofire/Source/Combine.swift @@ -22,7 +22,7 @@ // THE SOFTWARE. // -#if !((os(iOS) && (arch(i386) || arch(arm))) || os(Windows) || os(Linux)) +#if !((os(iOS) && (arch(i386) || arch(arm))) || os(Windows) || os(Linux) || os(Android)) import Combine import Dispatch @@ -91,23 +91,22 @@ public struct DataResponsePublisher: Publisher { where Downstream.Input == Output { typealias Failure = Downstream.Failure - @Protected - private var downstream: Downstream? + private let downstream: Protected private let request: DataRequest private let responseHandler: Handler init(request: DataRequest, responseHandler: @escaping Handler, downstream: Downstream) { self.request = request self.responseHandler = responseHandler - self.downstream = downstream + self.downstream = Protected(downstream) } func request(_ demand: Subscribers.Demand) { assert(demand > 0) - guard let downstream = downstream else { return } + guard let downstream = downstream.read({ $0 }) else { return } - self.downstream = nil + self.downstream.write(nil) responseHandler { response in _ = downstream.receive(response) downstream.receive(completion: .finished) @@ -116,7 +115,7 @@ public struct DataResponsePublisher: Publisher { func cancel() { request.cancel() - downstream = nil + downstream.write(nil) } } } @@ -312,23 +311,22 @@ public struct DataStreamPublisher: Publisher { where Downstream.Input == Output { typealias Failure = Downstream.Failure - @Protected - private var downstream: Downstream? + private let downstream: Protected private let request: DataStreamRequest private let streamHandler: Handler init(request: DataStreamRequest, streamHandler: @escaping Handler, downstream: Downstream) { self.request = request self.streamHandler = streamHandler - self.downstream = downstream + self.downstream = Protected(downstream) } func request(_ demand: Subscribers.Demand) { assert(demand > 0) - guard let downstream = downstream else { return } + guard let downstream = downstream.read({ $0 }) else { return } - self.downstream = nil + self.downstream.write(nil) streamHandler { stream in _ = downstream.receive(stream) if case .complete = stream.event { @@ -339,7 +337,7 @@ public struct DataStreamPublisher: Publisher { func cancel() { request.cancel() - downstream = nil + downstream.write(nil) } } } @@ -462,23 +460,22 @@ public struct DownloadResponsePublisher: Publisher { where Downstream.Input == Output { typealias Failure = Downstream.Failure - @Protected - private var downstream: Downstream? + private let downstream: Protected private let request: DownloadRequest private let responseHandler: Handler init(request: DownloadRequest, responseHandler: @escaping Handler, downstream: Downstream) { self.request = request self.responseHandler = responseHandler - self.downstream = downstream + self.downstream = Protected(downstream) } func request(_ demand: Subscribers.Demand) { assert(demand > 0) - guard let downstream = downstream else { return } + guard let downstream = downstream.read({ $0 }) else { return } - self.downstream = nil + self.downstream.write(nil) responseHandler { response in _ = downstream.receive(response) downstream.receive(completion: .finished) @@ -487,7 +484,7 @@ public struct DownloadResponsePublisher: Publisher { func cancel() { request.cancel() - downstream = nil + downstream.write(nil) } } } diff --git a/Pods/Alamofire/Source/Concurrency.swift b/Pods/Alamofire/Source/Concurrency.swift index 95008f9..21e7e1e 100644 --- a/Pods/Alamofire/Source/Concurrency.swift +++ b/Pods/Alamofire/Source/Concurrency.swift @@ -37,7 +37,7 @@ extension Request { /// - Returns: The `StreamOf`. public func uploadProgress(bufferingPolicy: StreamOf.BufferingPolicy = .unbounded) -> StreamOf { stream(bufferingPolicy: bufferingPolicy) { [unowned self] continuation in - uploadProgress(queue: .singleEventQueue) { progress in + uploadProgress(queue: underlyingQueue) { progress in continuation.yield(progress) } } @@ -50,7 +50,7 @@ extension Request { /// - Returns: The `StreamOf`. public func downloadProgress(bufferingPolicy: StreamOf.BufferingPolicy = .unbounded) -> StreamOf { stream(bufferingPolicy: bufferingPolicy) { [unowned self] continuation in - downloadProgress(queue: .singleEventQueue) { progress in + downloadProgress(queue: underlyingQueue) { progress in continuation.yield(progress) } } @@ -63,7 +63,7 @@ extension Request { /// - Returns: The `StreamOf`. public func urlRequests(bufferingPolicy: StreamOf.BufferingPolicy = .unbounded) -> StreamOf { stream(bufferingPolicy: bufferingPolicy) { [unowned self] continuation in - onURLRequestCreation(on: .singleEventQueue) { request in + onURLRequestCreation(on: underlyingQueue) { request in continuation.yield(request) } } @@ -76,7 +76,7 @@ extension Request { /// - Returns: The `StreamOf`. public func urlSessionTasks(bufferingPolicy: StreamOf.BufferingPolicy = .unbounded) -> StreamOf { stream(bufferingPolicy: bufferingPolicy) { [unowned self] continuation in - onURLSessionTaskCreation(on: .singleEventQueue) { task in + onURLSessionTaskCreation(on: underlyingQueue) { task in continuation.yield(task) } } @@ -89,15 +89,15 @@ extension Request { /// - Returns: The `StreamOf`. public func cURLDescriptions(bufferingPolicy: StreamOf.BufferingPolicy = .unbounded) -> StreamOf { stream(bufferingPolicy: bufferingPolicy) { [unowned self] continuation in - cURLDescription(on: .singleEventQueue) { description in + cURLDescription(on: underlyingQueue) { description in continuation.yield(description) } } } - private func stream(of type: T.Type = T.self, - bufferingPolicy: StreamOf.BufferingPolicy = .unbounded, - yielder: @escaping (StreamOf.Continuation) -> Void) -> StreamOf { + fileprivate func stream(of type: T.Type = T.self, + bufferingPolicy: StreamOf.BufferingPolicy = .unbounded, + yielder: @escaping (StreamOf.Continuation) -> Void) -> StreamOf { StreamOf(bufferingPolicy: bufferingPolicy) { [unowned self] continuation in yielder(continuation) // Must come after serializers run in order to catch retry progress. @@ -168,18 +168,83 @@ public struct DataTask { @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) extension DataRequest { + /// Creates a `StreamOf` for the instance's responses. + /// + /// - Parameter bufferingPolicy: `BufferingPolicy` that determines the stream's buffering behavior.`.unbounded` by default. + /// + /// - Returns: The `StreamOf`. + public func httpResponses(bufferingPolicy: StreamOf.BufferingPolicy = .unbounded) -> StreamOf { + stream(bufferingPolicy: bufferingPolicy) { [unowned self] continuation in + onHTTPResponse(on: underlyingQueue) { response in + continuation.yield(response) + } + } + } + + #if swift(>=5.7) + /// Sets an async closure returning a `Request.ResponseDisposition`, called whenever the `DataRequest` produces an + /// `HTTPURLResponse`. + /// + /// - Note: Most requests will only produce a single response for each outgoing attempt (initial + retries). + /// However, some types of response may trigger multiple `HTTPURLResponse`s, such as multipart streams, + /// where responses after the first will contain the part headers. + /// + /// - Parameters: + /// - handler: Async closure executed when a new `HTTPURLResponse` is received and returning a + /// `ResponseDisposition` value. This value determines whether to continue the request or cancel it as + /// if `cancel()` had been called on the instance. Note, this closure is called on an arbitrary thread, + /// so any synchronous calls in it will execute in that context. + /// + /// - Returns: The instance. + @_disfavoredOverload + @discardableResult + public func onHTTPResponse( + perform handler: @escaping @Sendable (_ response: HTTPURLResponse) async -> ResponseDisposition + ) -> Self { + onHTTPResponse(on: underlyingQueue) { response, completionHandler in + Task { + let disposition = await handler(response) + completionHandler(disposition) + } + } + + return self + } + + /// Sets an async closure called whenever the `DataRequest` produces an `HTTPURLResponse`. + /// + /// - Note: Most requests will only produce a single response for each outgoing attempt (initial + retries). + /// However, some types of response may trigger multiple `HTTPURLResponse`s, such as multipart streams, + /// where responses after the first will contain the part headers. + /// + /// - Parameters: + /// - handler: Async closure executed when a new `HTTPURLResponse` is received. Note, this closure is called on an + /// arbitrary thread, so any synchronous calls in it will execute in that context. + /// + /// - Returns: The instance. + @discardableResult + public func onHTTPResponse(perform handler: @escaping @Sendable (_ response: HTTPURLResponse) async -> Void) -> Self { + onHTTPResponse { response in + await handler(response) + return .allow + } + + return self + } + #endif + /// Creates a `DataTask` to `await` a `Data` value. /// /// - Parameters: /// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the /// enclosing async context is cancelled. Only applies to `DataTask`'s async - /// properties. `false` by default. + /// properties. `true` by default. /// - dataPreprocessor: `DataPreprocessor` which processes the received `Data` before completion. /// - emptyResponseCodes: HTTP response codes for which empty responses are allowed. `[204, 205]` by default. /// - emptyRequestMethods: `HTTPMethod`s for which empty responses are always valid. `[.head]` by default. /// /// - Returns: The `DataTask`. - public func serializingData(automaticallyCancelling shouldAutomaticallyCancel: Bool = false, + public func serializingData(automaticallyCancelling shouldAutomaticallyCancel: Bool = true, dataPreprocessor: DataPreprocessor = DataResponseSerializer.defaultDataPreprocessor, emptyResponseCodes: Set = DataResponseSerializer.defaultEmptyResponseCodes, emptyRequestMethods: Set = DataResponseSerializer.defaultEmptyRequestMethods) -> DataTask { @@ -195,7 +260,7 @@ extension DataRequest { /// - type: `Decodable` type to decode from response data. /// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the /// enclosing async context is cancelled. Only applies to `DataTask`'s async - /// properties. `false` by default. + /// properties. `true` by default. /// - dataPreprocessor: `DataPreprocessor` which processes the received `Data` before calling the serializer. /// `PassthroughPreprocessor()` by default. /// - decoder: `DataDecoder` to use to decode the response. `JSONDecoder()` by default. @@ -204,7 +269,7 @@ extension DataRequest { /// /// - Returns: The `DataTask`. public func serializingDecodable(_ type: Value.Type = Value.self, - automaticallyCancelling shouldAutomaticallyCancel: Bool = false, + automaticallyCancelling shouldAutomaticallyCancel: Bool = true, dataPreprocessor: DataPreprocessor = DecodableResponseSerializer.defaultDataPreprocessor, decoder: DataDecoder = JSONDecoder(), emptyResponseCodes: Set = DecodableResponseSerializer.defaultEmptyResponseCodes, @@ -221,7 +286,7 @@ extension DataRequest { /// - Parameters: /// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the /// enclosing async context is cancelled. Only applies to `DataTask`'s async - /// properties. `false` by default. + /// properties. `true` by default. /// - dataPreprocessor: `DataPreprocessor` which processes the received `Data` before calling the serializer. /// `PassthroughPreprocessor()` by default. /// - encoding: `String.Encoding` to use during serialization. Defaults to `nil`, in which case @@ -231,7 +296,7 @@ extension DataRequest { /// - emptyRequestMethods: `HTTPMethod`s for which empty responses are always valid. `[.head]` by default. /// /// - Returns: The `DataTask`. - public func serializingString(automaticallyCancelling shouldAutomaticallyCancel: Bool = false, + public func serializingString(automaticallyCancelling shouldAutomaticallyCancel: Bool = true, dataPreprocessor: DataPreprocessor = StringResponseSerializer.defaultDataPreprocessor, encoding: String.Encoding? = nil, emptyResponseCodes: Set = StringResponseSerializer.defaultEmptyResponseCodes, @@ -249,16 +314,16 @@ extension DataRequest { /// - serializer: `ResponseSerializer` responsible for serializing the request, response, and data. /// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the /// enclosing async context is cancelled. Only applies to `DataTask`'s async - /// properties. `false` by default. + /// properties. `true` by default. /// /// - Returns: The `DataTask`. public func serializingResponse(using serializer: Serializer, - automaticallyCancelling shouldAutomaticallyCancel: Bool = false) + automaticallyCancelling shouldAutomaticallyCancel: Bool = true) -> DataTask { - dataTask(automaticallyCancelling: shouldAutomaticallyCancel) { - self.response(queue: .singleEventQueue, - responseSerializer: serializer, - completionHandler: $0) + dataTask(automaticallyCancelling: shouldAutomaticallyCancel) { [self] in + response(queue: underlyingQueue, + responseSerializer: serializer, + completionHandler: $0) } } @@ -269,16 +334,16 @@ extension DataRequest { /// response, and data. /// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the /// enclosing async context is cancelled. Only applies to `DataTask`'s async - /// properties. `false` by default. + /// properties. `true` by default. /// /// - Returns: The `DataTask`. public func serializingResponse(using serializer: Serializer, - automaticallyCancelling shouldAutomaticallyCancel: Bool = false) + automaticallyCancelling shouldAutomaticallyCancel: Bool = true) -> DataTask { - dataTask(automaticallyCancelling: shouldAutomaticallyCancel) { - self.response(queue: .singleEventQueue, - responseSerializer: serializer, - completionHandler: $0) + dataTask(automaticallyCancelling: shouldAutomaticallyCancel) { [self] in + response(queue: underlyingQueue, + responseSerializer: serializer, + completionHandler: $0) } } @@ -366,13 +431,13 @@ extension DownloadRequest { /// - Parameters: /// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the /// enclosing async context is cancelled. Only applies to `DownloadTask`'s async - /// properties. `false` by default. + /// properties. `true` by default. /// - dataPreprocessor: `DataPreprocessor` which processes the received `Data` before completion. /// - emptyResponseCodes: HTTP response codes for which empty responses are allowed. `[204, 205]` by default. /// - emptyRequestMethods: `HTTPMethod`s for which empty responses are always valid. `[.head]` by default. /// /// - Returns: The `DownloadTask`. - public func serializingData(automaticallyCancelling shouldAutomaticallyCancel: Bool = false, + public func serializingData(automaticallyCancelling shouldAutomaticallyCancel: Bool = true, dataPreprocessor: DataPreprocessor = DataResponseSerializer.defaultDataPreprocessor, emptyResponseCodes: Set = DataResponseSerializer.defaultEmptyResponseCodes, emptyRequestMethods: Set = DataResponseSerializer.defaultEmptyRequestMethods) -> DownloadTask { @@ -390,7 +455,7 @@ extension DownloadRequest { /// - type: `Decodable` type to decode from response data. /// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the /// enclosing async context is cancelled. Only applies to `DownloadTask`'s async - /// properties. `false` by default. + /// properties. `true` by default. /// - dataPreprocessor: `DataPreprocessor` which processes the received `Data` before calling the serializer. /// `PassthroughPreprocessor()` by default. /// - decoder: `DataDecoder` to use to decode the response. `JSONDecoder()` by default. @@ -399,7 +464,7 @@ extension DownloadRequest { /// /// - Returns: The `DownloadTask`. public func serializingDecodable(_ type: Value.Type = Value.self, - automaticallyCancelling shouldAutomaticallyCancel: Bool = false, + automaticallyCancelling shouldAutomaticallyCancel: Bool = true, dataPreprocessor: DataPreprocessor = DecodableResponseSerializer.defaultDataPreprocessor, decoder: DataDecoder = JSONDecoder(), emptyResponseCodes: Set = DecodableResponseSerializer.defaultEmptyResponseCodes, @@ -416,10 +481,10 @@ extension DownloadRequest { /// - Parameters: /// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the /// enclosing async context is cancelled. Only applies to `DownloadTask`'s async - /// properties. `false` by default. + /// properties. `true` by default. /// /// - Returns: The `DownloadTask`. - public func serializingDownloadedFileURL(automaticallyCancelling shouldAutomaticallyCancel: Bool = false) -> DownloadTask { + public func serializingDownloadedFileURL(automaticallyCancelling shouldAutomaticallyCancel: Bool = true) -> DownloadTask { serializingDownload(using: URLResponseSerializer(), automaticallyCancelling: shouldAutomaticallyCancel) } @@ -429,7 +494,7 @@ extension DownloadRequest { /// - Parameters: /// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the /// enclosing async context is cancelled. Only applies to `DownloadTask`'s async - /// properties. `false` by default. + /// properties. `true` by default. /// - dataPreprocessor: `DataPreprocessor` which processes the received `Data` before calling the /// serializer. `PassthroughPreprocessor()` by default. /// - encoding: `String.Encoding` to use during serialization. Defaults to `nil`, in which case @@ -439,7 +504,7 @@ extension DownloadRequest { /// - emptyRequestMethods: `HTTPMethod`s for which empty responses are always valid. `[.head]` by default. /// /// - Returns: The `DownloadTask`. - public func serializingString(automaticallyCancelling shouldAutomaticallyCancel: Bool = false, + public func serializingString(automaticallyCancelling shouldAutomaticallyCancel: Bool = true, dataPreprocessor: DataPreprocessor = StringResponseSerializer.defaultDataPreprocessor, encoding: String.Encoding? = nil, emptyResponseCodes: Set = StringResponseSerializer.defaultEmptyResponseCodes, @@ -457,16 +522,16 @@ extension DownloadRequest { /// - serializer: `ResponseSerializer` responsible for serializing the request, response, and data. /// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the /// enclosing async context is cancelled. Only applies to `DownloadTask`'s async - /// properties. `false` by default. + /// properties. `true` by default. /// /// - Returns: The `DownloadTask`. public func serializingDownload(using serializer: Serializer, - automaticallyCancelling shouldAutomaticallyCancel: Bool = false) + automaticallyCancelling shouldAutomaticallyCancel: Bool = true) -> DownloadTask { - downloadTask(automaticallyCancelling: shouldAutomaticallyCancel) { - self.response(queue: .singleEventQueue, - responseSerializer: serializer, - completionHandler: $0) + downloadTask(automaticallyCancelling: shouldAutomaticallyCancel) { [self] in + response(queue: underlyingQueue, + responseSerializer: serializer, + completionHandler: $0) } } @@ -478,16 +543,16 @@ extension DownloadRequest { /// response, and data. /// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the /// enclosing async context is cancelled. Only applies to `DownloadTask`'s async - /// properties. `false` by default. + /// properties. `true` by default. /// /// - Returns: The `DownloadTask`. public func serializingDownload(using serializer: Serializer, - automaticallyCancelling shouldAutomaticallyCancel: Bool = false) + automaticallyCancelling shouldAutomaticallyCancel: Bool = true) -> DownloadTask { - downloadTask(automaticallyCancelling: shouldAutomaticallyCancel) { - self.response(queue: .singleEventQueue, - responseSerializer: serializer, - completionHandler: $0) + downloadTask(automaticallyCancelling: shouldAutomaticallyCancel) { [self] in + response(queue: underlyingQueue, + responseSerializer: serializer, + completionHandler: $0) } } @@ -625,6 +690,69 @@ public struct DataStreamTask { @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) extension DataStreamRequest { + /// Creates a `StreamOf` for the instance's responses. + /// + /// - Parameter bufferingPolicy: `BufferingPolicy` that determines the stream's buffering behavior.`.unbounded` by default. + /// + /// - Returns: The `StreamOf`. + public func httpResponses(bufferingPolicy: StreamOf.BufferingPolicy = .unbounded) -> StreamOf { + stream(bufferingPolicy: bufferingPolicy) { [unowned self] continuation in + onHTTPResponse(on: underlyingQueue) { response in + continuation.yield(response) + } + } + } + + #if swift(>=5.7) + /// Sets an async closure returning a `Request.ResponseDisposition`, called whenever the `DataStreamRequest` + /// produces an `HTTPURLResponse`. + /// + /// - Note: Most requests will only produce a single response for each outgoing attempt (initial + retries). + /// However, some types of response may trigger multiple `HTTPURLResponse`s, such as multipart streams, + /// where responses after the first will contain the part headers. + /// + /// - Parameters: + /// - handler: Async closure executed when a new `HTTPURLResponse` is received and returning a + /// `ResponseDisposition` value. This value determines whether to continue the request or cancel it as + /// if `cancel()` had been called on the instance. Note, this closure is called on an arbitrary thread, + /// so any synchronous calls in it will execute in that context. + /// + /// - Returns: The instance. + @_disfavoredOverload + @discardableResult + public func onHTTPResponse(perform handler: @escaping @Sendable (HTTPURLResponse) async -> ResponseDisposition) -> Self { + onHTTPResponse(on: underlyingQueue) { response, completionHandler in + Task { + let disposition = await handler(response) + completionHandler(disposition) + } + } + + return self + } + + /// Sets an async closure called whenever the `DataStreamRequest` produces an `HTTPURLResponse`. + /// + /// - Note: Most requests will only produce a single response for each outgoing attempt (initial + retries). + /// However, some types of response may trigger multiple `HTTPURLResponse`s, such as multipart streams, + /// where responses after the first will contain the part headers. + /// + /// - Parameters: + /// - handler: Async closure executed when a new `HTTPURLResponse` is received. Note, this closure is called on an + /// arbitrary thread, so any synchronous calls in it will execute in that context. + /// + /// - Returns: The instance. + @discardableResult + public func onHTTPResponse(perform handler: @escaping @Sendable (HTTPURLResponse) async -> Void) -> Self { + onHTTPResponse { response in + await handler(response) + return .allow + } + + return self + } + #endif + /// Creates a `DataStreamTask` used to `await` streams of serialized values. /// /// - Returns: The `DataStreamTask`. diff --git a/Pods/Alamofire/Source/EventMonitor.swift b/Pods/Alamofire/Source/EventMonitor.swift index 5fe22df..75b60f2 100644 --- a/Pods/Alamofire/Source/EventMonitor.swift +++ b/Pods/Alamofire/Source/EventMonitor.swift @@ -69,6 +69,9 @@ public protocol EventMonitor { // MARK: URLSessionDataDelegate Events + /// Event called during `URLSessionDataDelegate`'s `urlSession(_:dataTask:didReceive:completionHandler:)` method. + func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse) + /// Event called during `URLSessionDataDelegate`'s `urlSession(_:dataTask:didReceive:)` method. func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) @@ -244,6 +247,7 @@ extension EventMonitor { didFinishCollecting metrics: URLSessionTaskMetrics) {} public func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {} public func urlSession(_ session: URLSession, taskIsWaitingForConnectivity task: URLSessionTask) {} + public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse) {} public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {} public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, @@ -380,6 +384,10 @@ public final class CompositeEventMonitor: EventMonitor { performEvent { $0.urlSession(session, taskIsWaitingForConnectivity: task) } } + public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse) { + performEvent { $0.urlSession(session, dataTask: dataTask, didReceive: response) } + } + public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) { performEvent { $0.urlSession(session, dataTask: dataTask, didReceive: data) } } @@ -593,6 +601,9 @@ open class ClosureEventMonitor: EventMonitor { /// Closure called on the `urlSession(_:taskIsWaitingForConnectivity:)` event. open var taskIsWaitingForConnectivity: ((URLSession, URLSessionTask) -> Void)? + /// Closure called on the `urlSession(_:dataTask:didReceive:completionHandler:)` event. + open var dataTaskDidReceiveResponse: ((URLSession, URLSessionDataTask, URLResponse) -> Void)? + /// Closure that receives the `urlSession(_:dataTask:didReceive:)` event. open var dataTaskDidReceiveData: ((URLSession, URLSessionDataTask, Data) -> Void)? @@ -741,6 +752,10 @@ open class ClosureEventMonitor: EventMonitor { taskIsWaitingForConnectivity?(session, task) } + open func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse) { + dataTaskDidReceiveResponse?(session, dataTask, response) + } + open func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) { dataTaskDidReceiveData?(session, dataTask, data) } diff --git a/Pods/Alamofire/Source/HTTPHeaders.swift b/Pods/Alamofire/Source/HTTPHeaders.swift index 231f618..08d4799 100644 --- a/Pods/Alamofire/Source/HTTPHeaders.swift +++ b/Pods/Alamofire/Source/HTTPHeaders.swift @@ -34,16 +34,12 @@ public struct HTTPHeaders { /// Creates an instance from an array of `HTTPHeader`s. Duplicate case-insensitive names are collapsed into the last /// name and value encountered. public init(_ headers: [HTTPHeader]) { - self.init() - headers.forEach { update($0) } } /// Creates an instance from a `[String: String]`. Duplicate case-insensitive names are collapsed into the last name /// and value encountered. public init(_ dictionary: [String: String]) { - self.init() - dictionary.forEach { update(HTTPHeader(name: $0.key, value: $0.value)) } } @@ -145,8 +141,6 @@ public struct HTTPHeaders { extension HTTPHeaders: ExpressibleByDictionaryLiteral { public init(dictionaryLiteral elements: (String, String)...) { - self.init() - elements.forEach { update(name: $0.0, value: $0.1) } } } @@ -405,6 +399,8 @@ extension HTTPHeader { return "Linux" #elseif os(Windows) return "Windows" + #elseif os(Android) + return "Android" #else return "Unknown" #endif diff --git a/Pods/Alamofire/Source/MultipartFormData.swift b/Pods/Alamofire/Source/MultipartFormData.swift index 364b614..3fb6e2b 100644 --- a/Pods/Alamofire/Source/MultipartFormData.swift +++ b/Pods/Alamofire/Source/MultipartFormData.swift @@ -24,9 +24,9 @@ import Foundation -#if os(iOS) || os(watchOS) || os(tvOS) +#if canImport(MobileCoreServices) import MobileCoreServices -#elseif os(macOS) +#elseif canImport(CoreServices) import CoreServices #endif @@ -213,7 +213,7 @@ open class MultipartFormData { // Check 2 - is file URL reachable? //============================================================ - #if !(os(Linux) || os(Windows)) + #if !(os(Linux) || os(Windows) || os(Android)) do { let isReachable = try fileURL.checkPromisedItemIsReachable() guard isReachable else { @@ -455,9 +455,11 @@ open class MultipartFormData { inputStream.open() defer { inputStream.close() } - while inputStream.hasBytesAvailable { - var buffer = [UInt8](repeating: 0, count: streamBufferSize) - let bytesRead = inputStream.read(&buffer, maxLength: streamBufferSize) + var bytesLeftToRead = bodyPart.bodyContentLength + while inputStream.hasBytesAvailable && bytesLeftToRead > 0 { + let bufferSize = min(streamBufferSize, Int(bytesLeftToRead)) + var buffer = [UInt8](repeating: 0, count: bufferSize) + let bytesRead = inputStream.read(&buffer, maxLength: bufferSize) if let streamError = inputStream.streamError { throw AFError.multipartEncodingFailed(reason: .inputStreamReadFailed(error: streamError)) @@ -469,6 +471,7 @@ open class MultipartFormData { } try write(&buffer, to: outputStream) + bytesLeftToRead -= UInt64(bytesRead) } else { break } @@ -549,6 +552,19 @@ extension MultipartFormData { // MARK: - Private - Mime Type private func mimeType(forPathExtension pathExtension: String) -> String { + #if swift(>=5.9) + if #available(iOS 14, macOS 11, tvOS 14, watchOS 7, visionOS 1, *) { + return UTType(filenameExtension: pathExtension)?.preferredMIMEType ?? "application/octet-stream" + } else { + if + let id = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, pathExtension as CFString, nil)?.takeRetainedValue(), + let contentType = UTTypeCopyPreferredTagWithClass(id, kUTTagClassMIMEType)?.takeRetainedValue() { + return contentType as String + } + + return "application/octet-stream" + } + #else if #available(iOS 14, macOS 11, tvOS 14, watchOS 7, *) { return UTType(filenameExtension: pathExtension)?.preferredMIMEType ?? "application/octet-stream" } else { @@ -560,6 +576,7 @@ extension MultipartFormData { return "application/octet-stream" } + #endif } } @@ -569,7 +586,7 @@ extension MultipartFormData { // MARK: - Private - Mime Type private func mimeType(forPathExtension pathExtension: String) -> String { - #if !(os(Linux) || os(Windows)) + #if canImport(CoreServices) || canImport(MobileCoreServices) if let id = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, pathExtension as CFString, nil)?.takeRetainedValue(), let contentType = UTTypeCopyPreferredTagWithClass(id, kUTTagClassMIMEType)?.takeRetainedValue() { diff --git a/Pods/Alamofire/Source/MultipartUpload.swift b/Pods/Alamofire/Source/MultipartUpload.swift index ceda21f..ae905bd 100644 --- a/Pods/Alamofire/Source/MultipartUpload.swift +++ b/Pods/Alamofire/Source/MultipartUpload.swift @@ -28,8 +28,8 @@ import Foundation final class MultipartUpload { lazy var result = Result { try build() } - @Protected - private(set) var multipartFormData: MultipartFormData + private let multipartFormData: Protected + let encodingMemoryThreshold: UInt64 let request: URLRequestConvertible let fileManager: FileManager @@ -40,13 +40,13 @@ final class MultipartUpload { self.encodingMemoryThreshold = encodingMemoryThreshold self.request = request fileManager = multipartFormData.fileManager - self.multipartFormData = multipartFormData + self.multipartFormData = Protected(multipartFormData) } func build() throws -> UploadRequest.Uploadable { let uploadable: UploadRequest.Uploadable - if $multipartFormData.contentLength < encodingMemoryThreshold { - let data = try $multipartFormData.read { try $0.encode() } + if multipartFormData.contentLength < encodingMemoryThreshold { + let data = try multipartFormData.read { try $0.encode() } uploadable = .data(data) } else { @@ -58,7 +58,7 @@ final class MultipartUpload { try fileManager.createDirectory(at: directoryURL, withIntermediateDirectories: true, attributes: nil) do { - try $multipartFormData.read { try $0.writeEncodedData(to: fileURL) } + try multipartFormData.read { try $0.writeEncodedData(to: fileURL) } } catch { // Cleanup after attempted write if it fails. try? fileManager.removeItem(at: fileURL) @@ -76,7 +76,7 @@ extension MultipartUpload: UploadConvertible { func asURLRequest() throws -> URLRequest { var urlRequest = try request.asURLRequest() - $multipartFormData.read { multipartFormData in + multipartFormData.read { multipartFormData in urlRequest.headers.add(.contentType(multipartFormData.contentType)) } diff --git a/Pods/Alamofire/Source/NetworkReachabilityManager.swift b/Pods/Alamofire/Source/NetworkReachabilityManager.swift index d724722..650fdf9 100644 --- a/Pods/Alamofire/Source/NetworkReachabilityManager.swift +++ b/Pods/Alamofire/Source/NetworkReachabilityManager.swift @@ -22,7 +22,7 @@ // THE SOFTWARE. // -#if !(os(watchOS) || os(Linux) || os(Windows)) +#if canImport(SystemConfiguration) import Foundation import SystemConfiguration @@ -113,8 +113,7 @@ open class NetworkReachabilityManager { private let reachability: SCNetworkReachability /// Protected storage for mutable state. - @Protected - private var mutableState = MutableState() + private let mutableState = Protected(MutableState()) // MARK: - Initialization @@ -168,7 +167,7 @@ open class NetworkReachabilityManager { onUpdatePerforming listener: @escaping Listener) -> Bool { stopListening() - $mutableState.write { state in + mutableState.write { state in state.listenerQueue = queue state.listener = listener } @@ -194,7 +193,8 @@ open class NetworkReachabilityManager { let description = weakManager.manager?.flags?.readableDescription ?? "nil" return Unmanaged.passRetained(description as CFString) - }) + } + ) let callback: SCNetworkReachabilityCallBack = { _, flags, info in guard let info = info else { return } @@ -219,7 +219,7 @@ open class NetworkReachabilityManager { open func stopListening() { SCNetworkReachabilitySetCallback(reachability, nil, nil) SCNetworkReachabilitySetDispatchQueue(reachability, nil) - $mutableState.write { state in + mutableState.write { state in state.listener = nil state.listenerQueue = nil state.previousStatus = nil @@ -236,7 +236,7 @@ open class NetworkReachabilityManager { func notifyListener(_ flags: SCNetworkReachabilityFlags) { let newStatus = NetworkReachabilityStatus(flags) - $mutableState.write { state in + mutableState.write { state in guard state.previousStatus != newStatus else { return } state.previousStatus = newStatus @@ -266,7 +266,7 @@ extension SCNetworkReachabilityFlags { var canConnectWithoutUserInteraction: Bool { canConnectAutomatically && !contains(.interventionRequired) } var isActuallyReachable: Bool { isReachable && (!isConnectionRequired || canConnectWithoutUserInteraction) } var isCellular: Bool { - #if os(iOS) || os(tvOS) + #if os(iOS) || os(tvOS) || (swift(>=5.9) && os(visionOS)) return contains(.isWWAN) #else return false diff --git a/Pods/Alamofire/Source/Protected.swift b/Pods/Alamofire/Source/Protected.swift index 2c056fa..6756045 100644 --- a/Pods/Alamofire/Source/Protected.swift +++ b/Pods/Alamofire/Source/Protected.swift @@ -49,13 +49,7 @@ extension Lock { } } -#if os(Linux) || os(Windows) - -extension NSLock: Lock {} - -#endif - -#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) +#if canImport(Darwin) /// An `os_unfair_lock` wrapper. final class UnfairLock: Lock { private let unfairLock: os_unfair_lock_t @@ -78,41 +72,35 @@ final class UnfairLock: Lock { os_unfair_lock_unlock(unfairLock) } } + +#elseif canImport(Foundation) +extension NSLock: Lock {} +#else +#error("This platform needs a Lock-conforming type without Foundation.") #endif /// A thread-safe wrapper around a value. -@propertyWrapper @dynamicMemberLookup -final class Protected { - #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) +final class Protected { + #if canImport(Darwin) private let lock = UnfairLock() - #elseif os(Linux) || os(Windows) + #elseif canImport(Foundation) private let lock = NSLock() + #else + #error("This platform needs a Lock-conforming type without Foundation.") #endif - private var value: T + private var value: Value - init(_ value: T) { + init(_ value: Value) { self.value = value } - /// The contained value. Unsafe for anything more than direct read or write. - var wrappedValue: T { - get { lock.around { value } } - set { lock.around { value = newValue } } - } - - var projectedValue: Protected { self } - - init(wrappedValue: T) { - value = wrappedValue - } - /// Synchronously read or transform the contained value. /// /// - Parameter closure: The closure to execute. /// /// - Returns: The return value of the closure passed. - func read(_ closure: (T) throws -> U) rethrows -> U { + func read(_ closure: (Value) throws -> U) rethrows -> U { try lock.around { try closure(self.value) } } @@ -122,21 +110,28 @@ final class Protected { /// /// - Returns: The modified value. @discardableResult - func write(_ closure: (inout T) throws -> U) rethrows -> U { + func write(_ closure: (inout Value) throws -> U) rethrows -> U { try lock.around { try closure(&self.value) } } - subscript(dynamicMember keyPath: WritableKeyPath) -> Property { + /// Synchronously update the protected value. + /// + /// - Parameter value: The `Value`. + func write(_ value: Value) { + write { $0 = value } + } + + subscript(dynamicMember keyPath: WritableKeyPath) -> Property { get { lock.around { value[keyPath: keyPath] } } set { lock.around { value[keyPath: keyPath] = newValue } } } - subscript(dynamicMember keyPath: KeyPath) -> Property { + subscript(dynamicMember keyPath: KeyPath) -> Property { lock.around { value[keyPath: keyPath] } } } -extension Protected where T == Request.MutableState { +extension Protected where Value == Request.MutableState { /// Attempts to transition to the passed `State`. /// /// - Parameter state: The `State` to attempt transition to. @@ -159,3 +154,15 @@ extension Protected where T == Request.MutableState { lock.around { perform(value.state) } } } + +extension Protected: Equatable where Value: Equatable { + static func ==(lhs: Protected, rhs: Protected) -> Bool { + lhs.read { left in rhs.read { right in left == right }} + } +} + +extension Protected: Hashable where Value: Hashable { + func hash(into hasher: inout Hasher) { + read { hasher.combine($0) } + } +} diff --git a/Pods/Alamofire/Source/Request.swift b/Pods/Alamofire/Source/Request.swift index a707933..55f2a67 100644 --- a/Pods/Alamofire/Source/Request.swift +++ b/Pods/Alamofire/Source/Request.swift @@ -125,11 +125,10 @@ public class Request { } /// Protected `MutableState` value that provides thread-safe access to state values. - @Protected - fileprivate var mutableState = MutableState() + fileprivate let mutableState = Protected(MutableState()) /// `State` of the `Request`. - public var state: State { $mutableState.state } + public var state: State { mutableState.state } /// Returns whether `state` is `.initialized`. public var isInitialized: Bool { state == .initialized } /// Returns whether `state is `.resumed`. @@ -152,50 +151,49 @@ public class Request { public let downloadProgress = Progress(totalUnitCount: 0) /// `ProgressHandler` called when `uploadProgress` is updated, on the provided `DispatchQueue`. private var uploadProgressHandler: (handler: ProgressHandler, queue: DispatchQueue)? { - get { $mutableState.uploadProgressHandler } - set { $mutableState.uploadProgressHandler = newValue } + get { mutableState.uploadProgressHandler } + set { mutableState.uploadProgressHandler = newValue } } /// `ProgressHandler` called when `downloadProgress` is updated, on the provided `DispatchQueue`. fileprivate var downloadProgressHandler: (handler: ProgressHandler, queue: DispatchQueue)? { - get { $mutableState.downloadProgressHandler } - set { $mutableState.downloadProgressHandler = newValue } + get { mutableState.downloadProgressHandler } + set { mutableState.downloadProgressHandler = newValue } } // MARK: Redirect Handling /// `RedirectHandler` set on the instance. public private(set) var redirectHandler: RedirectHandler? { - get { $mutableState.redirectHandler } - set { $mutableState.redirectHandler = newValue } + get { mutableState.redirectHandler } + set { mutableState.redirectHandler = newValue } } // MARK: Cached Response Handling /// `CachedResponseHandler` set on the instance. public private(set) var cachedResponseHandler: CachedResponseHandler? { - get { $mutableState.cachedResponseHandler } - set { $mutableState.cachedResponseHandler = newValue } + get { mutableState.cachedResponseHandler } + set { mutableState.cachedResponseHandler = newValue } } // MARK: URLCredential /// `URLCredential` used for authentication challenges. Created by calling one of the `authenticate` methods. public private(set) var credential: URLCredential? { - get { $mutableState.credential } - set { $mutableState.credential = newValue } + get { mutableState.credential } + set { mutableState.credential = newValue } } // MARK: Validators /// `Validator` callback closures that store the validation calls enqueued. - @Protected - fileprivate var validators: [() -> Void] = [] + fileprivate let validators = Protected<[() -> Void]>([]) // MARK: URLRequests /// All `URLRequests` created on behalf of the `Request`, including original and adapted requests. - public var requests: [URLRequest] { $mutableState.requests } + public var requests: [URLRequest] { mutableState.requests } /// First `URLRequest` created on behalf of the `Request`. May not be the first one actually executed. public var firstRequest: URLRequest? { requests.first } /// Last `URLRequest` created on behalf of the `Request`. @@ -205,7 +203,7 @@ public class Request { /// `URLRequest`s from all of the `URLSessionTask`s executed on behalf of the `Request`. May be different from /// `requests` due to `URLSession` manipulation. - public var performedRequests: [URLRequest] { $mutableState.read { $0.tasks.compactMap(\.currentRequest) } } + public var performedRequests: [URLRequest] { mutableState.read { $0.tasks.compactMap(\.currentRequest) } } // MARK: HTTPURLResponse @@ -216,7 +214,7 @@ public class Request { // MARK: Tasks /// All `URLSessionTask`s created on behalf of the `Request`. - public var tasks: [URLSessionTask] { $mutableState.tasks } + public var tasks: [URLSessionTask] { mutableState.tasks } /// First `URLSessionTask` created on behalf of the `Request`. public var firstTask: URLSessionTask? { tasks.first } /// Last `URLSessionTask` created on behalf of the `Request`. @@ -227,7 +225,7 @@ public class Request { // MARK: Metrics /// All `URLSessionTaskMetrics` gathered on behalf of the `Request`. Should correspond to the `tasks` created. - public var allMetrics: [URLSessionTaskMetrics] { $mutableState.metrics } + public var allMetrics: [URLSessionTaskMetrics] { mutableState.metrics } /// First `URLSessionTaskMetrics` gathered on behalf of the `Request`. public var firstMetrics: URLSessionTaskMetrics? { allMetrics.first } /// Last `URLSessionTaskMetrics` gathered on behalf of the `Request`. @@ -238,14 +236,14 @@ public class Request { // MARK: Retry Count /// Number of times the `Request` has been retried. - public var retryCount: Int { $mutableState.retryCount } + public var retryCount: Int { mutableState.retryCount } // MARK: Error /// `Error` returned from Alamofire internally, from the network request directly, or any validators executed. public fileprivate(set) var error: AFError? { - get { $mutableState.error } - set { $mutableState.error = newValue } + get { mutableState.error } + set { mutableState.error = newValue } } /// Default initializer for the `Request` superclass. @@ -283,7 +281,7 @@ public class Request { func didCreateInitialURLRequest(_ request: URLRequest) { dispatchPrecondition(condition: .onQueue(underlyingQueue)) - $mutableState.write { $0.requests.append(request) } + mutableState.write { $0.requests.append(request) } eventMonitor?.request(self, didCreateInitialURLRequest: request) } @@ -313,7 +311,7 @@ public class Request { func didAdaptInitialRequest(_ initialRequest: URLRequest, to adaptedRequest: URLRequest) { dispatchPrecondition(condition: .onQueue(underlyingQueue)) - $mutableState.write { $0.requests.append(adaptedRequest) } + mutableState.write { $0.requests.append(adaptedRequest) } eventMonitor?.request(self, didAdaptInitialRequest: initialRequest, to: adaptedRequest) } @@ -343,7 +341,7 @@ public class Request { func didCreateURLRequest(_ request: URLRequest) { dispatchPrecondition(condition: .onQueue(underlyingQueue)) - $mutableState.read { state in + mutableState.read { state in state.urlRequestHandler?.queue.async { state.urlRequestHandler?.handler(request) } } @@ -354,7 +352,7 @@ public class Request { /// Asynchronously calls any stored `cURLHandler` and then removes it from `mutableState`. private func callCURLHandlerIfNecessary() { - $mutableState.write { mutableState in + mutableState.write { mutableState in guard let cURLHandler = mutableState.cURLHandler else { return } cURLHandler.queue.async { cURLHandler.handler(self.cURLDescription()) } @@ -369,7 +367,7 @@ public class Request { func didCreateTask(_ task: URLSessionTask) { dispatchPrecondition(condition: .onQueue(underlyingQueue)) - $mutableState.write { state in + mutableState.write { state in state.tasks.append(task) guard let urlSessionTaskHandler = state.urlSessionTaskHandler else { return } @@ -416,7 +414,9 @@ public class Request { func didCancel() { dispatchPrecondition(condition: .onQueue(underlyingQueue)) - error = error ?? AFError.explicitlyCancelled + mutableState.write { mutableState in + mutableState.error = mutableState.error ?? AFError.explicitlyCancelled + } eventMonitor?.requestDidCancel(self) } @@ -436,7 +436,7 @@ public class Request { func didGatherMetrics(_ metrics: URLSessionTaskMetrics) { dispatchPrecondition(condition: .onQueue(underlyingQueue)) - $mutableState.write { $0.metrics.append(metrics) } + mutableState.write { $0.metrics.append(metrics) } eventMonitor?.request(self, didGatherMetrics: metrics) } @@ -468,6 +468,7 @@ public class Request { self.error = self.error ?? error + let validators = validators.read { $0 } validators.forEach { $0() } eventMonitor?.request(self, didCompleteTask: task, with: error) @@ -479,7 +480,7 @@ public class Request { func prepareForRetry() { dispatchPrecondition(condition: .onQueue(underlyingQueue)) - $mutableState.write { $0.retryCount += 1 } + mutableState.write { $0.retryCount += 1 } reset() @@ -513,9 +514,9 @@ public class Request { func finish(error: AFError? = nil) { dispatchPrecondition(condition: .onQueue(underlyingQueue)) - guard !$mutableState.isFinishing else { return } + guard !mutableState.isFinishing else { return } - $mutableState.isFinishing = true + mutableState.isFinishing = true if let error = error { self.error = error } @@ -531,7 +532,7 @@ public class Request { /// /// - Parameter closure: The closure containing the response serialization call. func appendResponseSerializer(_ closure: @escaping () -> Void) { - $mutableState.write { mutableState in + mutableState.write { mutableState in mutableState.responseSerializers.append(closure) if mutableState.state == .finished { @@ -554,7 +555,7 @@ public class Request { func nextResponseSerializer() -> (() -> Void)? { var responseSerializer: (() -> Void)? - $mutableState.write { mutableState in + mutableState.write { mutableState in let responseSerializerIndex = mutableState.responseSerializerCompletions.count if responseSerializerIndex < mutableState.responseSerializers.count { @@ -571,7 +572,7 @@ public class Request { // Execute all response serializer completions and clear them var completions: [() -> Void] = [] - $mutableState.write { mutableState in + mutableState.write { mutableState in completions = mutableState.responseSerializerCompletions // Clear out all response serializers and response serializer completions in mutable state since the @@ -605,7 +606,7 @@ public class Request { /// - Parameter completion: The completion handler provided with the response serializer, called when all serializers /// are complete. func responseSerializerDidComplete(completion: @escaping () -> Void) { - $mutableState.write { $0.responseSerializerCompletions.append(completion) } + mutableState.write { $0.responseSerializerCompletions.append(completion) } processNextResponseSerializer() } @@ -618,7 +619,7 @@ public class Request { downloadProgress.totalUnitCount = 0 downloadProgress.completedUnitCount = 0 - $mutableState.write { state in + mutableState.write { state in state.isFinishing = false state.responseSerializerCompletions = [] } @@ -640,7 +641,7 @@ public class Request { /// /// - Parameter perform: The closure to perform. func withState(perform: (State) -> Void) { - $mutableState.withState(perform: perform) + mutableState.withState(perform: perform) } // MARK: Task Creation @@ -667,7 +668,7 @@ public class Request { /// - Returns: The instance. @discardableResult public func cancel() -> Self { - $mutableState.write { mutableState in + mutableState.write { mutableState in guard mutableState.state.canTransitionTo(.cancelled) else { return } mutableState.state = .cancelled @@ -693,7 +694,7 @@ public class Request { /// - Returns: The instance. @discardableResult public func suspend() -> Self { - $mutableState.write { mutableState in + mutableState.write { mutableState in guard mutableState.state.canTransitionTo(.suspended) else { return } mutableState.state = .suspended @@ -714,7 +715,7 @@ public class Request { /// - Returns: The instance. @discardableResult public func resume() -> Self { - $mutableState.write { mutableState in + mutableState.write { mutableState in guard mutableState.state.canTransitionTo(.resumed) else { return } mutableState.state = .resumed @@ -754,7 +755,7 @@ public class Request { /// - Returns: The instance. @discardableResult public func authenticate(with credential: URLCredential) -> Self { - $mutableState.credential = credential + mutableState.credential = credential return self } @@ -770,7 +771,7 @@ public class Request { /// - Returns: The instance. @discardableResult public func downloadProgress(queue: DispatchQueue = .main, closure: @escaping ProgressHandler) -> Self { - $mutableState.downloadProgressHandler = (handler: closure, queue: queue) + mutableState.downloadProgressHandler = (handler: closure, queue: queue) return self } @@ -786,7 +787,7 @@ public class Request { /// - Returns: The instance. @discardableResult public func uploadProgress(queue: DispatchQueue = .main, closure: @escaping ProgressHandler) -> Self { - $mutableState.uploadProgressHandler = (handler: closure, queue: queue) + mutableState.uploadProgressHandler = (handler: closure, queue: queue) return self } @@ -802,7 +803,7 @@ public class Request { /// - Returns: The instance. @discardableResult public func redirect(using handler: RedirectHandler) -> Self { - $mutableState.write { mutableState in + mutableState.write { mutableState in precondition(mutableState.redirectHandler == nil, "Redirect handler has already been set.") mutableState.redirectHandler = handler } @@ -821,7 +822,7 @@ public class Request { /// - Returns: The instance. @discardableResult public func cacheResponse(using handler: CachedResponseHandler) -> Self { - $mutableState.write { mutableState in + mutableState.write { mutableState in precondition(mutableState.cachedResponseHandler == nil, "Cached response handler has already been set.") mutableState.cachedResponseHandler = handler } @@ -842,7 +843,7 @@ public class Request { /// - Returns: The instance. @discardableResult public func cURLDescription(on queue: DispatchQueue, calling handler: @escaping (String) -> Void) -> Self { - $mutableState.write { mutableState in + mutableState.write { mutableState in if mutableState.requests.last != nil { queue.async { handler(self.cURLDescription()) } } else { @@ -863,13 +864,7 @@ public class Request { /// - Returns: The instance. @discardableResult public func cURLDescription(calling handler: @escaping (String) -> Void) -> Self { - $mutableState.write { mutableState in - if mutableState.requests.last != nil { - underlyingQueue.async { handler(self.cURLDescription()) } - } else { - mutableState.cURLHandler = (underlyingQueue, handler) - } - } + cURLDescription(on: underlyingQueue, calling: handler) return self } @@ -885,7 +880,7 @@ public class Request { /// - Returns: The instance. @discardableResult public func onURLRequestCreation(on queue: DispatchQueue = .main, perform handler: @escaping (URLRequest) -> Void) -> Self { - $mutableState.write { state in + mutableState.write { state in if let request = state.requests.last { queue.async { handler(request) } } @@ -909,7 +904,7 @@ public class Request { /// - Returns: The instance. @discardableResult public func onURLSessionTaskCreation(on queue: DispatchQueue = .main, perform handler: @escaping (URLSessionTask) -> Void) -> Self { - $mutableState.write { state in + mutableState.write { state in if let task = state.tasks.last { queue.async { handler(task) } } @@ -928,19 +923,37 @@ public class Request { func onFinish(perform finishHandler: @escaping () -> Void) { guard !isFinished else { finishHandler(); return } - $mutableState.write { state in + mutableState.write { state in state.finishHandlers.append(finishHandler) } } /// Final cleanup step executed when the instance finishes response serialization. func cleanup() { - delegate?.cleanup(after: self) - let handlers = $mutableState.finishHandlers + let handlers = mutableState.finishHandlers handlers.forEach { $0() } - $mutableState.write { state in + mutableState.write { state in state.finishHandlers.removeAll() } + + delegate?.cleanup(after: self) + } +} + +extension Request { + /// Type indicating how a `DataRequest` or `DataStreamRequest` should proceed after receiving an `HTTPURLResponse`. + public enum ResponseDisposition { + /// Allow the request to continue normally. + case allow + /// Cancel the request, similar to calling `cancel()`. + case cancel + + var sessionDisposition: URLSession.ResponseDisposition { + switch self { + case .allow: return .allow + case .cancel: return .cancel + } + } } } @@ -1085,11 +1098,16 @@ public class DataRequest: Request { /// `URLRequestConvertible` value used to create `URLRequest`s for this instance. public let convertible: URLRequestConvertible /// `Data` read from the server so far. - public var data: Data? { mutableData } + public var data: Data? { dataMutableState.data } - /// Protected storage for the `Data` read by the instance. - @Protected - private var mutableData: Data? = nil + private struct DataMutableState { + var data: Data? + var httpResponseHandler: (queue: DispatchQueue, + handler: (_ response: HTTPURLResponse, + _ completionHandler: @escaping (ResponseDisposition) -> Void) -> Void)? + } + + private let dataMutableState = Protected(DataMutableState()) /// Creates a `DataRequest` using the provided parameters. /// @@ -1122,7 +1140,9 @@ public class DataRequest: Request { override func reset() { super.reset() - mutableData = nil + dataMutableState.write { mutableState in + mutableState.data = nil + } } /// Called when `Data` is received by this instance. @@ -1131,15 +1151,41 @@ public class DataRequest: Request { /// /// - Parameter data: The `Data` received. func didReceive(data: Data) { - if self.data == nil { - mutableData = data - } else { - $mutableData.write { $0?.append(data) } + dataMutableState.write { mutableState in + if mutableState.data == nil { + mutableState.data = data + } else { + mutableState.data?.append(data) + } } updateDownloadProgress() } + func didReceiveResponse(_ response: HTTPURLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) { + dataMutableState.read { dataMutableState in + guard let httpResponseHandler = dataMutableState.httpResponseHandler else { + underlyingQueue.async { completionHandler(.allow) } + return + } + + httpResponseHandler.queue.async { + httpResponseHandler.handler(response) { disposition in + if disposition == .cancel { + self.mutableState.write { mutableState in + mutableState.state = .cancelled + mutableState.error = mutableState.error ?? AFError.explicitlyCancelled + } + } + + self.underlyingQueue.async { + completionHandler(disposition.sessionDisposition) + } + } + } + } + } + override func task(for request: URLRequest, using session: URLSession) -> URLSessionTask { let copiedRequest = request return session.dataTask(with: copiedRequest) @@ -1179,7 +1225,48 @@ public class DataRequest: Request { withResult: result) } - $validators.write { $0.append(validator) } + validators.write { $0.append(validator) } + + return self + } + + /// Sets a closure called whenever the `DataRequest` produces an `HTTPURLResponse` and providing a completion + /// handler to return a `ResponseDisposition` value. + /// + /// - Parameters: + /// - queue: `DispatchQueue` on which the closure will be called. `.main` by default. + /// - handler: Closure called when the instance produces an `HTTPURLResponse`. The `completionHandler` provided + /// MUST be called, otherwise the request will never complete. + /// + /// - Returns: The instance. + @_disfavoredOverload + @discardableResult + public func onHTTPResponse( + on queue: DispatchQueue = .main, + perform handler: @escaping (_ response: HTTPURLResponse, + _ completionHandler: @escaping (ResponseDisposition) -> Void) -> Void + ) -> Self { + dataMutableState.write { mutableState in + mutableState.httpResponseHandler = (queue, handler) + } + + return self + } + + /// Sets a closure called whenever the `DataRequest` produces an `HTTPURLResponse`. + /// + /// - Parameters: + /// - queue: `DispatchQueue` on which the closure will be called. `.main` by default. + /// - handler: Closure called when the instance produces an `HTTPURLResponse`. + /// + /// - Returns: The instance. + @discardableResult + public func onHTTPResponse(on queue: DispatchQueue = .main, + perform handler: @escaping (HTTPURLResponse) -> Void) -> Self { + onHTTPResponse(on: queue) { response, completionHandler in + handler(response) + completionHandler(.allow) + } return self } @@ -1259,10 +1346,13 @@ public final class DataStreamRequest: Request { var numberOfExecutingStreams = 0 /// Completion calls enqueued while streams are still executing. var enqueuedCompletionEvents: [() -> Void] = [] + /// Handler for any `HTTPURLResponse`s received. + var httpResponseHandler: (queue: DispatchQueue, + handler: (_ response: HTTPURLResponse, + _ completionHandler: @escaping (ResponseDisposition) -> Void) -> Void)? } - @Protected - var streamMutableState = StreamMutableState() + let streamMutableState = Protected(StreamMutableState()) /// Creates a `DataStreamRequest` using the provided parameters. /// @@ -1306,7 +1396,7 @@ public final class DataStreamRequest: Request { } override func finish(error: AFError? = nil) { - $streamMutableState.write { state in + streamMutableState.write { state in state.outputStream?.close() } @@ -1314,8 +1404,8 @@ public final class DataStreamRequest: Request { } func didReceive(data: Data) { - $streamMutableState.write { state in - #if !(os(Linux) || os(Windows)) + streamMutableState.write { state in + #if !canImport(FoundationNetworking) // If we not using swift-corelibs-foundation. if let stream = state.outputStream { underlyingQueue.async { var bytes = Array(data) @@ -1329,6 +1419,30 @@ public final class DataStreamRequest: Request { } } + func didReceiveResponse(_ response: HTTPURLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) { + streamMutableState.read { dataMutableState in + guard let httpResponseHandler = dataMutableState.httpResponseHandler else { + underlyingQueue.async { completionHandler(.allow) } + return + } + + httpResponseHandler.queue.async { + httpResponseHandler.handler(response) { disposition in + if disposition == .cancel { + self.mutableState.write { mutableState in + mutableState.state = .cancelled + mutableState.error = mutableState.error ?? AFError.explicitlyCancelled + } + } + + self.underlyingQueue.async { + completionHandler(disposition.sessionDisposition) + } + } + } + } + } + /// Validates the `URLRequest` and `HTTPURLResponse` received for the instance using the provided `Validation` closure. /// /// - Parameter validation: `Validation` closure used to validate the request and response. @@ -1351,12 +1465,12 @@ public final class DataStreamRequest: Request { withResult: result) } - $validators.write { $0.append(validator) } + validators.write { $0.append(validator) } return self } - #if !(os(Linux) || os(Windows)) + #if !canImport(FoundationNetworking) // If we not using swift-corelibs-foundation. /// Produces an `InputStream` that receives the `Data` received by the instance. /// /// - Note: The `InputStream` produced by this method must have `open()` called before being able to read `Data`. @@ -1370,7 +1484,7 @@ public final class DataStreamRequest: Request { defer { resume() } var inputStream: InputStream? - $streamMutableState.write { state in + streamMutableState.write { state in Foundation.Stream.getBoundStreams(withBufferSize: bufferSize, inputStream: &inputStream, outputStream: &state.outputStream) @@ -1381,6 +1495,47 @@ public final class DataStreamRequest: Request { } #endif + /// Sets a closure called whenever the `DataRequest` produces an `HTTPURLResponse` and providing a completion + /// handler to return a `ResponseDisposition` value. + /// + /// - Parameters: + /// - queue: `DispatchQueue` on which the closure will be called. `.main` by default. + /// - handler: Closure called when the instance produces an `HTTPURLResponse`. The `completionHandler` provided + /// MUST be called, otherwise the request will never complete. + /// + /// - Returns: The instance. + @_disfavoredOverload + @discardableResult + public func onHTTPResponse( + on queue: DispatchQueue = .main, + perform handler: @escaping (_ response: HTTPURLResponse, + _ completionHandler: @escaping (ResponseDisposition) -> Void) -> Void + ) -> Self { + streamMutableState.write { mutableState in + mutableState.httpResponseHandler = (queue, handler) + } + + return self + } + + /// Sets a closure called whenever the `DataRequest` produces an `HTTPURLResponse`. + /// + /// - Parameters: + /// - queue: `DispatchQueue` on which the closure will be called. `.main` by default. + /// - handler: Closure called when the instance produces an `HTTPURLResponse`. + /// + /// - Returns: The instance. + @discardableResult + public func onHTTPResponse(on queue: DispatchQueue = .main, + perform handler: @escaping (HTTPURLResponse) -> Void) -> Self { + onHTTPResponse(on: queue) { response, completionHandler in + handler(response) + completionHandler(.allow) + } + + return self + } + func capturingError(from closure: () throws -> Void) { do { try closure() @@ -1395,7 +1550,7 @@ public final class DataStreamRequest: Request { appendResponseSerializer { self.underlyingQueue.async { self.responseSerializerDidComplete { - self.$streamMutableState.write { state in + self.streamMutableState.write { state in guard state.numberOfExecutingStreams == 0 else { state.enqueuedCompletionEvents.append { self.enqueueCompletion(on: queue, stream: stream) @@ -1546,23 +1701,22 @@ public class DownloadRequest: Request { } /// Protected mutable state specific to `DownloadRequest`. - @Protected - private var mutableDownloadState = DownloadRequestMutableState() + private let mutableDownloadState = Protected(DownloadRequestMutableState()) /// If the download is resumable and is eventually cancelled or fails, this value may be used to resume the download /// using the `download(resumingWith data:)` API. /// /// - Note: For more information about `resumeData`, see [Apple's documentation](https://developer.apple.com/documentation/foundation/urlsessiondownloadtask/1411634-cancel). public var resumeData: Data? { - #if !(os(Linux) || os(Windows)) - return $mutableDownloadState.resumeData ?? error?.downloadResumeData + #if !canImport(FoundationNetworking) // If we not using swift-corelibs-foundation. + return mutableDownloadState.resumeData ?? error?.downloadResumeData #else - return $mutableDownloadState.resumeData + return mutableDownloadState.resumeData #endif } /// If the download is successful, the `URL` where the file was downloaded. - public var fileURL: URL? { $mutableDownloadState.fileURL } + public var fileURL: URL? { mutableDownloadState.fileURL } // MARK: Initial State @@ -1605,7 +1759,7 @@ public class DownloadRequest: Request { override func reset() { super.reset() - $mutableDownloadState.write { + mutableDownloadState.write { $0.resumeData = nil $0.fileURL = nil } @@ -1620,7 +1774,7 @@ public class DownloadRequest: Request { eventMonitor?.request(self, didFinishDownloadingUsing: task, with: result) switch result { - case let .success(url): $mutableDownloadState.fileURL = url + case let .success(url): mutableDownloadState.fileURL = url case let .failure(error): self.error = error } } @@ -1698,7 +1852,7 @@ public class DownloadRequest: Request { /// /// - Returns: The instance. private func cancel(optionallyProducingResumeData completionHandler: ((_ resumeData: Data?) -> Void)?) -> Self { - $mutableState.write { mutableState in + mutableState.write { mutableState in guard mutableState.state.canTransitionTo(.cancelled) else { return } mutableState.state = .cancelled @@ -1714,7 +1868,7 @@ public class DownloadRequest: Request { // Resume to ensure metrics are gathered. task.resume() task.cancel { resumeData in - self.$mutableDownloadState.resumeData = resumeData + self.mutableDownloadState.resumeData = resumeData self.underlyingQueue.async { self.didCancelTask(task) } completionHandler(resumeData) } @@ -1754,7 +1908,7 @@ public class DownloadRequest: Request { withResult: result) } - $validators.write { $0.append(validator) } + validators.write { $0.append(validator) } return self } diff --git a/Pods/Alamofire/Source/RequestTaskMap.swift b/Pods/Alamofire/Source/RequestTaskMap.swift index 85b58f3..9955875 100644 --- a/Pods/Alamofire/Source/RequestTaskMap.swift +++ b/Pods/Alamofire/Source/RequestTaskMap.swift @@ -131,7 +131,7 @@ struct RequestTaskMap { switch (events.completed, events.metricsGathered) { case (true, _): fatalError("RequestTaskMap consistency error: duplicate completionReceivedForTask call.") - #if os(Linux) // Linux doesn't gather metrics, so unconditionally remove the reference and return true. + #if os(Linux) || os(Android) // Linux doesn't gather metrics, so unconditionally remove the reference and return true. default: self[task] = nil; return true #else case (false, false): diff --git a/Pods/Alamofire/Source/ResponseSerialization.swift b/Pods/Alamofire/Source/ResponseSerialization.swift index 0e718bd..2022ac0 100644 --- a/Pods/Alamofire/Source/ResponseSerialization.swift +++ b/Pods/Alamofire/Source/ResponseSerialization.swift @@ -1153,7 +1153,7 @@ extension DataStreamRequest { } } - $streamMutableState.write { $0.streams.append(parser) } + streamMutableState.write { $0.streams.append(parser) } appendStreamCompletion(on: queue, stream: stream) return self @@ -1195,7 +1195,7 @@ extension DataStreamRequest { } } - $streamMutableState.write { $0.streams.append(parser) } + streamMutableState.write { $0.streams.append(parser) } appendStreamCompletion(on: queue, stream: stream) return self @@ -1230,14 +1230,14 @@ extension DataStreamRequest { } } - $streamMutableState.write { $0.streams.append(parser) } + streamMutableState.write { $0.streams.append(parser) } appendStreamCompletion(on: queue, stream: stream) return self } private func updateAndCompleteIfPossible() { - $streamMutableState.write { state in + streamMutableState.write { state in state.numberOfExecutingStreams -= 1 guard state.numberOfExecutingStreams == 0, !state.enqueuedCompletionEvents.isEmpty else { return } diff --git a/Pods/Alamofire/Source/ServerTrustEvaluation.swift b/Pods/Alamofire/Source/ServerTrustEvaluation.swift index 4519a3d..e490ab4 100644 --- a/Pods/Alamofire/Source/ServerTrustEvaluation.swift +++ b/Pods/Alamofire/Source/ServerTrustEvaluation.swift @@ -1,5 +1,5 @@ // -// ServerTrustPolicy.swift +// ServerTrustEvaluation.swift // // Copyright (c) 2014-2016 Alamofire Software Foundation (http://alamofire.org/) // @@ -48,7 +48,7 @@ open class ServerTrustManager { self.evaluators = evaluators } - #if !(os(Linux) || os(Windows)) + #if canImport(Security) /// Returns the `ServerTrustEvaluating` value for the given host, if one is set. /// /// By default, this method will return the policy that perfectly matches the given host. Subclasses could override @@ -75,8 +75,8 @@ open class ServerTrustManager { /// A protocol describing the API used to evaluate server trusts. public protocol ServerTrustEvaluating { - #if os(Linux) || os(Windows) - // Implement this once Linux/Windows has API for evaluating server trusts. + #if !canImport(Security) + // Implement this once other platforms have API for evaluating server trusts. #else /// Evaluates the given `SecTrust` value for the given `host`. /// @@ -91,7 +91,7 @@ public protocol ServerTrustEvaluating { // MARK: - Server Trust Evaluators -#if !(os(Linux) || os(Windows)) +#if canImport(Security) /// An evaluator which uses the default server trust evaluation while allowing you to control whether to validate the /// host provided by the challenge. Applications are encouraged to always validate the host in production environments /// to guarantee the validity of the server's certificate chain. @@ -181,6 +181,15 @@ public final class RevocationTrustEvaluator: ServerTrustEvaluating { try trust.af.performValidation(forHost: host) } + #if swift(>=5.9) + if #available(iOS 12, macOS 10.14, tvOS 12, watchOS 5, visionOS 1, *) { + try trust.af.evaluate(afterApplying: SecPolicy.af.revocation(options: options)) + } else { + try trust.af.validate(policy: SecPolicy.af.revocation(options: options)) { status, result in + AFError.serverTrustEvaluationFailed(reason: .revocationCheckFailed(output: .init(host, trust, status, result), options: options)) + } + } + #else if #available(iOS 12, macOS 10.14, tvOS 12, watchOS 5, *) { try trust.af.evaluate(afterApplying: SecPolicy.af.revocation(options: options)) } else { @@ -188,6 +197,7 @@ public final class RevocationTrustEvaluator: ServerTrustEvaluating { AFError.serverTrustEvaluationFailed(reason: .revocationCheckFailed(output: .init(host, trust, status, result), options: options)) } } + #endif } } @@ -355,10 +365,8 @@ public final class PublicKeysTrustEvaluator: ServerTrustEvaluating { let pinnedKeysInServerKeys: Bool = { for serverPublicKey in trust.af.publicKeys { - for pinnedPublicKey in keys { - if serverPublicKey == pinnedPublicKey { - return true - } + if keys.contains(serverPublicKey) { + return true } } return false @@ -449,7 +457,7 @@ public final class DisabledTrustEvaluator: ServerTrustEvaluating { // MARK: - Extensions extension Array where Element == ServerTrustEvaluating { - #if os(Linux) || os(Windows) + #if os(Linux) || os(Windows) || os(Android) // Add this same convenience method for Linux/Windows. #else /// Evaluates the given `SecTrust` value for the given `host`. @@ -598,7 +606,15 @@ extension AlamofireExtension where ExtendedType == SecTrust { /// The `SecCertificate`s contained in `self`. public var certificates: [SecCertificate] { - #if swift(>=5.5.1) // Xcode 13.1 / 2021 SDKs. + #if swift(>=5.9) + if #available(iOS 15, macOS 12, tvOS 15, watchOS 8, visionOS 1, *) { + return (SecTrustCopyCertificateChain(type) as? [SecCertificate]) ?? [] + } else { + return (0..=5.5.1) // Xcode 13.1 / 2021 SDKs. if #available(iOS 15, macOS 12, tvOS 15, watchOS 8, *) { return (SecTrustCopyCertificateChain(type) as? [SecCertificate]) ?? [] } else { @@ -623,6 +639,15 @@ extension AlamofireExtension where ExtendedType == SecTrust { /// - Parameter host: The hostname, used only in the error output if validation fails. /// - Throws: An `AFError.serverTrustEvaluationFailed` instance with a `.defaultEvaluationFailed` reason. public func performDefaultValidation(forHost host: String) throws { + #if swift(>=5.9) + if #available(iOS 12, macOS 10.14, tvOS 12, watchOS 5, visionOS 1, *) { + try evaluate(afterApplying: SecPolicy.af.default) + } else { + try validate(policy: SecPolicy.af.default) { status, result in + AFError.serverTrustEvaluationFailed(reason: .defaultEvaluationFailed(output: .init(host, type, status, result))) + } + } + #else if #available(iOS 12, macOS 10.14, tvOS 12, watchOS 5, *) { try evaluate(afterApplying: SecPolicy.af.default) } else { @@ -630,6 +655,7 @@ extension AlamofireExtension where ExtendedType == SecTrust { AFError.serverTrustEvaluationFailed(reason: .defaultEvaluationFailed(output: .init(host, type, status, result))) } } + #endif } /// Validates `self` after applying `SecPolicy.af.hostname(host)`, which performs the default validation as well as @@ -638,6 +664,15 @@ extension AlamofireExtension where ExtendedType == SecTrust { /// - Parameter host: The hostname to use in the validation. /// - Throws: An `AFError.serverTrustEvaluationFailed` instance with a `.defaultEvaluationFailed` reason. public func performValidation(forHost host: String) throws { + #if swift(>=5.9) + if #available(iOS 12, macOS 10.14, tvOS 12, watchOS 5, visionOS 1, *) { + try evaluate(afterApplying: SecPolicy.af.hostname(host)) + } else { + try validate(policy: SecPolicy.af.hostname(host)) { status, result in + AFError.serverTrustEvaluationFailed(reason: .hostValidationFailed(output: .init(host, type, status, result))) + } + } + #else if #available(iOS 12, macOS 10.14, tvOS 12, watchOS 5, *) { try evaluate(afterApplying: SecPolicy.af.hostname(host)) } else { @@ -645,6 +680,7 @@ extension AlamofireExtension where ExtendedType == SecTrust { AFError.serverTrustEvaluationFailed(reason: .hostValidationFailed(output: .init(host, type, status, result))) } } + #endif } } @@ -704,11 +740,19 @@ extension AlamofireExtension where ExtendedType == SecCertificate { guard let createdTrust = trust, trustCreationStatus == errSecSuccess else { return nil } + #if swift(>=5.9) + if #available(iOS 14, macOS 11, tvOS 14, watchOS 7, visionOS 1, *) { + return SecTrustCopyKey(createdTrust) + } else { + return SecTrustCopyPublicKey(createdTrust) + } + #else if #available(iOS 14, macOS 11, tvOS 14, watchOS 7, *) { return SecTrustCopyKey(createdTrust) } else { return SecTrustCopyPublicKey(createdTrust) } + #endif } } diff --git a/Pods/Alamofire/Source/SessionDelegate.swift b/Pods/Alamofire/Source/SessionDelegate.swift index a794d83..af45b27 100644 --- a/Pods/Alamofire/Source/SessionDelegate.swift +++ b/Pods/Alamofire/Source/SessionDelegate.swift @@ -94,7 +94,7 @@ extension SessionDelegate: URLSessionTaskDelegate { case NSURLAuthenticationMethodHTTPBasic, NSURLAuthenticationMethodHTTPDigest, NSURLAuthenticationMethodNTLM, NSURLAuthenticationMethodNegotiate: evaluation = attemptCredentialAuthentication(for: challenge, belongingTo: task) - #if !(os(Linux) || os(Windows)) + #if canImport(Security) case NSURLAuthenticationMethodServerTrust: evaluation = attemptServerTrustAuthentication(with: challenge) case NSURLAuthenticationMethodClientCertificate: @@ -111,7 +111,7 @@ extension SessionDelegate: URLSessionTaskDelegate { completionHandler(evaluation.disposition, evaluation.credential) } - #if !(os(Linux) || os(Windows)) + #if canImport(Security) /// Evaluates the server trust `URLAuthenticationChallenge` received. /// /// - Parameter challenge: The `URLAuthenticationChallenge`. @@ -230,6 +230,25 @@ extension SessionDelegate: URLSessionTaskDelegate { // MARK: URLSessionDataDelegate extension SessionDelegate: URLSessionDataDelegate { + open func urlSession(_ session: URLSession, + dataTask: URLSessionDataTask, + didReceive response: URLResponse, + completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) { + eventMonitor?.urlSession(session, dataTask: dataTask, didReceive: response) + + guard let response = response as? HTTPURLResponse else { completionHandler(.allow); return } + + if let request = request(for: dataTask, as: DataRequest.self) { + request.didReceiveResponse(response, completionHandler: completionHandler) + } else if let request = request(for: dataTask, as: DataStreamRequest.self) { + request.didReceiveResponse(response, completionHandler: completionHandler) + } else { + assertionFailure("dataTask did not find DataRequest or DataStreamRequest in didReceive response") + completionHandler(.allow) + return + } + } + open func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) { eventMonitor?.urlSession(session, dataTask: dataTask, didReceive: data) @@ -238,7 +257,7 @@ extension SessionDelegate: URLSessionDataDelegate { } else if let request = request(for: dataTask, as: DataStreamRequest.self) { request.didReceive(data: data) } else { - assertionFailure("dataTask did not find DataRequest or DataStreamRequest in didReceive") + assertionFailure("dataTask did not find DataRequest or DataStreamRequest in didReceive data") return } } diff --git a/Pods/Alamofire/Source/URLEncodedFormEncoder.swift b/Pods/Alamofire/Source/URLEncodedFormEncoder.swift index dcb5991..cfbd7e4 100644 --- a/Pods/Alamofire/Source/URLEncodedFormEncoder.swift +++ b/Pods/Alamofire/Source/URLEncodedFormEncoder.swift @@ -695,6 +695,74 @@ extension _URLEncodedFormEncoder.KeyedContainer: KeyedEncodingContainerProtocol try encode(nilValue, forKey: key) } + func encodeIfPresent(_ value: Bool?, forKey key: Key) throws { + try _encodeIfPresent(value, forKey: key) + } + + func encodeIfPresent(_ value: String?, forKey key: Key) throws { + try _encodeIfPresent(value, forKey: key) + } + + func encodeIfPresent(_ value: Double?, forKey key: Key) throws { + try _encodeIfPresent(value, forKey: key) + } + + func encodeIfPresent(_ value: Float?, forKey key: Key) throws { + try _encodeIfPresent(value, forKey: key) + } + + func encodeIfPresent(_ value: Int?, forKey key: Key) throws { + try _encodeIfPresent(value, forKey: key) + } + + func encodeIfPresent(_ value: Int8?, forKey key: Key) throws { + try _encodeIfPresent(value, forKey: key) + } + + func encodeIfPresent(_ value: Int16?, forKey key: Key) throws { + try _encodeIfPresent(value, forKey: key) + } + + func encodeIfPresent(_ value: Int32?, forKey key: Key) throws { + try _encodeIfPresent(value, forKey: key) + } + + func encodeIfPresent(_ value: Int64?, forKey key: Key) throws { + try _encodeIfPresent(value, forKey: key) + } + + func encodeIfPresent(_ value: UInt?, forKey key: Key) throws { + try _encodeIfPresent(value, forKey: key) + } + + func encodeIfPresent(_ value: UInt8?, forKey key: Key) throws { + try _encodeIfPresent(value, forKey: key) + } + + func encodeIfPresent(_ value: UInt16?, forKey key: Key) throws { + try _encodeIfPresent(value, forKey: key) + } + + func encodeIfPresent(_ value: UInt32?, forKey key: Key) throws { + try _encodeIfPresent(value, forKey: key) + } + + func encodeIfPresent(_ value: UInt64?, forKey key: Key) throws { + try _encodeIfPresent(value, forKey: key) + } + + func encodeIfPresent(_ value: Value?, forKey key: Key) throws where Value: Encodable { + try _encodeIfPresent(value, forKey: key) + } + + func _encodeIfPresent(_ value: Value?, forKey key: Key) throws where Value: Encodable { + if let value = value { + try encode(value, forKey: key) + } else { + try encodeNil(forKey: key) + } + } + func encode(_ value: T, forKey key: Key) throws where T: Encodable { var container = nestedSingleValueEncoder(for: key) try container.encode(value) diff --git a/Pods/DDNetworkingOfAlamofireKit_Private/DDNetworkingOfAlamofireKit_Private/Classes/DDAF.swift b/Pods/DDNetworkingOfAlamofireKit_Private/DDNetworkingOfAlamofireKit_Private/Classes/DDAF.swift index 4aa4667..ba0c1f9 100644 --- a/Pods/DDNetworkingOfAlamofireKit_Private/DDNetworkingOfAlamofireKit_Private/Classes/DDAF.swift +++ b/Pods/DDNetworkingOfAlamofireKit_Private/DDNetworkingOfAlamofireKit_Private/Classes/DDAF.swift @@ -17,52 +17,76 @@ extension DDAlamofire { public init() {} } + public enum DDError : Error { + case allError + } + // MARK: example - public func get(urlString:String,parameters:P? = DDParameters(),encoding:ParameterEncoder = URLEncodedFormParameterEncoder.default,headers:HTTPHeaders? = nil,responseType:T.Type = T.self) -> Single { + public func get(urlString:String,parameters:P? = DDParameters(),encoding:ParameterEncoder = URLEncodedFormParameterEncoder.default,headers:HTTPHeaders? = nil,responseType:T.Type = T.self,completionHandler: (((SingleEvent) -> Void,AFDataResponse) -> Void)? = nil) -> Single { return Single.create {[weak self] single in self?.request(urlString: urlString, method: .get,parameters: parameters,encoding: encoding,headers: headers,responseType: responseType,completionHandler: {[weak self] response in self?.logInfo(parameters: parameters, response: response) - single(.success(response.value)) + if let completionHandler { + completionHandler(single,response) + }else{ + single(.success(response.value)) + } }) return Disposables.create() } } - public func post(urlString:String,parameters:P? = DDParameters(),encoding:ParameterEncoder = URLEncodedFormParameterEncoder.default,headers:HTTPHeaders? = nil,responseType:T.Type = T.self) -> Single { + public func post(urlString:String,parameters:P? = DDParameters(),encoding:ParameterEncoder = URLEncodedFormParameterEncoder.default,headers:HTTPHeaders? = nil,responseType:T.Type = T.self,completionHandler: (((SingleEvent) -> Void,AFDataResponse) -> Void)? = nil) -> Single { return Single.create {[weak self] single in self?.request(urlString: urlString, method: .post,parameters: parameters,encoding: encoding,headers: headers,responseType: responseType,completionHandler: {[weak self] response in self?.logInfo(parameters: parameters, response: response) - single(.success(response.value)) + if let completionHandler { + completionHandler(single,response) + }else{ + single(.success(response.value)) + } }) return Disposables.create() } } - public func get(urlString:String,parameters:[String:Any]? = nil,encoding:ParameterEncoding = URLEncoding.default,headers:HTTPHeaders? = nil,responseType:T.Type = T.self) -> Single { + public func get(urlString:String,parameters:[String:Any]? = nil,encoding:ParameterEncoding = URLEncoding.default,headers:HTTPHeaders? = nil,responseType:T.Type = T.self,completionHandler: (((SingleEvent) -> Void,AFDataResponse) -> Void)? = nil) -> Single { return Single.create {[weak self] single in self?.request(urlString: urlString, method: .get,parameters: parameters,encoding: encoding,headers: headers,responseType: responseType,completionHandler: {[weak self] response in self?.logInfo(parameters: parameters, response: response) - single(.success(response.value)) + if let completionHandler { + completionHandler(single,response) + }else{ + single(.success(response.value)) + } }) return Disposables.create() } } - public func post(urlString:String,parameters:[String:Any]? = nil,encoding:ParameterEncoding = URLEncoding.default,headers:HTTPHeaders? = nil,responseType:T.Type = T.self) -> Single { + public func post(urlString:String,parameters:[String:Any]? = nil,encoding:ParameterEncoding = URLEncoding.default,headers:HTTPHeaders? = nil,responseType:T.Type = T.self,completionHandler: (((SingleEvent) -> Void,AFDataResponse) -> Void)? = nil) -> Single { return Single.create {[weak self] single in self?.request(urlString: urlString, method: .post,parameters: parameters,encoding: encoding,headers: headers,responseType: responseType,completionHandler: {[weak self] response in self?.logInfo(parameters: parameters, response: response) - single(.success(response.value)) + if let completionHandler { + completionHandler(single,response) + }else{ + single(.success(response.value)) + } }) return Disposables.create() } } - public func upload(urlString:String,headers:HTTPHeaders? = nil,responseType:T.Type = T.self,multipartFormData: @escaping (MultipartFormData) -> Void,uploadProgress: @escaping (Progress) -> Void) -> Single { + public func upload(urlString:String,headers:HTTPHeaders? = nil,responseType:T.Type = T.self,multipartFormData: @escaping (MultipartFormData) -> Void,uploadProgress: @escaping (Progress) -> Void,completionHandler: (((SingleEvent) -> Void,AFDataResponse) -> Void)? = nil) -> Single { return Single.create {[weak self] single in self?.upload(urlString: urlString,method: .post,headers: headers,responseType: responseType,multipartFormData: multipartFormData,uploadProgress: uploadProgress,completionHandler: { response in self?.logInfo(parameters: nil, response: response) - single(.success(response.value)) + if let completionHandler { + completionHandler(single,response) + }else{ + single(.success(response.value)) + } }) return Disposables.create() } diff --git a/Pods/Manifest.lock b/Pods/Manifest.lock index c26efa5..9a0af78 100644 --- a/Pods/Manifest.lock +++ b/Pods/Manifest.lock @@ -1,5 +1,5 @@ PODS: - - Alamofire (5.7.1) + - Alamofire (5.8.1) - AMapFoundation-NO-IDFA (1.8.2) - AMapLocation-NO-IDFA (2.9.0): - AMapFoundation-NO-IDFA (>= 1.7.0) @@ -270,7 +270,7 @@ PODS: - DDLogKit_Private - DDMAMapKit_Private/DDMAUtil (0.1.5): - DDMAMapKit_Private/DDMAMap - - DDNetworkingOfAlamofireKit_Private (0.1.8): + - DDNetworkingOfAlamofireKit_Private (0.2.1): - Alamofire - DDLogKit_Private - RxSwift @@ -412,7 +412,7 @@ SPEC REPOS: - ZLPhotoBrowser SPEC CHECKSUMS: - Alamofire: 0123a34370cb170936ae79a8df46cc62b2edeb88 + Alamofire: 3ca42e259043ee0dc5c0cdd76c4bc568b8e42af7 AMapFoundation-NO-IDFA: 6ce0ef596d4eb8d934ff498e56747b6de1247b05 AMapLocation-NO-IDFA: 6839d1543b3138ae594ddd36ab72741dc87df66f AMapNavi-NO-IDFA: 70c724400376bfadcb8ec08b9761f526096cfdb6 @@ -430,7 +430,7 @@ SPEC CHECKSUMS: DDFontKit_Private: 7b8f4ebf0f60622874036202734d8460dc7b3806 DDLogKit_Private: 1ed442cc7be004bd05f27bfda9b525e113df54e0 DDMAMapKit_Private: b378d69f693d6998d136155cd5c81be2e4545fae - DDNetworkingOfAlamofireKit_Private: d65c96f99bc59311d374e7b7a7e8a9e042d9b5ea + DDNetworkingOfAlamofireKit_Private: 652eb70a7d8bac81d77d036fabeb52f807120f6d DDPersistenceKit_Private: c150822543ffa6ece3900178629812f64902ed90 DDProgressHUDKit_Private: 1e219062ddeb7801a4bb13b367efa1f3fbf17f1e DDTimerSwiftKit_Private: cce3fe58b1b581fe4cddb3fb84fcde31b4e83541