diff --git a/modules/openapi-generator/src/main/resources/swift5/libraries/urlsession/URLSessionImplementations.mustache b/modules/openapi-generator/src/main/resources/swift5/libraries/urlsession/URLSessionImplementations.mustache index 36240f6c6c0..4c98339a357 100644 --- a/modules/openapi-generator/src/main/resources/swift5/libraries/urlsession/URLSessionImplementations.mustache +++ b/modules/openapi-generator/src/main/resources/swift5/libraries/urlsession/URLSessionImplementations.mustache @@ -19,15 +19,26 @@ class URLSessionRequestBuilderFactory: RequestBuilderFactory { } } +{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} typealias {{projectName}}APIChallengeHandler = ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?)) + +// Store the URLSession's delegate to retain its reference +private let sessionDelegate = SessionDelegate() + // Store the URLSession to retain its reference -private var urlSessionStore = SynchronizedDictionary() +private let defaultURLSession = URLSession(configuration: .default, delegate: sessionDelegate, delegateQueue: nil) + +// Store current taskDidReceiveChallenge for every URLSessionTask +private var challengeHandlerStore = SynchronizedDictionary() + +// Store current URLCredential for every URLSessionTask +private var credentialStore = SynchronizedDictionary() {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class URLSessionRequestBuilder: RequestBuilder { /** May be assigned if you want to control the authentication challenges. */ - {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var taskDidReceiveChallenge: ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))? + {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var taskDidReceiveChallenge: {{projectName}}APIChallengeHandler? /** May be assigned if you want to do any of those things: @@ -47,12 +58,7 @@ private var urlSessionStore = SynchronizedDictionary() configuration. */ {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} func createURLSession() -> URLSession { - let configuration = URLSessionConfiguration.default - configuration.httpAdditionalHeaders = buildHeaders() - let sessionDelegate = SessionDelegate() - sessionDelegate.credential = credential - sessionDelegate.taskDidReceiveChallenge = taskDidReceiveChallenge - return URLSession(configuration: configuration, delegate: sessionDelegate, delegateQueue: nil) + return defaultURLSession } /** @@ -94,10 +100,7 @@ private var urlSessionStore = SynchronizedDictionary() } override {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} func execute(_ apiResponseQueue: DispatchQueue = {{projectName}}API.apiResponseQueue, _ completion: @escaping (_ result: Swift.Result, ErrorResponse>) -> Void) { - let urlSessionId = UUID().uuidString - // Create a new manager for each request to customize its request header let urlSession = createURLSession() - urlSessionStore[urlSessionId] = urlSession guard let xMethod = HTTPMethod(rawValue: method) else { fatalError("Unsupported Http method - \(method)") @@ -123,14 +126,17 @@ private var urlSessionStore = SynchronizedDictionary() } } - let cleanupRequest = { - urlSessionStore[urlSessionId]?.finishTasksAndInvalidate() - urlSessionStore[urlSessionId] = nil - } - do { let request = try createURLRequest(urlSession: urlSession, method: xMethod, encoding: encoding, headers: headers) + var taskIdentifier: Int? + let cleanupRequest = { + if let taskIdentifier = taskIdentifier { + challengeHandlerStore[taskIdentifier] = nil + credentialStore[taskIdentifier] = nil + } + } + let dataTask = urlSession.dataTask(with: request) { data, response, error in if let taskCompletionShouldRetry = self.taskCompletionShouldRetry { @@ -159,11 +165,14 @@ private var urlSessionStore = SynchronizedDictionary() onProgressReady?(dataTask.progress) } + taskIdentifier = dataTask.taskIdentifier + challengeHandlerStore[dataTask.taskIdentifier] = taskDidReceiveChallenge + credentialStore[dataTask.taskIdentifier] = credential + dataTask.resume() } catch { apiResponseQueue.async { - cleanupRequest() completion(.failure(ErrorResponse.error(415, nil, nil, error))) } } @@ -398,25 +407,20 @@ private var urlSessionStore = SynchronizedDictionary() } } -private class SessionDelegate: NSObject, URLSessionDelegate, URLSessionDataDelegate { - - var credential: URLCredential? - - var taskDidReceiveChallenge: ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))? - +private class SessionDelegate: NSObject, URLSessionTaskDelegate { func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { var disposition: URLSession.AuthChallengeDisposition = .performDefaultHandling var credential: URLCredential? - if let taskDidReceiveChallenge = taskDidReceiveChallenge { + if let taskDidReceiveChallenge = challengeHandlerStore[task.taskIdentifier] { (disposition, credential) = taskDidReceiveChallenge(session, task, challenge) } else { if challenge.previousFailureCount > 0 { disposition = .rejectProtectionSpace } else { - credential = self.credential ?? session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace) + credential = credentialStore[task.taskIdentifier] ?? session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace) if credential != nil { disposition = .useCredential diff --git a/samples/client/petstore/swift5/asyncAwaitLibrary/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift b/samples/client/petstore/swift5/asyncAwaitLibrary/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift index 762df8c3045..c60991d13af 100644 --- a/samples/client/petstore/swift5/asyncAwaitLibrary/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift +++ b/samples/client/petstore/swift5/asyncAwaitLibrary/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift @@ -19,15 +19,26 @@ class URLSessionRequestBuilderFactory: RequestBuilderFactory { } } +public typealias PetstoreClientAPIChallengeHandler = ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?)) + +// Store the URLSession's delegate to retain its reference +private let sessionDelegate = SessionDelegate() + // Store the URLSession to retain its reference -private var urlSessionStore = SynchronizedDictionary() +private let defaultURLSession = URLSession(configuration: .default, delegate: sessionDelegate, delegateQueue: nil) + +// Store current taskDidReceiveChallenge for every URLSessionTask +private var challengeHandlerStore = SynchronizedDictionary() + +// Store current URLCredential for every URLSessionTask +private var credentialStore = SynchronizedDictionary() open class URLSessionRequestBuilder: RequestBuilder { /** May be assigned if you want to control the authentication challenges. */ - public var taskDidReceiveChallenge: ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))? + public var taskDidReceiveChallenge: PetstoreClientAPIChallengeHandler? /** May be assigned if you want to do any of those things: @@ -47,12 +58,7 @@ open class URLSessionRequestBuilder: RequestBuilder { configuration. */ open func createURLSession() -> URLSession { - let configuration = URLSessionConfiguration.default - configuration.httpAdditionalHeaders = buildHeaders() - let sessionDelegate = SessionDelegate() - sessionDelegate.credential = credential - sessionDelegate.taskDidReceiveChallenge = taskDidReceiveChallenge - return URLSession(configuration: configuration, delegate: sessionDelegate, delegateQueue: nil) + return defaultURLSession } /** @@ -94,10 +100,7 @@ open class URLSessionRequestBuilder: RequestBuilder { } override open func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (_ result: Swift.Result, ErrorResponse>) -> Void) { - let urlSessionId = UUID().uuidString - // Create a new manager for each request to customize its request header let urlSession = createURLSession() - urlSessionStore[urlSessionId] = urlSession guard let xMethod = HTTPMethod(rawValue: method) else { fatalError("Unsupported Http method - \(method)") @@ -123,14 +126,17 @@ open class URLSessionRequestBuilder: RequestBuilder { } } - let cleanupRequest = { - urlSessionStore[urlSessionId]?.finishTasksAndInvalidate() - urlSessionStore[urlSessionId] = nil - } - do { let request = try createURLRequest(urlSession: urlSession, method: xMethod, encoding: encoding, headers: headers) + var taskIdentifier: Int? + let cleanupRequest = { + if let taskIdentifier = taskIdentifier { + challengeHandlerStore[taskIdentifier] = nil + credentialStore[taskIdentifier] = nil + } + } + let dataTask = urlSession.dataTask(with: request) { data, response, error in if let taskCompletionShouldRetry = self.taskCompletionShouldRetry { @@ -159,11 +165,14 @@ open class URLSessionRequestBuilder: RequestBuilder { onProgressReady?(dataTask.progress) } + taskIdentifier = dataTask.taskIdentifier + challengeHandlerStore[dataTask.taskIdentifier] = taskDidReceiveChallenge + credentialStore[dataTask.taskIdentifier] = credential + dataTask.resume() } catch { apiResponseQueue.async { - cleanupRequest() completion(.failure(ErrorResponse.error(415, nil, nil, error))) } } @@ -398,25 +407,20 @@ open class URLSessionDecodableRequestBuilder: URLSessionRequestBui } } -private class SessionDelegate: NSObject, URLSessionDelegate, URLSessionDataDelegate { - - var credential: URLCredential? - - var taskDidReceiveChallenge: ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))? - +private class SessionDelegate: NSObject, URLSessionTaskDelegate { func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { var disposition: URLSession.AuthChallengeDisposition = .performDefaultHandling var credential: URLCredential? - if let taskDidReceiveChallenge = taskDidReceiveChallenge { + if let taskDidReceiveChallenge = challengeHandlerStore[task.taskIdentifier] { (disposition, credential) = taskDidReceiveChallenge(session, task, challenge) } else { if challenge.previousFailureCount > 0 { disposition = .rejectProtectionSpace } else { - credential = self.credential ?? session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace) + credential = credentialStore[task.taskIdentifier] ?? session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace) if credential != nil { disposition = .useCredential diff --git a/samples/client/petstore/swift5/combineLibrary/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift b/samples/client/petstore/swift5/combineLibrary/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift index 762df8c3045..c60991d13af 100644 --- a/samples/client/petstore/swift5/combineLibrary/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift +++ b/samples/client/petstore/swift5/combineLibrary/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift @@ -19,15 +19,26 @@ class URLSessionRequestBuilderFactory: RequestBuilderFactory { } } +public typealias PetstoreClientAPIChallengeHandler = ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?)) + +// Store the URLSession's delegate to retain its reference +private let sessionDelegate = SessionDelegate() + // Store the URLSession to retain its reference -private var urlSessionStore = SynchronizedDictionary() +private let defaultURLSession = URLSession(configuration: .default, delegate: sessionDelegate, delegateQueue: nil) + +// Store current taskDidReceiveChallenge for every URLSessionTask +private var challengeHandlerStore = SynchronizedDictionary() + +// Store current URLCredential for every URLSessionTask +private var credentialStore = SynchronizedDictionary() open class URLSessionRequestBuilder: RequestBuilder { /** May be assigned if you want to control the authentication challenges. */ - public var taskDidReceiveChallenge: ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))? + public var taskDidReceiveChallenge: PetstoreClientAPIChallengeHandler? /** May be assigned if you want to do any of those things: @@ -47,12 +58,7 @@ open class URLSessionRequestBuilder: RequestBuilder { configuration. */ open func createURLSession() -> URLSession { - let configuration = URLSessionConfiguration.default - configuration.httpAdditionalHeaders = buildHeaders() - let sessionDelegate = SessionDelegate() - sessionDelegate.credential = credential - sessionDelegate.taskDidReceiveChallenge = taskDidReceiveChallenge - return URLSession(configuration: configuration, delegate: sessionDelegate, delegateQueue: nil) + return defaultURLSession } /** @@ -94,10 +100,7 @@ open class URLSessionRequestBuilder: RequestBuilder { } override open func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (_ result: Swift.Result, ErrorResponse>) -> Void) { - let urlSessionId = UUID().uuidString - // Create a new manager for each request to customize its request header let urlSession = createURLSession() - urlSessionStore[urlSessionId] = urlSession guard let xMethod = HTTPMethod(rawValue: method) else { fatalError("Unsupported Http method - \(method)") @@ -123,14 +126,17 @@ open class URLSessionRequestBuilder: RequestBuilder { } } - let cleanupRequest = { - urlSessionStore[urlSessionId]?.finishTasksAndInvalidate() - urlSessionStore[urlSessionId] = nil - } - do { let request = try createURLRequest(urlSession: urlSession, method: xMethod, encoding: encoding, headers: headers) + var taskIdentifier: Int? + let cleanupRequest = { + if let taskIdentifier = taskIdentifier { + challengeHandlerStore[taskIdentifier] = nil + credentialStore[taskIdentifier] = nil + } + } + let dataTask = urlSession.dataTask(with: request) { data, response, error in if let taskCompletionShouldRetry = self.taskCompletionShouldRetry { @@ -159,11 +165,14 @@ open class URLSessionRequestBuilder: RequestBuilder { onProgressReady?(dataTask.progress) } + taskIdentifier = dataTask.taskIdentifier + challengeHandlerStore[dataTask.taskIdentifier] = taskDidReceiveChallenge + credentialStore[dataTask.taskIdentifier] = credential + dataTask.resume() } catch { apiResponseQueue.async { - cleanupRequest() completion(.failure(ErrorResponse.error(415, nil, nil, error))) } } @@ -398,25 +407,20 @@ open class URLSessionDecodableRequestBuilder: URLSessionRequestBui } } -private class SessionDelegate: NSObject, URLSessionDelegate, URLSessionDataDelegate { - - var credential: URLCredential? - - var taskDidReceiveChallenge: ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))? - +private class SessionDelegate: NSObject, URLSessionTaskDelegate { func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { var disposition: URLSession.AuthChallengeDisposition = .performDefaultHandling var credential: URLCredential? - if let taskDidReceiveChallenge = taskDidReceiveChallenge { + if let taskDidReceiveChallenge = challengeHandlerStore[task.taskIdentifier] { (disposition, credential) = taskDidReceiveChallenge(session, task, challenge) } else { if challenge.previousFailureCount > 0 { disposition = .rejectProtectionSpace } else { - credential = self.credential ?? session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace) + credential = credentialStore[task.taskIdentifier] ?? session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace) if credential != nil { disposition = .useCredential diff --git a/samples/client/petstore/swift5/default/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift b/samples/client/petstore/swift5/default/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift index 762df8c3045..c60991d13af 100644 --- a/samples/client/petstore/swift5/default/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift +++ b/samples/client/petstore/swift5/default/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift @@ -19,15 +19,26 @@ class URLSessionRequestBuilderFactory: RequestBuilderFactory { } } +public typealias PetstoreClientAPIChallengeHandler = ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?)) + +// Store the URLSession's delegate to retain its reference +private let sessionDelegate = SessionDelegate() + // Store the URLSession to retain its reference -private var urlSessionStore = SynchronizedDictionary() +private let defaultURLSession = URLSession(configuration: .default, delegate: sessionDelegate, delegateQueue: nil) + +// Store current taskDidReceiveChallenge for every URLSessionTask +private var challengeHandlerStore = SynchronizedDictionary() + +// Store current URLCredential for every URLSessionTask +private var credentialStore = SynchronizedDictionary() open class URLSessionRequestBuilder: RequestBuilder { /** May be assigned if you want to control the authentication challenges. */ - public var taskDidReceiveChallenge: ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))? + public var taskDidReceiveChallenge: PetstoreClientAPIChallengeHandler? /** May be assigned if you want to do any of those things: @@ -47,12 +58,7 @@ open class URLSessionRequestBuilder: RequestBuilder { configuration. */ open func createURLSession() -> URLSession { - let configuration = URLSessionConfiguration.default - configuration.httpAdditionalHeaders = buildHeaders() - let sessionDelegate = SessionDelegate() - sessionDelegate.credential = credential - sessionDelegate.taskDidReceiveChallenge = taskDidReceiveChallenge - return URLSession(configuration: configuration, delegate: sessionDelegate, delegateQueue: nil) + return defaultURLSession } /** @@ -94,10 +100,7 @@ open class URLSessionRequestBuilder: RequestBuilder { } override open func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (_ result: Swift.Result, ErrorResponse>) -> Void) { - let urlSessionId = UUID().uuidString - // Create a new manager for each request to customize its request header let urlSession = createURLSession() - urlSessionStore[urlSessionId] = urlSession guard let xMethod = HTTPMethod(rawValue: method) else { fatalError("Unsupported Http method - \(method)") @@ -123,14 +126,17 @@ open class URLSessionRequestBuilder: RequestBuilder { } } - let cleanupRequest = { - urlSessionStore[urlSessionId]?.finishTasksAndInvalidate() - urlSessionStore[urlSessionId] = nil - } - do { let request = try createURLRequest(urlSession: urlSession, method: xMethod, encoding: encoding, headers: headers) + var taskIdentifier: Int? + let cleanupRequest = { + if let taskIdentifier = taskIdentifier { + challengeHandlerStore[taskIdentifier] = nil + credentialStore[taskIdentifier] = nil + } + } + let dataTask = urlSession.dataTask(with: request) { data, response, error in if let taskCompletionShouldRetry = self.taskCompletionShouldRetry { @@ -159,11 +165,14 @@ open class URLSessionRequestBuilder: RequestBuilder { onProgressReady?(dataTask.progress) } + taskIdentifier = dataTask.taskIdentifier + challengeHandlerStore[dataTask.taskIdentifier] = taskDidReceiveChallenge + credentialStore[dataTask.taskIdentifier] = credential + dataTask.resume() } catch { apiResponseQueue.async { - cleanupRequest() completion(.failure(ErrorResponse.error(415, nil, nil, error))) } } @@ -398,25 +407,20 @@ open class URLSessionDecodableRequestBuilder: URLSessionRequestBui } } -private class SessionDelegate: NSObject, URLSessionDelegate, URLSessionDataDelegate { - - var credential: URLCredential? - - var taskDidReceiveChallenge: ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))? - +private class SessionDelegate: NSObject, URLSessionTaskDelegate { func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { var disposition: URLSession.AuthChallengeDisposition = .performDefaultHandling var credential: URLCredential? - if let taskDidReceiveChallenge = taskDidReceiveChallenge { + if let taskDidReceiveChallenge = challengeHandlerStore[task.taskIdentifier] { (disposition, credential) = taskDidReceiveChallenge(session, task, challenge) } else { if challenge.previousFailureCount > 0 { disposition = .rejectProtectionSpace } else { - credential = self.credential ?? session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace) + credential = credentialStore[task.taskIdentifier] ?? session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace) if credential != nil { disposition = .useCredential diff --git a/samples/client/petstore/swift5/deprecated/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift b/samples/client/petstore/swift5/deprecated/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift index 762df8c3045..c60991d13af 100644 --- a/samples/client/petstore/swift5/deprecated/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift +++ b/samples/client/petstore/swift5/deprecated/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift @@ -19,15 +19,26 @@ class URLSessionRequestBuilderFactory: RequestBuilderFactory { } } +public typealias PetstoreClientAPIChallengeHandler = ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?)) + +// Store the URLSession's delegate to retain its reference +private let sessionDelegate = SessionDelegate() + // Store the URLSession to retain its reference -private var urlSessionStore = SynchronizedDictionary() +private let defaultURLSession = URLSession(configuration: .default, delegate: sessionDelegate, delegateQueue: nil) + +// Store current taskDidReceiveChallenge for every URLSessionTask +private var challengeHandlerStore = SynchronizedDictionary() + +// Store current URLCredential for every URLSessionTask +private var credentialStore = SynchronizedDictionary() open class URLSessionRequestBuilder: RequestBuilder { /** May be assigned if you want to control the authentication challenges. */ - public var taskDidReceiveChallenge: ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))? + public var taskDidReceiveChallenge: PetstoreClientAPIChallengeHandler? /** May be assigned if you want to do any of those things: @@ -47,12 +58,7 @@ open class URLSessionRequestBuilder: RequestBuilder { configuration. */ open func createURLSession() -> URLSession { - let configuration = URLSessionConfiguration.default - configuration.httpAdditionalHeaders = buildHeaders() - let sessionDelegate = SessionDelegate() - sessionDelegate.credential = credential - sessionDelegate.taskDidReceiveChallenge = taskDidReceiveChallenge - return URLSession(configuration: configuration, delegate: sessionDelegate, delegateQueue: nil) + return defaultURLSession } /** @@ -94,10 +100,7 @@ open class URLSessionRequestBuilder: RequestBuilder { } override open func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (_ result: Swift.Result, ErrorResponse>) -> Void) { - let urlSessionId = UUID().uuidString - // Create a new manager for each request to customize its request header let urlSession = createURLSession() - urlSessionStore[urlSessionId] = urlSession guard let xMethod = HTTPMethod(rawValue: method) else { fatalError("Unsupported Http method - \(method)") @@ -123,14 +126,17 @@ open class URLSessionRequestBuilder: RequestBuilder { } } - let cleanupRequest = { - urlSessionStore[urlSessionId]?.finishTasksAndInvalidate() - urlSessionStore[urlSessionId] = nil - } - do { let request = try createURLRequest(urlSession: urlSession, method: xMethod, encoding: encoding, headers: headers) + var taskIdentifier: Int? + let cleanupRequest = { + if let taskIdentifier = taskIdentifier { + challengeHandlerStore[taskIdentifier] = nil + credentialStore[taskIdentifier] = nil + } + } + let dataTask = urlSession.dataTask(with: request) { data, response, error in if let taskCompletionShouldRetry = self.taskCompletionShouldRetry { @@ -159,11 +165,14 @@ open class URLSessionRequestBuilder: RequestBuilder { onProgressReady?(dataTask.progress) } + taskIdentifier = dataTask.taskIdentifier + challengeHandlerStore[dataTask.taskIdentifier] = taskDidReceiveChallenge + credentialStore[dataTask.taskIdentifier] = credential + dataTask.resume() } catch { apiResponseQueue.async { - cleanupRequest() completion(.failure(ErrorResponse.error(415, nil, nil, error))) } } @@ -398,25 +407,20 @@ open class URLSessionDecodableRequestBuilder: URLSessionRequestBui } } -private class SessionDelegate: NSObject, URLSessionDelegate, URLSessionDataDelegate { - - var credential: URLCredential? - - var taskDidReceiveChallenge: ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))? - +private class SessionDelegate: NSObject, URLSessionTaskDelegate { func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { var disposition: URLSession.AuthChallengeDisposition = .performDefaultHandling var credential: URLCredential? - if let taskDidReceiveChallenge = taskDidReceiveChallenge { + if let taskDidReceiveChallenge = challengeHandlerStore[task.taskIdentifier] { (disposition, credential) = taskDidReceiveChallenge(session, task, challenge) } else { if challenge.previousFailureCount > 0 { disposition = .rejectProtectionSpace } else { - credential = self.credential ?? session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace) + credential = credentialStore[task.taskIdentifier] ?? session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace) if credential != nil { disposition = .useCredential diff --git a/samples/client/petstore/swift5/nonPublicApi/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift b/samples/client/petstore/swift5/nonPublicApi/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift index 9a76a452f22..49f60b13912 100644 --- a/samples/client/petstore/swift5/nonPublicApi/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift +++ b/samples/client/petstore/swift5/nonPublicApi/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift @@ -19,15 +19,26 @@ class URLSessionRequestBuilderFactory: RequestBuilderFactory { } } +internal typealias PetstoreClientAPIChallengeHandler = ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?)) + +// Store the URLSession's delegate to retain its reference +private let sessionDelegate = SessionDelegate() + // Store the URLSession to retain its reference -private var urlSessionStore = SynchronizedDictionary() +private let defaultURLSession = URLSession(configuration: .default, delegate: sessionDelegate, delegateQueue: nil) + +// Store current taskDidReceiveChallenge for every URLSessionTask +private var challengeHandlerStore = SynchronizedDictionary() + +// Store current URLCredential for every URLSessionTask +private var credentialStore = SynchronizedDictionary() internal class URLSessionRequestBuilder: RequestBuilder { /** May be assigned if you want to control the authentication challenges. */ - internal var taskDidReceiveChallenge: ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))? + internal var taskDidReceiveChallenge: PetstoreClientAPIChallengeHandler? /** May be assigned if you want to do any of those things: @@ -47,12 +58,7 @@ internal class URLSessionRequestBuilder: RequestBuilder { configuration. */ internal func createURLSession() -> URLSession { - let configuration = URLSessionConfiguration.default - configuration.httpAdditionalHeaders = buildHeaders() - let sessionDelegate = SessionDelegate() - sessionDelegate.credential = credential - sessionDelegate.taskDidReceiveChallenge = taskDidReceiveChallenge - return URLSession(configuration: configuration, delegate: sessionDelegate, delegateQueue: nil) + return defaultURLSession } /** @@ -94,10 +100,7 @@ internal class URLSessionRequestBuilder: RequestBuilder { } override internal func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (_ result: Swift.Result, ErrorResponse>) -> Void) { - let urlSessionId = UUID().uuidString - // Create a new manager for each request to customize its request header let urlSession = createURLSession() - urlSessionStore[urlSessionId] = urlSession guard let xMethod = HTTPMethod(rawValue: method) else { fatalError("Unsupported Http method - \(method)") @@ -123,14 +126,17 @@ internal class URLSessionRequestBuilder: RequestBuilder { } } - let cleanupRequest = { - urlSessionStore[urlSessionId]?.finishTasksAndInvalidate() - urlSessionStore[urlSessionId] = nil - } - do { let request = try createURLRequest(urlSession: urlSession, method: xMethod, encoding: encoding, headers: headers) + var taskIdentifier: Int? + let cleanupRequest = { + if let taskIdentifier = taskIdentifier { + challengeHandlerStore[taskIdentifier] = nil + credentialStore[taskIdentifier] = nil + } + } + let dataTask = urlSession.dataTask(with: request) { data, response, error in if let taskCompletionShouldRetry = self.taskCompletionShouldRetry { @@ -159,11 +165,14 @@ internal class URLSessionRequestBuilder: RequestBuilder { onProgressReady?(dataTask.progress) } + taskIdentifier = dataTask.taskIdentifier + challengeHandlerStore[dataTask.taskIdentifier] = taskDidReceiveChallenge + credentialStore[dataTask.taskIdentifier] = credential + dataTask.resume() } catch { apiResponseQueue.async { - cleanupRequest() completion(.failure(ErrorResponse.error(415, nil, nil, error))) } } @@ -398,25 +407,20 @@ internal class URLSessionDecodableRequestBuilder: URLSessionReques } } -private class SessionDelegate: NSObject, URLSessionDelegate, URLSessionDataDelegate { - - var credential: URLCredential? - - var taskDidReceiveChallenge: ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))? - +private class SessionDelegate: NSObject, URLSessionTaskDelegate { func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { var disposition: URLSession.AuthChallengeDisposition = .performDefaultHandling var credential: URLCredential? - if let taskDidReceiveChallenge = taskDidReceiveChallenge { + if let taskDidReceiveChallenge = challengeHandlerStore[task.taskIdentifier] { (disposition, credential) = taskDidReceiveChallenge(session, task, challenge) } else { if challenge.previousFailureCount > 0 { disposition = .rejectProtectionSpace } else { - credential = self.credential ?? session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace) + credential = credentialStore[task.taskIdentifier] ?? session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace) if credential != nil { disposition = .useCredential diff --git a/samples/client/petstore/swift5/objcCompatible/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift b/samples/client/petstore/swift5/objcCompatible/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift index 762df8c3045..c60991d13af 100644 --- a/samples/client/petstore/swift5/objcCompatible/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift +++ b/samples/client/petstore/swift5/objcCompatible/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift @@ -19,15 +19,26 @@ class URLSessionRequestBuilderFactory: RequestBuilderFactory { } } +public typealias PetstoreClientAPIChallengeHandler = ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?)) + +// Store the URLSession's delegate to retain its reference +private let sessionDelegate = SessionDelegate() + // Store the URLSession to retain its reference -private var urlSessionStore = SynchronizedDictionary() +private let defaultURLSession = URLSession(configuration: .default, delegate: sessionDelegate, delegateQueue: nil) + +// Store current taskDidReceiveChallenge for every URLSessionTask +private var challengeHandlerStore = SynchronizedDictionary() + +// Store current URLCredential for every URLSessionTask +private var credentialStore = SynchronizedDictionary() open class URLSessionRequestBuilder: RequestBuilder { /** May be assigned if you want to control the authentication challenges. */ - public var taskDidReceiveChallenge: ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))? + public var taskDidReceiveChallenge: PetstoreClientAPIChallengeHandler? /** May be assigned if you want to do any of those things: @@ -47,12 +58,7 @@ open class URLSessionRequestBuilder: RequestBuilder { configuration. */ open func createURLSession() -> URLSession { - let configuration = URLSessionConfiguration.default - configuration.httpAdditionalHeaders = buildHeaders() - let sessionDelegate = SessionDelegate() - sessionDelegate.credential = credential - sessionDelegate.taskDidReceiveChallenge = taskDidReceiveChallenge - return URLSession(configuration: configuration, delegate: sessionDelegate, delegateQueue: nil) + return defaultURLSession } /** @@ -94,10 +100,7 @@ open class URLSessionRequestBuilder: RequestBuilder { } override open func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (_ result: Swift.Result, ErrorResponse>) -> Void) { - let urlSessionId = UUID().uuidString - // Create a new manager for each request to customize its request header let urlSession = createURLSession() - urlSessionStore[urlSessionId] = urlSession guard let xMethod = HTTPMethod(rawValue: method) else { fatalError("Unsupported Http method - \(method)") @@ -123,14 +126,17 @@ open class URLSessionRequestBuilder: RequestBuilder { } } - let cleanupRequest = { - urlSessionStore[urlSessionId]?.finishTasksAndInvalidate() - urlSessionStore[urlSessionId] = nil - } - do { let request = try createURLRequest(urlSession: urlSession, method: xMethod, encoding: encoding, headers: headers) + var taskIdentifier: Int? + let cleanupRequest = { + if let taskIdentifier = taskIdentifier { + challengeHandlerStore[taskIdentifier] = nil + credentialStore[taskIdentifier] = nil + } + } + let dataTask = urlSession.dataTask(with: request) { data, response, error in if let taskCompletionShouldRetry = self.taskCompletionShouldRetry { @@ -159,11 +165,14 @@ open class URLSessionRequestBuilder: RequestBuilder { onProgressReady?(dataTask.progress) } + taskIdentifier = dataTask.taskIdentifier + challengeHandlerStore[dataTask.taskIdentifier] = taskDidReceiveChallenge + credentialStore[dataTask.taskIdentifier] = credential + dataTask.resume() } catch { apiResponseQueue.async { - cleanupRequest() completion(.failure(ErrorResponse.error(415, nil, nil, error))) } } @@ -398,25 +407,20 @@ open class URLSessionDecodableRequestBuilder: URLSessionRequestBui } } -private class SessionDelegate: NSObject, URLSessionDelegate, URLSessionDataDelegate { - - var credential: URLCredential? - - var taskDidReceiveChallenge: ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))? - +private class SessionDelegate: NSObject, URLSessionTaskDelegate { func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { var disposition: URLSession.AuthChallengeDisposition = .performDefaultHandling var credential: URLCredential? - if let taskDidReceiveChallenge = taskDidReceiveChallenge { + if let taskDidReceiveChallenge = challengeHandlerStore[task.taskIdentifier] { (disposition, credential) = taskDidReceiveChallenge(session, task, challenge) } else { if challenge.previousFailureCount > 0 { disposition = .rejectProtectionSpace } else { - credential = self.credential ?? session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace) + credential = credentialStore[task.taskIdentifier] ?? session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace) if credential != nil { disposition = .useCredential diff --git a/samples/client/petstore/swift5/oneOf/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift b/samples/client/petstore/swift5/oneOf/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift index 762df8c3045..c60991d13af 100644 --- a/samples/client/petstore/swift5/oneOf/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift +++ b/samples/client/petstore/swift5/oneOf/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift @@ -19,15 +19,26 @@ class URLSessionRequestBuilderFactory: RequestBuilderFactory { } } +public typealias PetstoreClientAPIChallengeHandler = ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?)) + +// Store the URLSession's delegate to retain its reference +private let sessionDelegate = SessionDelegate() + // Store the URLSession to retain its reference -private var urlSessionStore = SynchronizedDictionary() +private let defaultURLSession = URLSession(configuration: .default, delegate: sessionDelegate, delegateQueue: nil) + +// Store current taskDidReceiveChallenge for every URLSessionTask +private var challengeHandlerStore = SynchronizedDictionary() + +// Store current URLCredential for every URLSessionTask +private var credentialStore = SynchronizedDictionary() open class URLSessionRequestBuilder: RequestBuilder { /** May be assigned if you want to control the authentication challenges. */ - public var taskDidReceiveChallenge: ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))? + public var taskDidReceiveChallenge: PetstoreClientAPIChallengeHandler? /** May be assigned if you want to do any of those things: @@ -47,12 +58,7 @@ open class URLSessionRequestBuilder: RequestBuilder { configuration. */ open func createURLSession() -> URLSession { - let configuration = URLSessionConfiguration.default - configuration.httpAdditionalHeaders = buildHeaders() - let sessionDelegate = SessionDelegate() - sessionDelegate.credential = credential - sessionDelegate.taskDidReceiveChallenge = taskDidReceiveChallenge - return URLSession(configuration: configuration, delegate: sessionDelegate, delegateQueue: nil) + return defaultURLSession } /** @@ -94,10 +100,7 @@ open class URLSessionRequestBuilder: RequestBuilder { } override open func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (_ result: Swift.Result, ErrorResponse>) -> Void) { - let urlSessionId = UUID().uuidString - // Create a new manager for each request to customize its request header let urlSession = createURLSession() - urlSessionStore[urlSessionId] = urlSession guard let xMethod = HTTPMethod(rawValue: method) else { fatalError("Unsupported Http method - \(method)") @@ -123,14 +126,17 @@ open class URLSessionRequestBuilder: RequestBuilder { } } - let cleanupRequest = { - urlSessionStore[urlSessionId]?.finishTasksAndInvalidate() - urlSessionStore[urlSessionId] = nil - } - do { let request = try createURLRequest(urlSession: urlSession, method: xMethod, encoding: encoding, headers: headers) + var taskIdentifier: Int? + let cleanupRequest = { + if let taskIdentifier = taskIdentifier { + challengeHandlerStore[taskIdentifier] = nil + credentialStore[taskIdentifier] = nil + } + } + let dataTask = urlSession.dataTask(with: request) { data, response, error in if let taskCompletionShouldRetry = self.taskCompletionShouldRetry { @@ -159,11 +165,14 @@ open class URLSessionRequestBuilder: RequestBuilder { onProgressReady?(dataTask.progress) } + taskIdentifier = dataTask.taskIdentifier + challengeHandlerStore[dataTask.taskIdentifier] = taskDidReceiveChallenge + credentialStore[dataTask.taskIdentifier] = credential + dataTask.resume() } catch { apiResponseQueue.async { - cleanupRequest() completion(.failure(ErrorResponse.error(415, nil, nil, error))) } } @@ -398,25 +407,20 @@ open class URLSessionDecodableRequestBuilder: URLSessionRequestBui } } -private class SessionDelegate: NSObject, URLSessionDelegate, URLSessionDataDelegate { - - var credential: URLCredential? - - var taskDidReceiveChallenge: ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))? - +private class SessionDelegate: NSObject, URLSessionTaskDelegate { func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { var disposition: URLSession.AuthChallengeDisposition = .performDefaultHandling var credential: URLCredential? - if let taskDidReceiveChallenge = taskDidReceiveChallenge { + if let taskDidReceiveChallenge = challengeHandlerStore[task.taskIdentifier] { (disposition, credential) = taskDidReceiveChallenge(session, task, challenge) } else { if challenge.previousFailureCount > 0 { disposition = .rejectProtectionSpace } else { - credential = self.credential ?? session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace) + credential = credentialStore[task.taskIdentifier] ?? session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace) if credential != nil { disposition = .useCredential diff --git a/samples/client/petstore/swift5/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift b/samples/client/petstore/swift5/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift index 762df8c3045..c60991d13af 100644 --- a/samples/client/petstore/swift5/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift +++ b/samples/client/petstore/swift5/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift @@ -19,15 +19,26 @@ class URLSessionRequestBuilderFactory: RequestBuilderFactory { } } +public typealias PetstoreClientAPIChallengeHandler = ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?)) + +// Store the URLSession's delegate to retain its reference +private let sessionDelegate = SessionDelegate() + // Store the URLSession to retain its reference -private var urlSessionStore = SynchronizedDictionary() +private let defaultURLSession = URLSession(configuration: .default, delegate: sessionDelegate, delegateQueue: nil) + +// Store current taskDidReceiveChallenge for every URLSessionTask +private var challengeHandlerStore = SynchronizedDictionary() + +// Store current URLCredential for every URLSessionTask +private var credentialStore = SynchronizedDictionary() open class URLSessionRequestBuilder: RequestBuilder { /** May be assigned if you want to control the authentication challenges. */ - public var taskDidReceiveChallenge: ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))? + public var taskDidReceiveChallenge: PetstoreClientAPIChallengeHandler? /** May be assigned if you want to do any of those things: @@ -47,12 +58,7 @@ open class URLSessionRequestBuilder: RequestBuilder { configuration. */ open func createURLSession() -> URLSession { - let configuration = URLSessionConfiguration.default - configuration.httpAdditionalHeaders = buildHeaders() - let sessionDelegate = SessionDelegate() - sessionDelegate.credential = credential - sessionDelegate.taskDidReceiveChallenge = taskDidReceiveChallenge - return URLSession(configuration: configuration, delegate: sessionDelegate, delegateQueue: nil) + return defaultURLSession } /** @@ -94,10 +100,7 @@ open class URLSessionRequestBuilder: RequestBuilder { } override open func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (_ result: Swift.Result, ErrorResponse>) -> Void) { - let urlSessionId = UUID().uuidString - // Create a new manager for each request to customize its request header let urlSession = createURLSession() - urlSessionStore[urlSessionId] = urlSession guard let xMethod = HTTPMethod(rawValue: method) else { fatalError("Unsupported Http method - \(method)") @@ -123,14 +126,17 @@ open class URLSessionRequestBuilder: RequestBuilder { } } - let cleanupRequest = { - urlSessionStore[urlSessionId]?.finishTasksAndInvalidate() - urlSessionStore[urlSessionId] = nil - } - do { let request = try createURLRequest(urlSession: urlSession, method: xMethod, encoding: encoding, headers: headers) + var taskIdentifier: Int? + let cleanupRequest = { + if let taskIdentifier = taskIdentifier { + challengeHandlerStore[taskIdentifier] = nil + credentialStore[taskIdentifier] = nil + } + } + let dataTask = urlSession.dataTask(with: request) { data, response, error in if let taskCompletionShouldRetry = self.taskCompletionShouldRetry { @@ -159,11 +165,14 @@ open class URLSessionRequestBuilder: RequestBuilder { onProgressReady?(dataTask.progress) } + taskIdentifier = dataTask.taskIdentifier + challengeHandlerStore[dataTask.taskIdentifier] = taskDidReceiveChallenge + credentialStore[dataTask.taskIdentifier] = credential + dataTask.resume() } catch { apiResponseQueue.async { - cleanupRequest() completion(.failure(ErrorResponse.error(415, nil, nil, error))) } } @@ -398,25 +407,20 @@ open class URLSessionDecodableRequestBuilder: URLSessionRequestBui } } -private class SessionDelegate: NSObject, URLSessionDelegate, URLSessionDataDelegate { - - var credential: URLCredential? - - var taskDidReceiveChallenge: ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))? - +private class SessionDelegate: NSObject, URLSessionTaskDelegate { func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { var disposition: URLSession.AuthChallengeDisposition = .performDefaultHandling var credential: URLCredential? - if let taskDidReceiveChallenge = taskDidReceiveChallenge { + if let taskDidReceiveChallenge = challengeHandlerStore[task.taskIdentifier] { (disposition, credential) = taskDidReceiveChallenge(session, task, challenge) } else { if challenge.previousFailureCount > 0 { disposition = .rejectProtectionSpace } else { - credential = self.credential ?? session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace) + credential = credentialStore[task.taskIdentifier] ?? session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace) if credential != nil { disposition = .useCredential diff --git a/samples/client/petstore/swift5/readonlyProperties/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift b/samples/client/petstore/swift5/readonlyProperties/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift index 762df8c3045..c60991d13af 100644 --- a/samples/client/petstore/swift5/readonlyProperties/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift +++ b/samples/client/petstore/swift5/readonlyProperties/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift @@ -19,15 +19,26 @@ class URLSessionRequestBuilderFactory: RequestBuilderFactory { } } +public typealias PetstoreClientAPIChallengeHandler = ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?)) + +// Store the URLSession's delegate to retain its reference +private let sessionDelegate = SessionDelegate() + // Store the URLSession to retain its reference -private var urlSessionStore = SynchronizedDictionary() +private let defaultURLSession = URLSession(configuration: .default, delegate: sessionDelegate, delegateQueue: nil) + +// Store current taskDidReceiveChallenge for every URLSessionTask +private var challengeHandlerStore = SynchronizedDictionary() + +// Store current URLCredential for every URLSessionTask +private var credentialStore = SynchronizedDictionary() open class URLSessionRequestBuilder: RequestBuilder { /** May be assigned if you want to control the authentication challenges. */ - public var taskDidReceiveChallenge: ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))? + public var taskDidReceiveChallenge: PetstoreClientAPIChallengeHandler? /** May be assigned if you want to do any of those things: @@ -47,12 +58,7 @@ open class URLSessionRequestBuilder: RequestBuilder { configuration. */ open func createURLSession() -> URLSession { - let configuration = URLSessionConfiguration.default - configuration.httpAdditionalHeaders = buildHeaders() - let sessionDelegate = SessionDelegate() - sessionDelegate.credential = credential - sessionDelegate.taskDidReceiveChallenge = taskDidReceiveChallenge - return URLSession(configuration: configuration, delegate: sessionDelegate, delegateQueue: nil) + return defaultURLSession } /** @@ -94,10 +100,7 @@ open class URLSessionRequestBuilder: RequestBuilder { } override open func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (_ result: Swift.Result, ErrorResponse>) -> Void) { - let urlSessionId = UUID().uuidString - // Create a new manager for each request to customize its request header let urlSession = createURLSession() - urlSessionStore[urlSessionId] = urlSession guard let xMethod = HTTPMethod(rawValue: method) else { fatalError("Unsupported Http method - \(method)") @@ -123,14 +126,17 @@ open class URLSessionRequestBuilder: RequestBuilder { } } - let cleanupRequest = { - urlSessionStore[urlSessionId]?.finishTasksAndInvalidate() - urlSessionStore[urlSessionId] = nil - } - do { let request = try createURLRequest(urlSession: urlSession, method: xMethod, encoding: encoding, headers: headers) + var taskIdentifier: Int? + let cleanupRequest = { + if let taskIdentifier = taskIdentifier { + challengeHandlerStore[taskIdentifier] = nil + credentialStore[taskIdentifier] = nil + } + } + let dataTask = urlSession.dataTask(with: request) { data, response, error in if let taskCompletionShouldRetry = self.taskCompletionShouldRetry { @@ -159,11 +165,14 @@ open class URLSessionRequestBuilder: RequestBuilder { onProgressReady?(dataTask.progress) } + taskIdentifier = dataTask.taskIdentifier + challengeHandlerStore[dataTask.taskIdentifier] = taskDidReceiveChallenge + credentialStore[dataTask.taskIdentifier] = credential + dataTask.resume() } catch { apiResponseQueue.async { - cleanupRequest() completion(.failure(ErrorResponse.error(415, nil, nil, error))) } } @@ -398,25 +407,20 @@ open class URLSessionDecodableRequestBuilder: URLSessionRequestBui } } -private class SessionDelegate: NSObject, URLSessionDelegate, URLSessionDataDelegate { - - var credential: URLCredential? - - var taskDidReceiveChallenge: ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))? - +private class SessionDelegate: NSObject, URLSessionTaskDelegate { func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { var disposition: URLSession.AuthChallengeDisposition = .performDefaultHandling var credential: URLCredential? - if let taskDidReceiveChallenge = taskDidReceiveChallenge { + if let taskDidReceiveChallenge = challengeHandlerStore[task.taskIdentifier] { (disposition, credential) = taskDidReceiveChallenge(session, task, challenge) } else { if challenge.previousFailureCount > 0 { disposition = .rejectProtectionSpace } else { - credential = self.credential ?? session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace) + credential = credentialStore[task.taskIdentifier] ?? session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace) if credential != nil { disposition = .useCredential diff --git a/samples/client/petstore/swift5/resultLibrary/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift b/samples/client/petstore/swift5/resultLibrary/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift index 762df8c3045..c60991d13af 100644 --- a/samples/client/petstore/swift5/resultLibrary/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift +++ b/samples/client/petstore/swift5/resultLibrary/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift @@ -19,15 +19,26 @@ class URLSessionRequestBuilderFactory: RequestBuilderFactory { } } +public typealias PetstoreClientAPIChallengeHandler = ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?)) + +// Store the URLSession's delegate to retain its reference +private let sessionDelegate = SessionDelegate() + // Store the URLSession to retain its reference -private var urlSessionStore = SynchronizedDictionary() +private let defaultURLSession = URLSession(configuration: .default, delegate: sessionDelegate, delegateQueue: nil) + +// Store current taskDidReceiveChallenge for every URLSessionTask +private var challengeHandlerStore = SynchronizedDictionary() + +// Store current URLCredential for every URLSessionTask +private var credentialStore = SynchronizedDictionary() open class URLSessionRequestBuilder: RequestBuilder { /** May be assigned if you want to control the authentication challenges. */ - public var taskDidReceiveChallenge: ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))? + public var taskDidReceiveChallenge: PetstoreClientAPIChallengeHandler? /** May be assigned if you want to do any of those things: @@ -47,12 +58,7 @@ open class URLSessionRequestBuilder: RequestBuilder { configuration. */ open func createURLSession() -> URLSession { - let configuration = URLSessionConfiguration.default - configuration.httpAdditionalHeaders = buildHeaders() - let sessionDelegate = SessionDelegate() - sessionDelegate.credential = credential - sessionDelegate.taskDidReceiveChallenge = taskDidReceiveChallenge - return URLSession(configuration: configuration, delegate: sessionDelegate, delegateQueue: nil) + return defaultURLSession } /** @@ -94,10 +100,7 @@ open class URLSessionRequestBuilder: RequestBuilder { } override open func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (_ result: Swift.Result, ErrorResponse>) -> Void) { - let urlSessionId = UUID().uuidString - // Create a new manager for each request to customize its request header let urlSession = createURLSession() - urlSessionStore[urlSessionId] = urlSession guard let xMethod = HTTPMethod(rawValue: method) else { fatalError("Unsupported Http method - \(method)") @@ -123,14 +126,17 @@ open class URLSessionRequestBuilder: RequestBuilder { } } - let cleanupRequest = { - urlSessionStore[urlSessionId]?.finishTasksAndInvalidate() - urlSessionStore[urlSessionId] = nil - } - do { let request = try createURLRequest(urlSession: urlSession, method: xMethod, encoding: encoding, headers: headers) + var taskIdentifier: Int? + let cleanupRequest = { + if let taskIdentifier = taskIdentifier { + challengeHandlerStore[taskIdentifier] = nil + credentialStore[taskIdentifier] = nil + } + } + let dataTask = urlSession.dataTask(with: request) { data, response, error in if let taskCompletionShouldRetry = self.taskCompletionShouldRetry { @@ -159,11 +165,14 @@ open class URLSessionRequestBuilder: RequestBuilder { onProgressReady?(dataTask.progress) } + taskIdentifier = dataTask.taskIdentifier + challengeHandlerStore[dataTask.taskIdentifier] = taskDidReceiveChallenge + credentialStore[dataTask.taskIdentifier] = credential + dataTask.resume() } catch { apiResponseQueue.async { - cleanupRequest() completion(.failure(ErrorResponse.error(415, nil, nil, error))) } } @@ -398,25 +407,20 @@ open class URLSessionDecodableRequestBuilder: URLSessionRequestBui } } -private class SessionDelegate: NSObject, URLSessionDelegate, URLSessionDataDelegate { - - var credential: URLCredential? - - var taskDidReceiveChallenge: ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))? - +private class SessionDelegate: NSObject, URLSessionTaskDelegate { func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { var disposition: URLSession.AuthChallengeDisposition = .performDefaultHandling var credential: URLCredential? - if let taskDidReceiveChallenge = taskDidReceiveChallenge { + if let taskDidReceiveChallenge = challengeHandlerStore[task.taskIdentifier] { (disposition, credential) = taskDidReceiveChallenge(session, task, challenge) } else { if challenge.previousFailureCount > 0 { disposition = .rejectProtectionSpace } else { - credential = self.credential ?? session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace) + credential = credentialStore[task.taskIdentifier] ?? session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace) if credential != nil { disposition = .useCredential diff --git a/samples/client/petstore/swift5/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift b/samples/client/petstore/swift5/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift index 762df8c3045..c60991d13af 100644 --- a/samples/client/petstore/swift5/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift +++ b/samples/client/petstore/swift5/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift @@ -19,15 +19,26 @@ class URLSessionRequestBuilderFactory: RequestBuilderFactory { } } +public typealias PetstoreClientAPIChallengeHandler = ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?)) + +// Store the URLSession's delegate to retain its reference +private let sessionDelegate = SessionDelegate() + // Store the URLSession to retain its reference -private var urlSessionStore = SynchronizedDictionary() +private let defaultURLSession = URLSession(configuration: .default, delegate: sessionDelegate, delegateQueue: nil) + +// Store current taskDidReceiveChallenge for every URLSessionTask +private var challengeHandlerStore = SynchronizedDictionary() + +// Store current URLCredential for every URLSessionTask +private var credentialStore = SynchronizedDictionary() open class URLSessionRequestBuilder: RequestBuilder { /** May be assigned if you want to control the authentication challenges. */ - public var taskDidReceiveChallenge: ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))? + public var taskDidReceiveChallenge: PetstoreClientAPIChallengeHandler? /** May be assigned if you want to do any of those things: @@ -47,12 +58,7 @@ open class URLSessionRequestBuilder: RequestBuilder { configuration. */ open func createURLSession() -> URLSession { - let configuration = URLSessionConfiguration.default - configuration.httpAdditionalHeaders = buildHeaders() - let sessionDelegate = SessionDelegate() - sessionDelegate.credential = credential - sessionDelegate.taskDidReceiveChallenge = taskDidReceiveChallenge - return URLSession(configuration: configuration, delegate: sessionDelegate, delegateQueue: nil) + return defaultURLSession } /** @@ -94,10 +100,7 @@ open class URLSessionRequestBuilder: RequestBuilder { } override open func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (_ result: Swift.Result, ErrorResponse>) -> Void) { - let urlSessionId = UUID().uuidString - // Create a new manager for each request to customize its request header let urlSession = createURLSession() - urlSessionStore[urlSessionId] = urlSession guard let xMethod = HTTPMethod(rawValue: method) else { fatalError("Unsupported Http method - \(method)") @@ -123,14 +126,17 @@ open class URLSessionRequestBuilder: RequestBuilder { } } - let cleanupRequest = { - urlSessionStore[urlSessionId]?.finishTasksAndInvalidate() - urlSessionStore[urlSessionId] = nil - } - do { let request = try createURLRequest(urlSession: urlSession, method: xMethod, encoding: encoding, headers: headers) + var taskIdentifier: Int? + let cleanupRequest = { + if let taskIdentifier = taskIdentifier { + challengeHandlerStore[taskIdentifier] = nil + credentialStore[taskIdentifier] = nil + } + } + let dataTask = urlSession.dataTask(with: request) { data, response, error in if let taskCompletionShouldRetry = self.taskCompletionShouldRetry { @@ -159,11 +165,14 @@ open class URLSessionRequestBuilder: RequestBuilder { onProgressReady?(dataTask.progress) } + taskIdentifier = dataTask.taskIdentifier + challengeHandlerStore[dataTask.taskIdentifier] = taskDidReceiveChallenge + credentialStore[dataTask.taskIdentifier] = credential + dataTask.resume() } catch { apiResponseQueue.async { - cleanupRequest() completion(.failure(ErrorResponse.error(415, nil, nil, error))) } } @@ -398,25 +407,20 @@ open class URLSessionDecodableRequestBuilder: URLSessionRequestBui } } -private class SessionDelegate: NSObject, URLSessionDelegate, URLSessionDataDelegate { - - var credential: URLCredential? - - var taskDidReceiveChallenge: ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))? - +private class SessionDelegate: NSObject, URLSessionTaskDelegate { func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { var disposition: URLSession.AuthChallengeDisposition = .performDefaultHandling var credential: URLCredential? - if let taskDidReceiveChallenge = taskDidReceiveChallenge { + if let taskDidReceiveChallenge = challengeHandlerStore[task.taskIdentifier] { (disposition, credential) = taskDidReceiveChallenge(session, task, challenge) } else { if challenge.previousFailureCount > 0 { disposition = .rejectProtectionSpace } else { - credential = self.credential ?? session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace) + credential = credentialStore[task.taskIdentifier] ?? session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace) if credential != nil { disposition = .useCredential diff --git a/samples/client/petstore/swift5/urlsessionLibrary/Sources/PetstoreClient/URLSessionImplementations.swift b/samples/client/petstore/swift5/urlsessionLibrary/Sources/PetstoreClient/URLSessionImplementations.swift index 762df8c3045..c60991d13af 100644 --- a/samples/client/petstore/swift5/urlsessionLibrary/Sources/PetstoreClient/URLSessionImplementations.swift +++ b/samples/client/petstore/swift5/urlsessionLibrary/Sources/PetstoreClient/URLSessionImplementations.swift @@ -19,15 +19,26 @@ class URLSessionRequestBuilderFactory: RequestBuilderFactory { } } +public typealias PetstoreClientAPIChallengeHandler = ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?)) + +// Store the URLSession's delegate to retain its reference +private let sessionDelegate = SessionDelegate() + // Store the URLSession to retain its reference -private var urlSessionStore = SynchronizedDictionary() +private let defaultURLSession = URLSession(configuration: .default, delegate: sessionDelegate, delegateQueue: nil) + +// Store current taskDidReceiveChallenge for every URLSessionTask +private var challengeHandlerStore = SynchronizedDictionary() + +// Store current URLCredential for every URLSessionTask +private var credentialStore = SynchronizedDictionary() open class URLSessionRequestBuilder: RequestBuilder { /** May be assigned if you want to control the authentication challenges. */ - public var taskDidReceiveChallenge: ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))? + public var taskDidReceiveChallenge: PetstoreClientAPIChallengeHandler? /** May be assigned if you want to do any of those things: @@ -47,12 +58,7 @@ open class URLSessionRequestBuilder: RequestBuilder { configuration. */ open func createURLSession() -> URLSession { - let configuration = URLSessionConfiguration.default - configuration.httpAdditionalHeaders = buildHeaders() - let sessionDelegate = SessionDelegate() - sessionDelegate.credential = credential - sessionDelegate.taskDidReceiveChallenge = taskDidReceiveChallenge - return URLSession(configuration: configuration, delegate: sessionDelegate, delegateQueue: nil) + return defaultURLSession } /** @@ -94,10 +100,7 @@ open class URLSessionRequestBuilder: RequestBuilder { } override open func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (_ result: Swift.Result, ErrorResponse>) -> Void) { - let urlSessionId = UUID().uuidString - // Create a new manager for each request to customize its request header let urlSession = createURLSession() - urlSessionStore[urlSessionId] = urlSession guard let xMethod = HTTPMethod(rawValue: method) else { fatalError("Unsupported Http method - \(method)") @@ -123,14 +126,17 @@ open class URLSessionRequestBuilder: RequestBuilder { } } - let cleanupRequest = { - urlSessionStore[urlSessionId]?.finishTasksAndInvalidate() - urlSessionStore[urlSessionId] = nil - } - do { let request = try createURLRequest(urlSession: urlSession, method: xMethod, encoding: encoding, headers: headers) + var taskIdentifier: Int? + let cleanupRequest = { + if let taskIdentifier = taskIdentifier { + challengeHandlerStore[taskIdentifier] = nil + credentialStore[taskIdentifier] = nil + } + } + let dataTask = urlSession.dataTask(with: request) { data, response, error in if let taskCompletionShouldRetry = self.taskCompletionShouldRetry { @@ -159,11 +165,14 @@ open class URLSessionRequestBuilder: RequestBuilder { onProgressReady?(dataTask.progress) } + taskIdentifier = dataTask.taskIdentifier + challengeHandlerStore[dataTask.taskIdentifier] = taskDidReceiveChallenge + credentialStore[dataTask.taskIdentifier] = credential + dataTask.resume() } catch { apiResponseQueue.async { - cleanupRequest() completion(.failure(ErrorResponse.error(415, nil, nil, error))) } } @@ -398,25 +407,20 @@ open class URLSessionDecodableRequestBuilder: URLSessionRequestBui } } -private class SessionDelegate: NSObject, URLSessionDelegate, URLSessionDataDelegate { - - var credential: URLCredential? - - var taskDidReceiveChallenge: ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))? - +private class SessionDelegate: NSObject, URLSessionTaskDelegate { func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { var disposition: URLSession.AuthChallengeDisposition = .performDefaultHandling var credential: URLCredential? - if let taskDidReceiveChallenge = taskDidReceiveChallenge { + if let taskDidReceiveChallenge = challengeHandlerStore[task.taskIdentifier] { (disposition, credential) = taskDidReceiveChallenge(session, task, challenge) } else { if challenge.previousFailureCount > 0 { disposition = .rejectProtectionSpace } else { - credential = self.credential ?? session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace) + credential = credentialStore[task.taskIdentifier] ?? session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace) if credential != nil { disposition = .useCredential diff --git a/samples/client/petstore/swift5/x-swift-hashable/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift b/samples/client/petstore/swift5/x-swift-hashable/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift index 762df8c3045..c60991d13af 100644 --- a/samples/client/petstore/swift5/x-swift-hashable/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift +++ b/samples/client/petstore/swift5/x-swift-hashable/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift @@ -19,15 +19,26 @@ class URLSessionRequestBuilderFactory: RequestBuilderFactory { } } +public typealias PetstoreClientAPIChallengeHandler = ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?)) + +// Store the URLSession's delegate to retain its reference +private let sessionDelegate = SessionDelegate() + // Store the URLSession to retain its reference -private var urlSessionStore = SynchronizedDictionary() +private let defaultURLSession = URLSession(configuration: .default, delegate: sessionDelegate, delegateQueue: nil) + +// Store current taskDidReceiveChallenge for every URLSessionTask +private var challengeHandlerStore = SynchronizedDictionary() + +// Store current URLCredential for every URLSessionTask +private var credentialStore = SynchronizedDictionary() open class URLSessionRequestBuilder: RequestBuilder { /** May be assigned if you want to control the authentication challenges. */ - public var taskDidReceiveChallenge: ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))? + public var taskDidReceiveChallenge: PetstoreClientAPIChallengeHandler? /** May be assigned if you want to do any of those things: @@ -47,12 +58,7 @@ open class URLSessionRequestBuilder: RequestBuilder { configuration. */ open func createURLSession() -> URLSession { - let configuration = URLSessionConfiguration.default - configuration.httpAdditionalHeaders = buildHeaders() - let sessionDelegate = SessionDelegate() - sessionDelegate.credential = credential - sessionDelegate.taskDidReceiveChallenge = taskDidReceiveChallenge - return URLSession(configuration: configuration, delegate: sessionDelegate, delegateQueue: nil) + return defaultURLSession } /** @@ -94,10 +100,7 @@ open class URLSessionRequestBuilder: RequestBuilder { } override open func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (_ result: Swift.Result, ErrorResponse>) -> Void) { - let urlSessionId = UUID().uuidString - // Create a new manager for each request to customize its request header let urlSession = createURLSession() - urlSessionStore[urlSessionId] = urlSession guard let xMethod = HTTPMethod(rawValue: method) else { fatalError("Unsupported Http method - \(method)") @@ -123,14 +126,17 @@ open class URLSessionRequestBuilder: RequestBuilder { } } - let cleanupRequest = { - urlSessionStore[urlSessionId]?.finishTasksAndInvalidate() - urlSessionStore[urlSessionId] = nil - } - do { let request = try createURLRequest(urlSession: urlSession, method: xMethod, encoding: encoding, headers: headers) + var taskIdentifier: Int? + let cleanupRequest = { + if let taskIdentifier = taskIdentifier { + challengeHandlerStore[taskIdentifier] = nil + credentialStore[taskIdentifier] = nil + } + } + let dataTask = urlSession.dataTask(with: request) { data, response, error in if let taskCompletionShouldRetry = self.taskCompletionShouldRetry { @@ -159,11 +165,14 @@ open class URLSessionRequestBuilder: RequestBuilder { onProgressReady?(dataTask.progress) } + taskIdentifier = dataTask.taskIdentifier + challengeHandlerStore[dataTask.taskIdentifier] = taskDidReceiveChallenge + credentialStore[dataTask.taskIdentifier] = credential + dataTask.resume() } catch { apiResponseQueue.async { - cleanupRequest() completion(.failure(ErrorResponse.error(415, nil, nil, error))) } } @@ -398,25 +407,20 @@ open class URLSessionDecodableRequestBuilder: URLSessionRequestBui } } -private class SessionDelegate: NSObject, URLSessionDelegate, URLSessionDataDelegate { - - var credential: URLCredential? - - var taskDidReceiveChallenge: ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))? - +private class SessionDelegate: NSObject, URLSessionTaskDelegate { func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { var disposition: URLSession.AuthChallengeDisposition = .performDefaultHandling var credential: URLCredential? - if let taskDidReceiveChallenge = taskDidReceiveChallenge { + if let taskDidReceiveChallenge = challengeHandlerStore[task.taskIdentifier] { (disposition, credential) = taskDidReceiveChallenge(session, task, challenge) } else { if challenge.previousFailureCount > 0 { disposition = .rejectProtectionSpace } else { - credential = self.credential ?? session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace) + credential = credentialStore[task.taskIdentifier] ?? session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace) if credential != nil { disposition = .useCredential