commit
baeaabdd59
@ -0,0 +1,20 @@ |
||||
# Uncomment the next line to define a global platform for your project |
||||
platform :ios, '13.0' |
||||
|
||||
target 'Weibo' do |
||||
# Comment the next line if you don't want to use dynamic frameworks |
||||
use_frameworks! |
||||
pod "Weibo_SDK", :git => "https://github.com/sinaweibosdk/weibo_ios_sdk.git" |
||||
pod 'AlamofireImage', '~> 4.1' |
||||
# Pods for Weibo |
||||
|
||||
target 'WeiboTests' do |
||||
inherit! :search_paths |
||||
# Pods for testing |
||||
end |
||||
|
||||
target 'WeiboUITests' do |
||||
# Pods for testing |
||||
end |
||||
|
||||
end |
@ -0,0 +1,32 @@ |
||||
PODS: |
||||
- Alamofire (5.2.2) |
||||
- AlamofireImage (4.1.0): |
||||
- Alamofire (~> 5.1) |
||||
- Weibo_SDK (3.2.7) |
||||
|
||||
DEPENDENCIES: |
||||
- AlamofireImage (~> 4.1) |
||||
- Weibo_SDK (from `https://github.com/sinaweibosdk/weibo_ios_sdk.git`) |
||||
|
||||
SPEC REPOS: |
||||
trunk: |
||||
- Alamofire |
||||
- AlamofireImage |
||||
|
||||
EXTERNAL SOURCES: |
||||
Weibo_SDK: |
||||
:git: https://github.com/sinaweibosdk/weibo_ios_sdk.git |
||||
|
||||
CHECKOUT OPTIONS: |
||||
Weibo_SDK: |
||||
:commit: 90a5cf8d5dfb03ccf62b1c8e1a17fea766dc806b |
||||
:git: https://github.com/sinaweibosdk/weibo_ios_sdk.git |
||||
|
||||
SPEC CHECKSUMS: |
||||
Alamofire: 814429acc853c6c54ff123fc3d2ef66803823ce0 |
||||
AlamofireImage: c4a2ba349885fb3064feb74d2e547bd42ce9be10 |
||||
Weibo_SDK: 5a4d08f7e1fedbb635435e4585c8c0439c7da089 |
||||
|
||||
PODFILE CHECKSUM: 599c8e5ab6c4a30be0c9160b75846117173d99df |
||||
|
||||
COCOAPODS: 1.9.3 |
@ -0,0 +1,19 @@ |
||||
Copyright (c) 2014-2020 Alamofire Software Foundation (http://alamofire.org/) |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
of this software and associated documentation files (the "Software"), to deal |
||||
in the Software without restriction, including without limitation the rights |
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
copies of the Software, and to permit persons to whom the Software is |
||||
furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in |
||||
all copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
||||
THE SOFTWARE. |
@ -0,0 +1,206 @@ |
||||
 |
||||
|
||||
[](https://github.com/Alamofire/Alamofire/actions) |
||||
[](https://img.shields.io/cocoapods/v/Alamofire.svg) |
||||
[](https://github.com/Carthage/Carthage) |
||||
[](https://alamofire.github.io/Alamofire) |
||||
[](https://twitter.com/AlamofireSF) |
||||
[](https://gitter.im/Alamofire/Alamofire?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) |
||||
[](https://www.codetriage.com/alamofire/alamofire) |
||||
|
||||
Alamofire is an HTTP networking library written in Swift. |
||||
|
||||
- [Features](#features) |
||||
- [Component Libraries](#component-libraries) |
||||
- [Requirements](#requirements) |
||||
- [Migration Guides](#migration-guides) |
||||
- [Communication](#communication) |
||||
- [Installation](#installation) |
||||
- [Usage](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#using-alamofire) |
||||
- [**Introduction -**](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#introduction) [Making Requests](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#making-requests), [Response Handling](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#response-handling), [Response Validation](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#response-validation), [Response Caching](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#response-caching) |
||||
- **HTTP -** [HTTP Methods](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#http-methods), [Parameters and Parameter Encoder](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md##request-parameters-and-parameter-encoders), [HTTP Headers](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#http-headers), [Authentication](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#authentication) |
||||
- **Large Data -** [Downloading Data to a File](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#downloading-data-to-a-file), [Uploading Data to a Server](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#uploading-data-to-a-server) |
||||
- **Tools -** [Statistical Metrics](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#statistical-metrics), [cURL Command Output](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#curl-command-output) |
||||
- [Advanced Usage](https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md) |
||||
- **URL Session -** [Session Manager](https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#session), [Session Delegate](https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#sessiondelegate), [Request](https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#request) |
||||
- **Routing -** [Routing Requests](https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#routing-requests), [Adapting and Retrying Requests](https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#adapting-and-retrying-requests-with-requestinterceptor) |
||||
- **Model Objects -** [Custom Response Handlers](https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#customizing-response-handlers) |
||||
- **Connection -** [Security](https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#security), [Network Reachability](https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#network-reachability) |
||||
- [Open Radars](#open-radars) |
||||
- [FAQ](#faq) |
||||
- [Credits](#credits) |
||||
- [Donations](#donations) |
||||
- [License](#license) |
||||
|
||||
## Features |
||||
|
||||
- [x] Chainable Request / Response Methods |
||||
- [x] Combine Support |
||||
- [x] URL / JSON Parameter Encoding |
||||
- [x] Upload File / Data / Stream / MultipartFormData |
||||
- [x] Download File using Request or Resume Data |
||||
- [x] Authentication with `URLCredential` |
||||
- [x] HTTP Response Validation |
||||
- [x] Upload and Download Progress Closures with Progress |
||||
- [x] cURL Command Output |
||||
- [x] Dynamically Adapt and Retry Requests |
||||
- [x] TLS Certificate and Public Key Pinning |
||||
- [x] Network Reachability |
||||
- [x] Comprehensive Unit and Integration Test Coverage |
||||
- [x] [Complete Documentation](https://alamofire.github.io/Alamofire) |
||||
|
||||
## 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. |
||||
|
||||
- [AlamofireImage](https://github.com/Alamofire/AlamofireImage) - An image library including image response serializers, `UIImage` and `UIImageView` extensions, custom image filters, an auto-purging in-memory cache and a priority-based image downloading system. |
||||
- [AlamofireNetworkActivityIndicator](https://github.com/Alamofire/AlamofireNetworkActivityIndicator) - Controls the visibility of the network activity indicator on iOS using Alamofire. It contains configurable delay timers to help mitigate flicker and can support `URLSession` instances not managed by Alamofire. |
||||
|
||||
## Requirements |
||||
|
||||
- iOS 10.0+ / macOS 10.12+ / tvOS 10.0+ / watchOS 3.0+ |
||||
- Xcode 11+ |
||||
- Swift 5.1+ |
||||
|
||||
## Migration Guides |
||||
|
||||
- [Alamofire 5.0 Migration Guide](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Alamofire%205.0%20Migration%20Guide.md) |
||||
- [Alamofire 4.0 Migration Guide](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Alamofire%204.0%20Migration%20Guide.md) |
||||
- [Alamofire 3.0 Migration Guide](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Alamofire%203.0%20Migration%20Guide.md) |
||||
- [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 **found a bug**, open an issue here on GitHub and follow the guide. The more detail the better! |
||||
- If you **want to contribute**, submit a pull request! |
||||
|
||||
## Installation |
||||
|
||||
### CocoaPods |
||||
|
||||
[CocoaPods](https://cocoapods.org) is a dependency manager for Cocoa projects. For usage and installation instructions, visit their website. To integrate Alamofire into your Xcode project using CocoaPods, specify it in your `Podfile`: |
||||
|
||||
```ruby |
||||
pod 'Alamofire', '~> 5.2' |
||||
``` |
||||
|
||||
### Carthage |
||||
|
||||
[Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks. To integrate Alamofire into your Xcode project using Carthage, specify it in your `Cartfile`: |
||||
|
||||
```ogdl |
||||
github "Alamofire/Alamofire" ~> 5.2 |
||||
``` |
||||
|
||||
### 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. It is in early development, but Alamofire does support its use on supported platforms. |
||||
|
||||
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.2.0")) |
||||
] |
||||
``` |
||||
|
||||
### Manually |
||||
|
||||
If you prefer not to use any of the aforementioned dependency managers, you can integrate Alamofire into your project manually. |
||||
|
||||
#### Embedded Framework |
||||
|
||||
- Open up Terminal, `cd` into your top-level project directory, and run the following command "if" your project is not initialized as a git repository: |
||||
|
||||
```bash |
||||
$ git init |
||||
``` |
||||
|
||||
- Add Alamofire as a git [submodule](https://git-scm.com/docs/git-submodule) by running the following command: |
||||
|
||||
```bash |
||||
$ git submodule add https://github.com/Alamofire/Alamofire.git |
||||
``` |
||||
|
||||
- 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. |
||||
|
||||
- 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. |
||||
- In the tab bar at the top of that window, open the "General" panel. |
||||
- 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`. |
||||
|
||||
- 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 either `Alamofire iOS`, `Alamofire macOS`, `Alamofire tvOS` or `Alamofire watchOS`. |
||||
|
||||
- And that's it! |
||||
|
||||
> The `Alamofire.framework` is automagically added as a target dependency, linked framework and embedded framework in a copy files build phase which is all you need to build on the simulator and a device. |
||||
|
||||
## Open Radars |
||||
|
||||
The following radars have some effect on the current implementation of Alamofire. |
||||
|
||||
- [`rdar://21349340`](http://www.openradar.me/radar?id=5517037090635776) - Compiler throwing warning due to toll-free bridging issue in test case |
||||
- `rdar://26870455` - Background URL Session Configurations do not work in the simulator |
||||
- `rdar://26849668` - Some URLProtocol APIs do not properly handle `URLRequest` |
||||
- `FB7624529` - `urlSession(_:task:didFinishCollecting:)` never called on watchOS |
||||
|
||||
## Resolved Radars |
||||
|
||||
The following radars have been resolved over time after being filed against the Alamofire project. |
||||
|
||||
- [`rdar://26761490`](http://www.openradar.me/radar?id=5010235949318144) - Swift string interpolation causing memory leak with common usage. |
||||
- (Resolved): 9/1/17 in Xcode 9 beta 6. |
||||
- [`rdar://36082113`](http://openradar.appspot.com/radar?id=4942308441063424) - `URLSessionTaskMetrics` failing to link on watchOS 3.0+ |
||||
- (Resolved): Just add `CFNetwork` to your linked frameworks. |
||||
|
||||
## Workarounds |
||||
|
||||
- Collection of `URLSessionTaskMetrics` is currently disabled on watchOS due to `FB7624529`. |
||||
|
||||
## FAQ |
||||
|
||||
### What's the origin of the name Alamofire? |
||||
|
||||
Alamofire is named after the [Alamo Fire flower](https://aggie-horticulture.tamu.edu/wildseed/alamofire.html), a hybrid variant of the Bluebonnet, the official state flower of Texas. |
||||
|
||||
## Credits |
||||
|
||||
Alamofire is owned and maintained by the [Alamofire Software Foundation](http://alamofire.org). You can follow them on Twitter at [@AlamofireSF](https://twitter.com/AlamofireSF) for project updates and releases. |
||||
|
||||
### Security Disclosure |
||||
|
||||
If you believe you have identified a security vulnerability with Alamofire, you should report it as soon as possible via email to security@alamofire.org. Please do not post it to a public issue tracker. |
||||
|
||||
## Donations |
||||
|
||||
The [ASF](https://github.com/Alamofire/Foundation#members) is looking to raise money to officially stay registered as a federal non-profit organization. |
||||
Registering will allow us members to gain some legal protections and also allow us to put donations to use, tax-free. |
||||
Donating to the ASF will enable us to: |
||||
|
||||
- Pay our yearly legal fees to keep the non-profit in good status |
||||
- Pay for our mail servers to help us stay on top of all questions and security issues |
||||
- Potentially fund test servers to make it easier for us to test the edge cases |
||||
- Potentially fund developers to work on one of our projects full-time |
||||
|
||||
The community adoption of the ASF libraries has been amazing. |
||||
We are greatly humbled by your enthusiasm around the projects and want to continue to do everything we can to move the needle forward. |
||||
With your continued support, the ASF will be able to improve its reach and also provide better legal safety for the core members. |
||||
If you use any of our libraries for work, see if your employers would be interested in donating. |
||||
Any amount you can donate today to help us reach our goal would be greatly appreciated. |
||||
|
||||
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=W34WPEE74APJQ) |
||||
|
||||
## License |
||||
|
||||
Alamofire is released under the MIT license. [See LICENSE](https://github.com/Alamofire/Alamofire/blob/master/LICENSE) for details. |
@ -0,0 +1,840 @@ |
||||
// |
||||
// AFError.swift |
||||
// |
||||
// Copyright (c) 2014-2018 Alamofire Software Foundation (http://alamofire.org/) |
||||
// |
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
// of this software and associated documentation files (the "Software"), to deal |
||||
// in the Software without restriction, including without limitation the rights |
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
// copies of the Software, and to permit persons to whom the Software is |
||||
// furnished to do so, subject to the following conditions: |
||||
// |
||||
// The above copyright notice and this permission notice shall be included in |
||||
// all copies or substantial portions of the Software. |
||||
// |
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
||||
// THE SOFTWARE. |
||||
// |
||||
|
||||
import Foundation |
||||
|
||||
/// `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 { |
||||
/// The underlying reason the `.multipartEncodingFailed` error occurred. |
||||
public enum MultipartEncodingFailureReason { |
||||
/// The `fileURL` provided for reading an encodable body part isn't a file `URL`. |
||||
case bodyPartURLInvalid(url: URL) |
||||
/// The filename of the `fileURL` provided has either an empty `lastPathComponent` or `pathExtension. |
||||
case bodyPartFilenameInvalid(in: URL) |
||||
/// The file at the `fileURL` provided was not reachable. |
||||
case bodyPartFileNotReachable(at: URL) |
||||
/// Attempting to check the reachability of the `fileURL` provided threw an error. |
||||
case bodyPartFileNotReachableWithError(atURL: URL, error: Error) |
||||
/// The file at the `fileURL` provided is actually a directory. |
||||
case bodyPartFileIsDirectory(at: URL) |
||||
/// The size of the file at the `fileURL` provided was not returned by the system. |
||||
case bodyPartFileSizeNotAvailable(at: URL) |
||||
/// The attempt to find the size of the file at the `fileURL` provided threw an error. |
||||
case bodyPartFileSizeQueryFailedWithError(forURL: URL, error: Error) |
||||
/// An `InputStream` could not be created for the provided `fileURL`. |
||||
case bodyPartInputStreamCreationFailed(for: URL) |
||||
/// An `OutputStream` could not be created when attempting to write the encoded data to disk. |
||||
case outputStreamCreationFailed(for: URL) |
||||
/// The encoded body data could not be written to disk because a file already exists at the provided `fileURL`. |
||||
case outputStreamFileAlreadyExists(at: URL) |
||||
/// The `fileURL` provided for writing the encoded body data to disk is not a file `URL`. |
||||
case outputStreamURLInvalid(url: URL) |
||||
/// The attempt to write the encoded body data to disk failed with an underlying error. |
||||
case outputStreamWriteFailed(error: Error) |
||||
/// The attempt to read an encoded body part `InputStream` failed with underlying system error. |
||||
case inputStreamReadFailed(error: Error) |
||||
} |
||||
|
||||
/// The underlying reason the `.parameterEncodingFailed` error occurred. |
||||
public enum ParameterEncodingFailureReason { |
||||
/// The `URLRequest` did not have a `URL` to encode. |
||||
case missingURL |
||||
/// JSON serialization failed with an underlying system error during the encoding process. |
||||
case jsonEncodingFailed(error: Error) |
||||
/// Custom parameter encoding failed due to the associated `Error`. |
||||
case customEncodingFailed(error: Error) |
||||
} |
||||
|
||||
/// The underlying reason the `.parameterEncoderFailed` error occurred. |
||||
public enum ParameterEncoderFailureReason { |
||||
/// Possible missing components. |
||||
public enum RequiredComponent { |
||||
/// The `URL` was missing or unable to be extracted from the passed `URLRequest` or during encoding. |
||||
case url |
||||
/// The `HTTPMethod` could not be extracted from the passed `URLRequest`. |
||||
case httpMethod(rawValue: String) |
||||
} |
||||
|
||||
/// A `RequiredComponent` was missing during encoding. |
||||
case missingRequiredComponent(RequiredComponent) |
||||
/// The underlying encoder failed with the associated error. |
||||
case encoderFailed(error: Error) |
||||
} |
||||
|
||||
/// The underlying reason the `.responseValidationFailed` error occurred. |
||||
public enum ResponseValidationFailureReason { |
||||
/// The data file containing the server response did not exist. |
||||
case dataFileNil |
||||
/// The data file containing the server response at the associated `URL` could not be read. |
||||
case dataFileReadFailed(at: URL) |
||||
/// The response did not contain a `Content-Type` and the `acceptableContentTypes` provided did not contain a |
||||
/// wildcard type. |
||||
case missingContentType(acceptableContentTypes: [String]) |
||||
/// The response `Content-Type` did not match any type in the provided `acceptableContentTypes`. |
||||
case unacceptableContentType(acceptableContentTypes: [String], responseContentType: String) |
||||
/// The response status code was not acceptable. |
||||
case unacceptableStatusCode(code: Int) |
||||
/// Custom response validation failed due to the associated `Error`. |
||||
case customValidationFailed(error: Error) |
||||
} |
||||
|
||||
/// The underlying reason the response serialization error occurred. |
||||
public enum ResponseSerializationFailureReason { |
||||
/// The server response contained no data or the data was zero length. |
||||
case inputDataNilOrZeroLength |
||||
/// The file containing the server response did not exist. |
||||
case inputFileNil |
||||
/// The file containing the server response could not be read from the associated `URL`. |
||||
case inputFileReadFailed(at: URL) |
||||
/// String serialization failed using the provided `String.Encoding`. |
||||
case stringSerializationFailed(encoding: String.Encoding) |
||||
/// JSON serialization failed with an underlying system error. |
||||
case jsonSerializationFailed(error: Error) |
||||
/// A `DataDecoder` failed to decode the response due to the associated `Error`. |
||||
case decodingFailed(error: Error) |
||||
/// A custom response serializer failed due to the associated `Error`. |
||||
case customSerializationFailed(error: Error) |
||||
/// Generic serialization failed for an empty response that wasn't type `Empty` but instead the associated type. |
||||
case invalidEmptyResponse(type: String) |
||||
} |
||||
|
||||
/// Underlying reason a server trust evaluation error occurred. |
||||
public enum ServerTrustFailureReason { |
||||
/// The output of a server trust evaluation. |
||||
public struct Output { |
||||
/// The host for which the evaluation was performed. |
||||
public let host: String |
||||
/// The `SecTrust` value which was evaluated. |
||||
public let trust: SecTrust |
||||
/// The `OSStatus` of evaluation operation. |
||||
public let status: OSStatus |
||||
/// The result of the evaluation operation. |
||||
public let result: SecTrustResultType |
||||
|
||||
/// Creates an `Output` value from the provided values. |
||||
init(_ host: String, _ trust: SecTrust, _ status: OSStatus, _ result: SecTrustResultType) { |
||||
self.host = host |
||||
self.trust = trust |
||||
self.status = status |
||||
self.result = result |
||||
} |
||||
} |
||||
|
||||
/// No `ServerTrustEvaluator` was found for the associated host. |
||||
case noRequiredEvaluator(host: String) |
||||
/// No certificates were found with which to perform the trust evaluation. |
||||
case noCertificatesFound |
||||
/// No public keys were found with which to perform the trust evaluation. |
||||
case noPublicKeysFound |
||||
/// During evaluation, application of the associated `SecPolicy` failed. |
||||
case policyApplicationFailed(trust: SecTrust, policy: SecPolicy, status: OSStatus) |
||||
/// During evaluation, setting the associated anchor certificates failed. |
||||
case settingAnchorCertificatesFailed(status: OSStatus, certificates: [SecCertificate]) |
||||
/// During evaluation, creation of the revocation policy failed. |
||||
case revocationPolicyCreationFailed |
||||
/// `SecTrust` evaluation failed with the associated `Error`, if one was produced. |
||||
case trustEvaluationFailed(error: Error?) |
||||
/// Default evaluation failed with the associated `Output`. |
||||
case defaultEvaluationFailed(output: Output) |
||||
/// Host validation failed with the associated `Output`. |
||||
case hostValidationFailed(output: Output) |
||||
/// Revocation check failed with the associated `Output` and options. |
||||
case revocationCheckFailed(output: Output, options: RevocationTrustEvaluator.Options) |
||||
/// Certificate pinning failed. |
||||
case certificatePinningFailed(host: String, trust: SecTrust, pinnedCertificates: [SecCertificate], serverCertificates: [SecCertificate]) |
||||
/// Public key pinning failed. |
||||
case publicKeyPinningFailed(host: String, trust: SecTrust, pinnedKeys: [SecKey], serverKeys: [SecKey]) |
||||
/// Custom server trust evaluation failed due to the associated `Error`. |
||||
case customEvaluationFailed(error: Error) |
||||
} |
||||
|
||||
/// The underlying reason the `.urlRequestValidationFailed` |
||||
public enum URLRequestValidationFailureReason { |
||||
/// URLRequest with GET method had body data. |
||||
case bodyDataInGETRequest(Data) |
||||
} |
||||
|
||||
/// `UploadableConvertible` threw an error in `createUploadable()`. |
||||
case createUploadableFailed(error: Error) |
||||
/// `URLRequestConvertible` threw an error in `asURLRequest()`. |
||||
case createURLRequestFailed(error: Error) |
||||
/// `SessionDelegate` threw an error while attempting to move downloaded file to destination URL. |
||||
case downloadedFileMoveFailed(error: Error, source: URL, destination: URL) |
||||
/// `Request` was explicitly cancelled. |
||||
case explicitlyCancelled |
||||
/// `URLConvertible` type failed to create a valid `URL`. |
||||
case invalidURL(url: URLConvertible) |
||||
/// Multipart form encoding failed. |
||||
case multipartEncodingFailed(reason: MultipartEncodingFailureReason) |
||||
/// `ParameterEncoding` threw an error during the encoding process. |
||||
case parameterEncodingFailed(reason: ParameterEncodingFailureReason) |
||||
/// `ParameterEncoder` threw an error while running the encoder. |
||||
case parameterEncoderFailed(reason: ParameterEncoderFailureReason) |
||||
/// `RequestAdapter` threw an error during adaptation. |
||||
case requestAdaptationFailed(error: Error) |
||||
/// `RequestRetrier` threw an error during the request retry process. |
||||
case requestRetryFailed(retryError: Error, originalError: Error) |
||||
/// Response validation failed. |
||||
case responseValidationFailed(reason: ResponseValidationFailureReason) |
||||
/// Response serialization failed. |
||||
case responseSerializationFailed(reason: ResponseSerializationFailureReason) |
||||
/// `ServerTrustEvaluating` instance threw an error during trust evaluation. |
||||
case serverTrustEvaluationFailed(reason: ServerTrustFailureReason) |
||||
/// `Session` which issued the `Request` was deinitialized, most likely because its reference went out of scope. |
||||
case sessionDeinitialized |
||||
/// `Session` was explicitly invalidated, possibly with the `Error` produced by the underlying `URLSession`. |
||||
case sessionInvalidated(error: Error?) |
||||
/// `URLSessionTask` completed with error. |
||||
case sessionTaskFailed(error: Error) |
||||
/// `URLRequest` failed validation. |
||||
case urlRequestValidationFailed(reason: URLRequestValidationFailureReason) |
||||
} |
||||
|
||||
extension Error { |
||||
/// Returns the instance cast as an `AFError`. |
||||
public var asAFError: AFError? { |
||||
self as? AFError |
||||
} |
||||
|
||||
/// Returns the instance cast as an `AFError`. If casting fails, a `fatalError` with the specified `message` is thrown. |
||||
public func asAFError(orFailWith message: @autoclosure () -> String, file: StaticString = #file, line: UInt = #line) -> AFError { |
||||
guard let afError = self as? AFError else { |
||||
fatalError(message(), file: file, line: line) |
||||
} |
||||
return afError |
||||
} |
||||
|
||||
/// Casts the instance as `AFError` or returns `defaultAFError` |
||||
func asAFError(or defaultAFError: @autoclosure () -> AFError) -> AFError { |
||||
self as? AFError ?? defaultAFError() |
||||
} |
||||
} |
||||
|
||||
// MARK: - Error Booleans |
||||
|
||||
extension AFError { |
||||
/// Returns whether the instance is `.sessionDeinitialized`. |
||||
public var isSessionDeinitializedError: Bool { |
||||
if case .sessionDeinitialized = self { return true } |
||||
return false |
||||
} |
||||
|
||||
/// Returns whether the instance is `.sessionInvalidated`. |
||||
public var isSessionInvalidatedError: Bool { |
||||
if case .sessionInvalidated = self { return true } |
||||
return false |
||||
} |
||||
|
||||
/// Returns whether the instance is `.explicitlyCancelled`. |
||||
public var isExplicitlyCancelledError: Bool { |
||||
if case .explicitlyCancelled = self { return true } |
||||
return false |
||||
} |
||||
|
||||
/// Returns whether the instance is `.invalidURL`. |
||||
public var isInvalidURLError: Bool { |
||||
if case .invalidURL = self { return true } |
||||
return false |
||||
} |
||||
|
||||
/// Returns whether the instance is `.parameterEncodingFailed`. When `true`, the `underlyingError` property will |
||||
/// contain the associated value. |
||||
public var isParameterEncodingError: Bool { |
||||
if case .parameterEncodingFailed = self { return true } |
||||
return false |
||||
} |
||||
|
||||
/// Returns whether the instance is `.parameterEncoderFailed`. When `true`, the `underlyingError` property will |
||||
/// contain the associated value. |
||||
public var isParameterEncoderError: Bool { |
||||
if case .parameterEncoderFailed = self { return true } |
||||
return false |
||||
} |
||||
|
||||
/// Returns whether the instance is `.multipartEncodingFailed`. When `true`, the `url` and `underlyingError` |
||||
/// properties will contain the associated values. |
||||
public var isMultipartEncodingError: Bool { |
||||
if case .multipartEncodingFailed = self { return true } |
||||
return false |
||||
} |
||||
|
||||
/// Returns whether the instance is `.requestAdaptationFailed`. When `true`, the `underlyingError` property will |
||||
/// contain the associated value. |
||||
public var isRequestAdaptationError: Bool { |
||||
if case .requestAdaptationFailed = self { return true } |
||||
return false |
||||
} |
||||
|
||||
/// Returns whether the instance is `.responseValidationFailed`. When `true`, the `acceptableContentTypes`, |
||||
/// `responseContentType`, `responseCode`, and `underlyingError` properties will contain the associated values. |
||||
public var isResponseValidationError: Bool { |
||||
if case .responseValidationFailed = self { return true } |
||||
return false |
||||
} |
||||
|
||||
/// Returns whether the instance is `.responseSerializationFailed`. When `true`, the `failedStringEncoding` and |
||||
/// `underlyingError` properties will contain the associated values. |
||||
public var isResponseSerializationError: Bool { |
||||
if case .responseSerializationFailed = self { return true } |
||||
return false |
||||
} |
||||
|
||||
/// Returns whether the instance is `.serverTrustEvaluationFailed`. When `true`, the `underlyingError` property will |
||||
/// contain the associated value. |
||||
public var isServerTrustEvaluationError: Bool { |
||||
if case .serverTrustEvaluationFailed = self { return true } |
||||
return false |
||||
} |
||||
|
||||
/// Returns whether the instance is `requestRetryFailed`. When `true`, the `underlyingError` property will |
||||
/// contain the associated value. |
||||
public var isRequestRetryError: Bool { |
||||
if case .requestRetryFailed = self { return true } |
||||
return false |
||||
} |
||||
|
||||
/// Returns whether the instance is `createUploadableFailed`. When `true`, the `underlyingError` property will |
||||
/// contain the associated value. |
||||
public var isCreateUploadableError: Bool { |
||||
if case .createUploadableFailed = self { return true } |
||||
return false |
||||
} |
||||
|
||||
/// Returns whether the instance is `createURLRequestFailed`. When `true`, the `underlyingError` property will |
||||
/// contain the associated value. |
||||
public var isCreateURLRequestError: Bool { |
||||
if case .createURLRequestFailed = self { return true } |
||||
return false |
||||
} |
||||
|
||||
/// Returns whether the instance is `downloadedFileMoveFailed`. When `true`, the `destination` and `underlyingError` properties will |
||||
/// contain the associated values. |
||||
public var isDownloadedFileMoveError: Bool { |
||||
if case .downloadedFileMoveFailed = self { return true } |
||||
return false |
||||
} |
||||
|
||||
/// Returns whether the instance is `createURLRequestFailed`. When `true`, the `underlyingError` property will |
||||
/// contain the associated value. |
||||
public var isSessionTaskError: Bool { |
||||
if case .sessionTaskFailed = self { return true } |
||||
return false |
||||
} |
||||
} |
||||
|
||||
// MARK: - Convenience Properties |
||||
|
||||
extension AFError { |
||||
/// The `URLConvertible` associated with the error. |
||||
public var urlConvertible: URLConvertible? { |
||||
guard case let .invalidURL(url) = self else { return nil } |
||||
return url |
||||
} |
||||
|
||||
/// The `URL` associated with the error. |
||||
public var url: URL? { |
||||
guard case let .multipartEncodingFailed(reason) = self else { return nil } |
||||
return reason.url |
||||
} |
||||
|
||||
/// The underlying `Error` responsible for generating the failure associated with `.sessionInvalidated`, |
||||
/// `.parameterEncodingFailed`, `.parameterEncoderFailed`, `.multipartEncodingFailed`, `.requestAdaptationFailed`, |
||||
/// `.responseSerializationFailed`, `.requestRetryFailed` errors. |
||||
public var underlyingError: Error? { |
||||
switch self { |
||||
case let .multipartEncodingFailed(reason): |
||||
return reason.underlyingError |
||||
case let .parameterEncodingFailed(reason): |
||||
return reason.underlyingError |
||||
case let .parameterEncoderFailed(reason): |
||||
return reason.underlyingError |
||||
case let .requestAdaptationFailed(error): |
||||
return error |
||||
case let .requestRetryFailed(retryError, _): |
||||
return retryError |
||||
case let .responseValidationFailed(reason): |
||||
return reason.underlyingError |
||||
case let .responseSerializationFailed(reason): |
||||
return reason.underlyingError |
||||
case let .serverTrustEvaluationFailed(reason): |
||||
return reason.underlyingError |
||||
case let .sessionInvalidated(error): |
||||
return error |
||||
case let .createUploadableFailed(error): |
||||
return error |
||||
case let .createURLRequestFailed(error): |
||||
return error |
||||
case let .downloadedFileMoveFailed(error, _, _): |
||||
return error |
||||
case let .sessionTaskFailed(error): |
||||
return error |
||||
case .explicitlyCancelled, |
||||
.invalidURL, |
||||
.sessionDeinitialized, |
||||
.urlRequestValidationFailed: |
||||
return nil |
||||
} |
||||
} |
||||
|
||||
/// The acceptable `Content-Type`s of a `.responseValidationFailed` error. |
||||
public var acceptableContentTypes: [String]? { |
||||
guard case let .responseValidationFailed(reason) = self else { return nil } |
||||
return reason.acceptableContentTypes |
||||
} |
||||
|
||||
/// The response `Content-Type` of a `.responseValidationFailed` error. |
||||
public var responseContentType: String? { |
||||
guard case let .responseValidationFailed(reason) = self else { return nil } |
||||
return reason.responseContentType |
||||
} |
||||
|
||||
/// The response code of a `.responseValidationFailed` error. |
||||
public var responseCode: Int? { |
||||
guard case let .responseValidationFailed(reason) = self else { return nil } |
||||
return reason.responseCode |
||||
} |
||||
|
||||
/// The `String.Encoding` associated with a failed `.stringResponse()` call. |
||||
public var failedStringEncoding: String.Encoding? { |
||||
guard case let .responseSerializationFailed(reason) = self else { return nil } |
||||
return reason.failedStringEncoding |
||||
} |
||||
|
||||
/// The `source` URL of a `.downloadedFileMoveFailed` error. |
||||
public var sourceURL: URL? { |
||||
guard case let .downloadedFileMoveFailed(_, source, _) = self else { return nil } |
||||
return source |
||||
} |
||||
|
||||
/// The `destination` URL of a `.downloadedFileMoveFailed` error. |
||||
public var destinationURL: URL? { |
||||
guard case let .downloadedFileMoveFailed(_, _, destination) = self else { return nil } |
||||
return destination |
||||
} |
||||
} |
||||
|
||||
extension AFError.ParameterEncodingFailureReason { |
||||
var underlyingError: Error? { |
||||
switch self { |
||||
case let .jsonEncodingFailed(error), |
||||
let .customEncodingFailed(error): |
||||
return error |
||||
case .missingURL: |
||||
return nil |
||||
} |
||||
} |
||||
} |
||||
|
||||
extension AFError.ParameterEncoderFailureReason { |
||||
var underlyingError: Error? { |
||||
switch self { |
||||
case let .encoderFailed(error): |
||||
return error |
||||
case .missingRequiredComponent: |
||||
return nil |
||||
} |
||||
} |
||||
} |
||||
|
||||
extension AFError.MultipartEncodingFailureReason { |
||||
var url: URL? { |
||||
switch self { |
||||
case let .bodyPartURLInvalid(url), |
||||
let .bodyPartFilenameInvalid(url), |
||||
let .bodyPartFileNotReachable(url), |
||||
let .bodyPartFileIsDirectory(url), |
||||
let .bodyPartFileSizeNotAvailable(url), |
||||
let .bodyPartInputStreamCreationFailed(url), |
||||
let .outputStreamCreationFailed(url), |
||||
let .outputStreamFileAlreadyExists(url), |
||||
let .outputStreamURLInvalid(url), |
||||
let .bodyPartFileNotReachableWithError(url, _), |
||||
let .bodyPartFileSizeQueryFailedWithError(url, _): |
||||
return url |
||||
case .outputStreamWriteFailed, |
||||
.inputStreamReadFailed: |
||||
return nil |
||||
} |
||||
} |
||||
|
||||
var underlyingError: Error? { |
||||
switch self { |
||||
case let .bodyPartFileNotReachableWithError(_, error), |
||||
let .bodyPartFileSizeQueryFailedWithError(_, error), |
||||
let .outputStreamWriteFailed(error), |
||||
let .inputStreamReadFailed(error): |
||||
return error |
||||
case .bodyPartURLInvalid, |
||||
.bodyPartFilenameInvalid, |
||||
.bodyPartFileNotReachable, |
||||
.bodyPartFileIsDirectory, |
||||
.bodyPartFileSizeNotAvailable, |
||||
.bodyPartInputStreamCreationFailed, |
||||
.outputStreamCreationFailed, |
||||
.outputStreamFileAlreadyExists, |
||||
.outputStreamURLInvalid: |
||||
return nil |
||||
} |
||||
} |
||||
} |
||||
|
||||
extension AFError.ResponseValidationFailureReason { |
||||
var acceptableContentTypes: [String]? { |
||||
switch self { |
||||
case let .missingContentType(types), |
||||
let .unacceptableContentType(types, _): |
||||
return types |
||||
case .dataFileNil, |
||||
.dataFileReadFailed, |
||||
.unacceptableStatusCode, |
||||
.customValidationFailed: |
||||
return nil |
||||
} |
||||
} |
||||
|
||||
var responseContentType: String? { |
||||
switch self { |
||||
case let .unacceptableContentType(_, responseType): |
||||
return responseType |
||||
case .dataFileNil, |
||||
.dataFileReadFailed, |
||||
.missingContentType, |
||||
.unacceptableStatusCode, |
||||
.customValidationFailed: |
||||
return nil |
||||
} |
||||
} |
||||
|
||||
var responseCode: Int? { |
||||
switch self { |
||||
case let .unacceptableStatusCode(code): |
||||
return code |
||||
case .dataFileNil, |
||||
.dataFileReadFailed, |
||||
.missingContentType, |
||||
.unacceptableContentType, |
||||
.customValidationFailed: |
||||
return nil |
||||
} |
||||
} |
||||
|
||||
var underlyingError: Error? { |
||||
switch self { |
||||
case let .customValidationFailed(error): |
||||
return error |
||||
case .dataFileNil, |
||||
.dataFileReadFailed, |
||||
.missingContentType, |
||||
.unacceptableContentType, |
||||
.unacceptableStatusCode: |
||||
return nil |
||||
} |
||||
} |
||||
} |
||||
|
||||
extension AFError.ResponseSerializationFailureReason { |
||||
var failedStringEncoding: String.Encoding? { |
||||
switch self { |
||||
case let .stringSerializationFailed(encoding): |
||||
return encoding |
||||
case .inputDataNilOrZeroLength, |
||||
.inputFileNil, |
||||
.inputFileReadFailed(_), |
||||
.jsonSerializationFailed(_), |
||||
.decodingFailed(_), |
||||
.customSerializationFailed(_), |
||||
.invalidEmptyResponse: |
||||
return nil |
||||
} |
||||
} |
||||
|
||||
var underlyingError: Error? { |
||||
switch self { |
||||
case let .jsonSerializationFailed(error), |
||||
let .decodingFailed(error), |
||||
let .customSerializationFailed(error): |
||||
return error |
||||
case .inputDataNilOrZeroLength, |
||||
.inputFileNil, |
||||
.inputFileReadFailed, |
||||
.stringSerializationFailed, |
||||
.invalidEmptyResponse: |
||||
return nil |
||||
} |
||||
} |
||||
} |
||||
|
||||
extension AFError.ServerTrustFailureReason { |
||||
var output: AFError.ServerTrustFailureReason.Output? { |
||||
switch self { |
||||
case let .defaultEvaluationFailed(output), |
||||
let .hostValidationFailed(output), |
||||
let .revocationCheckFailed(output, _): |
||||
return output |
||||
case .noRequiredEvaluator, |
||||
.noCertificatesFound, |
||||
.noPublicKeysFound, |
||||
.policyApplicationFailed, |
||||
.settingAnchorCertificatesFailed, |
||||
.revocationPolicyCreationFailed, |
||||
.trustEvaluationFailed, |
||||
.certificatePinningFailed, |
||||
.publicKeyPinningFailed, |
||||
.customEvaluationFailed: |
||||
return nil |
||||
} |
||||
} |
||||
|
||||
var underlyingError: Error? { |
||||
switch self { |
||||
case let .customEvaluationFailed(error): |
||||
return error |
||||
case let .trustEvaluationFailed(error): |
||||
return error |
||||
case .noRequiredEvaluator, |
||||
.noCertificatesFound, |
||||
.noPublicKeysFound, |
||||
.policyApplicationFailed, |
||||
.settingAnchorCertificatesFailed, |
||||
.revocationPolicyCreationFailed, |
||||
.defaultEvaluationFailed, |
||||
.hostValidationFailed, |
||||
.revocationCheckFailed, |
||||
.certificatePinningFailed, |
||||
.publicKeyPinningFailed: |
||||
return nil |
||||
} |
||||
} |
||||
} |
||||
|
||||
// MARK: - Error Descriptions |
||||
|
||||
extension AFError: LocalizedError { |
||||
public var errorDescription: String? { |
||||
switch self { |
||||
case .explicitlyCancelled: |
||||
return "Request explicitly cancelled." |
||||
case let .invalidURL(url): |
||||
return "URL is not valid: \(url)" |
||||
case let .parameterEncodingFailed(reason): |
||||
return reason.localizedDescription |
||||
case let .parameterEncoderFailed(reason): |
||||
return reason.localizedDescription |
||||
case let .multipartEncodingFailed(reason): |
||||
return reason.localizedDescription |
||||
case let .requestAdaptationFailed(error): |
||||
return "Request adaption failed with error: \(error.localizedDescription)" |
||||
case let .responseValidationFailed(reason): |
||||
return reason.localizedDescription |
||||
case let .responseSerializationFailed(reason): |
||||
return reason.localizedDescription |
||||
case let .requestRetryFailed(retryError, originalError): |
||||
return """ |
||||
Request retry failed with retry error: \(retryError.localizedDescription), \ |
||||
original error: \(originalError.localizedDescription) |
||||
""" |
||||
case .sessionDeinitialized: |
||||
return """ |
||||
Session was invalidated without error, so it was likely deinitialized unexpectedly. \ |
||||
Be sure to retain a reference to your Session for the duration of your requests. |
||||
""" |
||||
case let .sessionInvalidated(error): |
||||
return "Session was invalidated with error: \(error?.localizedDescription ?? "No description.")" |
||||
case let .serverTrustEvaluationFailed(reason): |
||||
return "Server trust evaluation failed due to reason: \(reason.localizedDescription)" |
||||
case let .urlRequestValidationFailed(reason): |
||||
return "URLRequest validation failed due to reason: \(reason.localizedDescription)" |
||||
case let .createUploadableFailed(error): |
||||
return "Uploadable creation failed with error: \(error.localizedDescription)" |
||||
case let .createURLRequestFailed(error): |
||||
return "URLRequest creation failed with error: \(error.localizedDescription)" |
||||
case let .downloadedFileMoveFailed(error, source, destination): |
||||
return "Moving downloaded file from: \(source) to: \(destination) failed with error: \(error.localizedDescription)" |
||||
case let .sessionTaskFailed(error): |
||||
return "URLSessionTask failed with error: \(error.localizedDescription)" |
||||
} |
||||
} |
||||
} |
||||
|
||||
extension AFError.ParameterEncodingFailureReason { |
||||
var localizedDescription: String { |
||||
switch self { |
||||
case .missingURL: |
||||
return "URL request to encode was missing a URL" |
||||
case let .jsonEncodingFailed(error): |
||||
return "JSON could not be encoded because of error:\n\(error.localizedDescription)" |
||||
case let .customEncodingFailed(error): |
||||
return "Custom parameter encoder failed with error: \(error.localizedDescription)" |
||||
} |
||||
} |
||||
} |
||||
|
||||
extension AFError.ParameterEncoderFailureReason { |
||||
var localizedDescription: String { |
||||
switch self { |
||||
case let .missingRequiredComponent(component): |
||||
return "Encoding failed due to a missing request component: \(component)" |
||||
case let .encoderFailed(error): |
||||
return "The underlying encoder failed with the error: \(error)" |
||||
} |
||||
} |
||||
} |
||||
|
||||
extension AFError.MultipartEncodingFailureReason { |
||||
var localizedDescription: String { |
||||
switch self { |
||||
case let .bodyPartURLInvalid(url): |
||||
return "The URL provided is not a file URL: \(url)" |
||||
case let .bodyPartFilenameInvalid(url): |
||||
return "The URL provided does not have a valid filename: \(url)" |
||||
case let .bodyPartFileNotReachable(url): |
||||
return "The URL provided is not reachable: \(url)" |
||||
case let .bodyPartFileNotReachableWithError(url, error): |
||||
return """ |
||||
The system returned an error while checking the provided URL for reachability. |
||||
URL: \(url) |
||||
Error: \(error) |
||||
""" |
||||
case let .bodyPartFileIsDirectory(url): |
||||
return "The URL provided is a directory: \(url)" |
||||
case let .bodyPartFileSizeNotAvailable(url): |
||||
return "Could not fetch the file size from the provided URL: \(url)" |
||||
case let .bodyPartFileSizeQueryFailedWithError(url, error): |
||||
return """ |
||||
The system returned an error while attempting to fetch the file size from the provided URL. |
||||
URL: \(url) |
||||
Error: \(error) |
||||
""" |
||||
case let .bodyPartInputStreamCreationFailed(url): |
||||
return "Failed to create an InputStream for the provided URL: \(url)" |
||||
case let .outputStreamCreationFailed(url): |
||||
return "Failed to create an OutputStream for URL: \(url)" |
||||
case let .outputStreamFileAlreadyExists(url): |
||||
return "A file already exists at the provided URL: \(url)" |
||||
case let .outputStreamURLInvalid(url): |
||||
return "The provided OutputStream URL is invalid: \(url)" |
||||
case let .outputStreamWriteFailed(error): |
||||
return "OutputStream write failed with error: \(error)" |
||||
case let .inputStreamReadFailed(error): |
||||
return "InputStream read failed with error: \(error)" |
||||
} |
||||
} |
||||
} |
||||
|
||||
extension AFError.ResponseSerializationFailureReason { |
||||
var localizedDescription: String { |
||||
switch self { |
||||
case .inputDataNilOrZeroLength: |
||||
return "Response could not be serialized, input data was nil or zero length." |
||||
case .inputFileNil: |
||||
return "Response could not be serialized, input file was nil." |
||||
case let .inputFileReadFailed(url): |
||||
return "Response could not be serialized, input file could not be read: \(url)." |
||||
case let .stringSerializationFailed(encoding): |
||||
return "String could not be serialized with encoding: \(encoding)." |
||||
case let .jsonSerializationFailed(error): |
||||
return "JSON could not be serialized because of error:\n\(error.localizedDescription)" |
||||
case let .invalidEmptyResponse(type): |
||||
return """ |
||||
Empty response could not be serialized to type: \(type). \ |
||||
Use Empty as the expected type for such responses. |
||||
""" |
||||
case let .decodingFailed(error): |
||||
return "Response could not be decoded because of error:\n\(error.localizedDescription)" |
||||
case let .customSerializationFailed(error): |
||||
return "Custom response serializer failed with error:\n\(error.localizedDescription)" |
||||
} |
||||
} |
||||
} |
||||
|
||||
extension AFError.ResponseValidationFailureReason { |
||||
var localizedDescription: String { |
||||
switch self { |
||||
case .dataFileNil: |
||||
return "Response could not be validated, data file was nil." |
||||
case let .dataFileReadFailed(url): |
||||
return "Response could not be validated, data file could not be read: \(url)." |
||||
case let .missingContentType(types): |
||||
return """ |
||||
Response Content-Type was missing and acceptable content types \ |
||||
(\(types.joined(separator: ","))) do not match "*/*". |
||||
""" |
||||
case let .unacceptableContentType(acceptableTypes, responseType): |
||||
return """ |
||||
Response Content-Type "\(responseType)" does not match any acceptable types: \ |
||||
\(acceptableTypes.joined(separator: ",")). |
||||
""" |
||||
case let .unacceptableStatusCode(code): |
||||