Explorar el Código

Move Automatic Resume Behavior to After the First Response Handler is Added (#2965)

* Move automatic resume after first response handler is added.

* Fix misspellings.
Jon Shier hace 6 años
padre
commit
fcc693f233

+ 4 - 4
Source/AFError.swift

@@ -422,7 +422,7 @@ extension AFError {
 
     /// The `source` URL of a `.downloadedFileMoveFailed` error.
     public var sourceURL: URL? {
-        guard case .downloadedFileMoveFailed(_, let source, _) = self else { return nil }
+        guard case let .downloadedFileMoveFailed(_, source, _) = self else { return nil }
         return source
     }
 
@@ -808,11 +808,11 @@ extension AFError.ServerTrustFailureReason {
             return "Default evaluation failed for host \(output.host)."
         case let .hostValidationFailed(output):
             return "Host validation failed for host \(output.host)."
-        case .revocationCheckFailed(let output, _):
+        case let .revocationCheckFailed(output, _):
             return "Revocation check failed for host \(output.host)."
-        case .certificatePinningFailed(let host, _, _, _):
+        case let .certificatePinningFailed(host, _, _, _):
             return "Certificate pinning failed for host \(host)."
-        case .publicKeyPinningFailed(let host, _, _, _):
+        case let .publicKeyPinningFailed(host, _, _, _):
             return "Public key pinning failed for host \(host)."
         case let .customEvaluationFailed(error):
             return "Custom trust evaluation failed with error: \(error.localizedDescription)"

+ 3 - 3
Source/EventMonitor.swift

@@ -118,7 +118,7 @@ public protocol EventMonitor {
     /// Event called when a `Request` receives a `URLSessionTaskMetrics` value.
     func request(_ request: Request, didGatherMetrics metrics: URLSessionTaskMetrics)
 
-    /// Event called when a `Request` fails due to an error created by Alamofire. e.g. When certificat pinning fails.
+    /// Event called when a `Request` fails due to an error created by Alamofire. e.g. When certificate pinning fails.
     func request(_ request: Request, didFailTask task: URLSessionTask, earlyWithError error: AFError)
 
     /// Event called when a `Request`'s task completes, possibly with an error. A `Request` may receive this event
@@ -169,7 +169,7 @@ public protocol EventMonitor {
     /// Event called when an `UploadRequest` creates its `Uploadable` value, indicating the type of upload it represents.
     func request(_ request: UploadRequest, didCreateUploadable uploadable: UploadRequest.Uploadable)
 
-    /// Event called when an `UploadRequest` failes to create its `Uploadable` value due to an error.
+    /// Event called when an `UploadRequest` failed to create its `Uploadable` value due to an error.
     func request(_ request: UploadRequest, didFailToCreateUploadableWithError error: AFError)
 
     /// Event called when an `UploadRequest` provides the `InputStream` from its `Uploadable` value. This only occurs if
@@ -284,7 +284,7 @@ extension EventMonitor {
 
 /// An `EventMonitor` which can contain multiple `EventMonitor`s and calls their methods on their queues.
 public final class CompositeEventMonitor: EventMonitor {
-    public let queue = DispatchQueue(label: "org.alamofire.componsiteEventMonitor", qos: .background)
+    public let queue = DispatchQueue(label: "org.alamofire.compositeEventMonitor", qos: .background)
 
     let monitors: [EventMonitor]
 

+ 1 - 1
Source/HTTPHeaders.swift

@@ -338,7 +338,7 @@ public extension HTTPHeaders {
 }
 
 extension HTTPHeader {
-    /// Returns Alamofire's default `Accept-Encoding` header, appropriate for the encodings supporte by particular OS
+    /// Returns Alamofire's default `Accept-Encoding` header, appropriate for the encodings supported by particular OS
     /// versions.
     ///
     /// See the [Accept-Encoding HTTP header documentation](https://tools.ietf.org/html/rfc7230#section-4.2.3) .

+ 1 - 1
Source/Protector.swift

@@ -147,7 +147,7 @@ extension Protector where T == Request.MutableState {
     ///
     /// - Parameter state: The `State` to attempt transition to.
     ///
-    /// - Returns:         Whether the transtion occurred.
+    /// - Returns:         Whether the transition occurred.
     func attemptToTransitionTo(_ state: Request.State) -> Bool {
         return lock.around {
             guard value.state.canTransitionTo(state) else { return false }

+ 13 - 4
Source/Request.swift

@@ -65,7 +65,7 @@ public class Request {
 
     // MARK: - Initial State
 
-    /// `UUID` prividing a unique identifier for the `Request`, used in the `Hashable` and `Equatable` conformances.
+    /// `UUID` providing a unique identifier for the `Request`, used in the `Hashable` and `Equatable` conformances.
     public let id: UUID
     /// The serial queue for all internal async actions.
     public let underlyingQueue: DispatchQueue
@@ -115,7 +115,7 @@ public class Request {
         var error: AFError?
     }
 
-    /// Protected `MutableState` value that provides threadsafe access to state values.
+    /// Protected `MutableState` value that provides thread-safe access to state values.
     fileprivate let protectedMutableState: Protector<MutableState> = Protector(MutableState())
 
     /// `State` of the `Request`.
@@ -267,7 +267,7 @@ public class Request {
 
     // All API must be called from underlyingQueue.
 
-    /// Called when a initial `URLRequest` has been created on behalf of the instance. If a `RequestAdapter` is active,
+    /// Called when an initial `URLRequest` has been created on behalf of the instance. If a `RequestAdapter` is active,
     /// the `URLRequest` will be adapted before being issued.
     ///
     /// - Parameter request: The `URLRequest` created.
@@ -466,6 +466,8 @@ public class Request {
 
     /// Appends the response serialization closure to the instance.
     ///
+    ///  - Note: This method will also `resume` the instance if `delegate.startImmediately` returns `true`.
+    ///
     /// - Parameter closure: The closure containing the response serialization call.
     func appendResponseSerializer(_ closure: @escaping () -> Void) {
         protectedMutableState.write { mutableState in
@@ -478,6 +480,10 @@ public class Request {
             if mutableState.responseSerializerProcessingFinished {
                 underlyingQueue.async { self.processNextResponseSerializer() }
             }
+
+            if mutableState.state.canTransitionTo(.resumed) {
+                underlyingQueue.async { if self.delegate?.startImmediately == true { self.resume() } }
+            }
         }
     }
 
@@ -534,7 +540,7 @@ public class Request {
 
     /// Notifies the `Request` that the response serializer is complete.
     ///
-    /// - Parameter completion: The completion handler provided with the response serilizer, called when all serializers
+    /// - Parameter completion: The completion handler provided with the response serializer, called when all serializers
     ///                         are complete.
     func responseSerializerDidComplete(completion: @escaping () -> Void) {
         protectedMutableState.write { $0.responseSerializerCompletions.append(completion) }
@@ -895,6 +901,9 @@ public protocol RequestDelegate: AnyObject {
     /// `URLSessionConfiguration` used to create the underlying `URLSessionTask`s.
     var sessionConfiguration: URLSessionConfiguration { get }
 
+    /// Determines whether the `Request` should automatically call `resume()` when adding the first response handler.
+    var startImmediately: Bool { get }
+
     /// Notifies the delegate the `Request` has reached a point where it needs cleanup.
     ///
     /// - Parameter request: The `Request` to cleanup after.

+ 5 - 5
Source/ServerTrustEvaluation.swift

@@ -35,14 +35,14 @@ open class ServerTrustManager {
     /// Initializes the `ServerTrustManager` instance with the given evaluators.
     ///
     /// Since different servers and web services can have different leaf certificates, intermediate and even root
-    /// certficates, it is important to have the flexibility to specify evaluation policies on a per host basis. This
+    /// certificates, it is important to have the flexibility to specify evaluation policies on a per host basis. This
     /// allows for scenarios such as using default evaluation for host1, certificate pinning for host2, public key
     /// pinning for host3 and disabling evaluation for host4.
     ///
     /// - Parameters:
     ///   - allHostsMustBeEvaluated: The value determining whether all hosts for this instance must be evaluated. `true`
     ///                              by default.
-    ///   - evaluators:              A dictionary of evaluators mappend to hosts.
+    ///   - evaluators:              A dictionary of evaluators mapped to hosts.
     public init(allHostsMustBeEvaluated: Bool = true, evaluators: [String: ServerTrustEvaluating]) {
         self.allHostsMustBeEvaluated = allHostsMustBeEvaluated
         self.evaluators = evaluators
@@ -95,7 +95,7 @@ public protocol ServerTrustEvaluating {
 public final class DefaultTrustEvaluator: ServerTrustEvaluating {
     private let validateHost: Bool
 
-    /// Creates a `DefaultTrustEvalutor`.
+    /// Creates a `DefaultTrustEvaluator`.
     ///
     /// - Parameter validateHost: Determines whether or not the evaluator should validate the host. `true` by default.
     public init(validateHost: Bool = true) {
@@ -198,9 +198,9 @@ public final class PinnedCertificatesTrustEvaluator: ServerTrustEvaluating {
     /// Creates a `PinnedCertificatesTrustEvaluator`.
     ///
     /// - Parameters:
-    ///   - certificates:                 The certificates to use to evalute the trust. All `cer`, `crt`, and `der`
+    ///   - certificates:                 The certificates to use to evaluate the trust. All `cer`, `crt`, and `der`
     ///                                   certificates in `Bundle.main` by default.
-    ///   - acceptSelfSignedCertificates: Adds the provided certificates as anchors for the trust evaulation, allowing
+    ///   - acceptSelfSignedCertificates: Adds the provided certificates as anchors for the trust evaluation, allowing
     ///                                   self-signed certificates to pass. `false` by default. THIS SETTING SHOULD BE
     ///                                   FALSE IN PRODUCTION!
     ///   - performDefaultValidation:     Determines whether default validation should be performed in addition to

+ 8 - 11
Source/Session.swift

@@ -113,7 +113,7 @@ open class Session {
         precondition(session.configuration.identifier == nil,
                      "Alamofire does not support background URLSessionConfigurations.")
         precondition(session.delegateQueue.underlyingQueue === rootQueue,
-                     "Session(session:) intializer must be passed the DispatchQueue used as the delegateQueue's underlyingQueue as rootQueue.")
+                     "Session(session:) initializer must be passed the DispatchQueue used as the delegateQueue's underlyingQueue as rootQueue.")
 
         self.session = session
         self.delegate = delegate
@@ -922,26 +922,21 @@ open class Session {
 
     func updateStatesForTask(_ task: URLSessionTask, request: Request) {
         request.withState { state in
-            switch (startRequestsImmediately, state) {
-            case (true, .initialized):
-                rootQueue.async { request.resume() }
-            case (false, .initialized):
+            switch state {
+            case .initialized, .finished:
                 // Do nothing.
                 break
-            case (_, .resumed):
+            case .resumed:
                 task.resume()
                 rootQueue.async { request.didResumeTask(task) }
-            case (_, .suspended):
+            case .suspended:
                 task.suspend()
                 rootQueue.async { request.didSuspendTask(task) }
-            case (_, .cancelled):
+            case .cancelled:
                 // Resume to ensure metrics are gathered.
                 task.resume()
                 task.cancel()
                 rootQueue.async { request.didCancelTask(task) }
-            case (_, .finished):
-                // Do nothing
-                break
             }
         }
     }
@@ -978,6 +973,8 @@ extension Session: RequestDelegate {
         return session.configuration
     }
 
+    public var startImmediately: Bool { return startRequestsImmediately }
+
     public func cleanup(after request: Request) {
         activeRequests.remove(request)
     }

+ 1 - 1
Source/URLConvertible+URLRequestConvertible.swift

@@ -67,7 +67,7 @@ extension URLComponents: URLConvertible {
 
 /// Types adopting the `URLRequestConvertible` protocol can be used to safely construct `URLRequest`s.
 public protocol URLRequestConvertible {
-    /// Returns a `URLRequest` or throws if an `Error` was encoutered.
+    /// Returns a `URLRequest` or throws if an `Error` was encountered.
     ///
     /// - Returns: A `URLRequest`.
     /// - Throws:  Any error thrown while constructing the `URLRequest`.

+ 1 - 1
Source/URLEncodedFormEncoder.swift

@@ -44,7 +44,7 @@ import Foundation
 public final class URLEncodedFormEncoder {
     /// Encoding to use for `Array` values.
     public enum ArrayEncoding {
-        /// An empty set of square brackets ("[]") are sppended to the key for every value. This is the default encoding.
+        /// An empty set of square brackets ("[]") are appended to the key for every value. This is the default encoding.
         case brackets
         /// No brackets are appended to the key and the key is encoded as is.
         case noBrackets

+ 4 - 4
Tests/RequestTests.swift

@@ -285,7 +285,7 @@ final class RequestResponseTestCase: BaseTestCase {
         let session = Session(eventMonitors: [eventMonitor])
 
         let expect = expectation(description: "request should receive appropriate lifetime events")
-        expect.expectedFulfillmentCount = 3
+        expect.expectedFulfillmentCount = 4
 
         eventMonitor.requestDidResumeTask = { _, _ in expect.fulfill() }
         eventMonitor.requestDidResume = { _ in expect.fulfill() }
@@ -297,7 +297,7 @@ final class RequestResponseTestCase: BaseTestCase {
         eventMonitor.requestDidCancelTask = { _, _ in expect.fulfill() }
 
         // When
-        let request = session.request(URLRequest.makeHTTPBinRequest())
+        let request = session.request(URLRequest.makeHTTPBinRequest()).response { _ in expect.fulfill() }
 
         waitForExpectations(timeout: timeout, handler: nil)
 
@@ -512,7 +512,7 @@ final class RequestResponseTestCase: BaseTestCase {
         let session = Session(eventMonitors: [eventMonitor])
 
         let expect = expectation(description: "request should receive appropriate lifetime events")
-        expect.expectedFulfillmentCount = 5
+        expect.expectedFulfillmentCount = 6
 
         eventMonitor.requestDidCancelTask = { _, _ in expect.fulfill() }
         eventMonitor.requestDidCancel = { _ in expect.fulfill() }
@@ -523,7 +523,7 @@ final class RequestResponseTestCase: BaseTestCase {
         eventMonitor.requestDidSuspendTask = { _, _ in expect.fulfill() }
 
         // When
-        let request = session.request(URLRequest.makeHTTPBinRequest())
+        let request = session.request(URLRequest.makeHTTPBinRequest()).response { _ in expect.fulfill() }
         // Cancellation stops task creation, so don't cancel the request until the task has been created.
         eventMonitor.requestDidCreateTask = { _, _ in
             DispatchQueue.concurrentPerform(iterations: 100) { i in