2
0
Эх сурвалжийг харах

Retrier is now called when uploads encounter adapt error.

Christian Noon 9 жил өмнө
parent
commit
9df01e64de

+ 17 - 13
Source/Request.swift

@@ -539,21 +539,25 @@ open class UploadRequest: DataRequest {
         case stream(InputStream, URLRequest)
 
         func task(session: URLSession, adapter: RequestAdapter?, queue: DispatchQueue) throws -> URLSessionTask {
-            let task: URLSessionTask
+            do {
+                let task: URLSessionTask
 
-            switch self {
-            case let .data(data, urlRequest):
-                let urlRequest = try urlRequest.adapt(using: adapter)
-                task = queue.syncResult { session.uploadTask(with: urlRequest, from: data) }
-            case let .file(url, urlRequest):
-                let urlRequest = try urlRequest.adapt(using: adapter)
-                task = queue.syncResult { session.uploadTask(with: urlRequest, fromFile: url) }
-            case let .stream(_, urlRequest):
-                let urlRequest = try urlRequest.adapt(using: adapter)
-                task = queue.syncResult { session.uploadTask(withStreamedRequest: urlRequest) }
-            }
+                switch self {
+                case let .data(data, urlRequest):
+                    let urlRequest = try urlRequest.adapt(using: adapter)
+                    task = queue.syncResult { session.uploadTask(with: urlRequest, from: data) }
+                case let .file(url, urlRequest):
+                    let urlRequest = try urlRequest.adapt(using: adapter)
+                    task = queue.syncResult { session.uploadTask(with: urlRequest, fromFile: url) }
+                case let .stream(_, urlRequest):
+                    let urlRequest = try urlRequest.adapt(using: adapter)
+                    task = queue.syncResult { session.uploadTask(withStreamedRequest: urlRequest) }
+                }
 
-            return task
+                return task
+            } catch {
+                throw AdaptError(error: error)
+            }
         }
     }
 

+ 25 - 10
Source/SessionManager.swift

@@ -466,7 +466,7 @@ open class SessionManager {
             let urlRequest = try URLRequest(url: url, method: method, headers: headers)
             return upload(fileURL, with: urlRequest)
         } catch {
-            return upload(failedWith: error)
+            return upload(nil, failedWith: error)
         }
     }
 
@@ -484,7 +484,7 @@ open class SessionManager {
             let urlRequest = try urlRequest.asURLRequest()
             return upload(.file(fileURL, urlRequest))
         } catch {
-            return upload(failedWith: error)
+            return upload(nil, failedWith: error)
         }
     }
 
@@ -512,7 +512,7 @@ open class SessionManager {
             let urlRequest = try URLRequest(url: url, method: method, headers: headers)
             return upload(data, with: urlRequest)
         } catch {
-            return upload(failedWith: error)
+            return upload(nil, failedWith: error)
         }
     }
 
@@ -530,7 +530,7 @@ open class SessionManager {
             let urlRequest = try urlRequest.asURLRequest()
             return upload(.data(data, urlRequest))
         } catch {
-            return upload(failedWith: error)
+            return upload(nil, failedWith: error)
         }
     }
 
@@ -558,7 +558,7 @@ open class SessionManager {
             let urlRequest = try URLRequest(url: url, method: method, headers: headers)
             return upload(stream, with: urlRequest)
         } catch {
-            return upload(failedWith: error)
+            return upload(nil, failedWith: error)
         }
     }
 
@@ -576,7 +576,7 @@ open class SessionManager {
             let urlRequest = try urlRequest.asURLRequest()
             return upload(.stream(stream, urlRequest))
         } catch {
-            return upload(failedWith: error)
+            return upload(nil, failedWith: error)
         }
     }
 
@@ -732,13 +732,28 @@ open class SessionManager {
 
             return upload
         } catch {
-            return upload(failedWith: error)
+            return upload(uploadable, failedWith: error)
         }
     }
 
-    private func upload(failedWith error: Error) -> UploadRequest {
-        let upload = UploadRequest(session: session, requestTask: .upload(nil, nil), error: error)
-        if startRequestsImmediately { upload.resume() }
+    private func upload(_ uploadable: UploadRequest.Uploadable?, failedWith error: Error) -> UploadRequest {
+        var uploadTask: Request.RequestTask = .upload(nil, nil)
+
+        if let uploadable = uploadable {
+            uploadTask = .upload(uploadable, nil)
+        }
+
+        let isAdaptError = error is AdaptError
+        let error = error.extractedAdaptError
+
+        let upload = UploadRequest(session: session, requestTask: uploadTask, error: error)
+
+        if let retrier = retrier, isAdaptError {
+            allowRetrier(retrier, toRetry: upload, with: error)
+        } else {
+            if startRequestsImmediately { upload.resume() }
+        }
+
         return upload
     }
 

+ 47 - 0
Tests/SessionManagerTests.swift

@@ -86,6 +86,24 @@ class SessionManagerTestCase: BaseTestCase {
         }
     }
 
+    private class UploadHandler: RequestAdapter, RequestRetrier {
+        var adaptedCount = 0
+        var retryCount = 0
+
+        func adapt(_ urlRequest: URLRequest) throws -> URLRequest {
+            adaptedCount += 1
+
+            if adaptedCount == 1 { throw AFError.invalidURL(url: "") }
+
+            return urlRequest
+        }
+
+        func should(_ manager: SessionManager, retry request: Request, with error: Error, completion: @escaping RequestRetryCompletion) {
+            retryCount += 1
+            completion(true, 0.0)
+        }
+    }
+
     // MARK: Tests - Initialization
 
     func testInitializerWithDefaultArguments() {
@@ -647,6 +665,35 @@ class SessionManagerTestCase: BaseTestCase {
         XCTAssertEqual(response?.result.isSuccess, true)
     }
 
+    func testThatSessionManagerCallsRequestRetrierWhenUploadInitiallyEncountersAdaptError() {
+        // Given
+        let handler = UploadHandler()
+
+        let sessionManager = SessionManager()
+        sessionManager.adapter = handler
+        sessionManager.retrier = handler
+
+        let expectation = self.expectation(description: "request should eventually fail")
+        var response: DataResponse<Any>?
+
+        let uploadData = "upload data".data(using: .utf8, allowLossyConversion: false)!
+
+        // When
+        sessionManager.upload(uploadData, to: "https://httpbin.org/post")
+            .validate()
+            .responseJSON { jsonResponse in
+                response = jsonResponse
+                expectation.fulfill()
+            }
+
+        waitForExpectations(timeout: timeout, handler: nil)
+
+        // Then
+        XCTAssertEqual(handler.adaptedCount, 2)
+        XCTAssertEqual(handler.retryCount, 1)
+        XCTAssertEqual(response?.result.isSuccess, true)
+    }
+
     func testThatSessionManagerCallsAdapterWhenRequestIsRetried() {
         // Given
         let handler = RequestHandler()