forked from loafle/openapi-generator-original
[swift5] Reuse URLSessions (#10790)
* Reuse URLSession with same configuration resolve #8562 * Add typealias for taskDidReceiveChallenge closure type * Add generated sample code
This commit is contained in:
parent
65f3845c17
commit
552a31d85c
@ -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<String, URLSession>()
|
||||
private let defaultURLSession = URLSession(configuration: .default, delegate: sessionDelegate, delegateQueue: nil)
|
||||
|
||||
// Store current taskDidReceiveChallenge for every URLSessionTask
|
||||
private var challengeHandlerStore = SynchronizedDictionary<Int, {{projectName}}APIChallengeHandler>()
|
||||
|
||||
// Store current URLCredential for every URLSessionTask
|
||||
private var credentialStore = SynchronizedDictionary<Int, URLCredential>()
|
||||
|
||||
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class URLSessionRequestBuilder<T>: RequestBuilder<T> {
|
||||
|
||||
/**
|
||||
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<String, URLSession>()
|
||||
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<String, URLSession>()
|
||||
}
|
||||
|
||||
override {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} func execute(_ apiResponseQueue: DispatchQueue = {{projectName}}API.apiResponseQueue, _ completion: @escaping (_ result: Swift.Result<Response<T>, 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<String, URLSession>()
|
||||
}
|
||||
}
|
||||
|
||||
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<String, URLSession>()
|
||||
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<String, URLSession>()
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -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<String, URLSession>()
|
||||
private let defaultURLSession = URLSession(configuration: .default, delegate: sessionDelegate, delegateQueue: nil)
|
||||
|
||||
// Store current taskDidReceiveChallenge for every URLSessionTask
|
||||
private var challengeHandlerStore = SynchronizedDictionary<Int, PetstoreClientAPIChallengeHandler>()
|
||||
|
||||
// Store current URLCredential for every URLSessionTask
|
||||
private var credentialStore = SynchronizedDictionary<Int, URLCredential>()
|
||||
|
||||
open class URLSessionRequestBuilder<T>: RequestBuilder<T> {
|
||||
|
||||
/**
|
||||
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<T>: RequestBuilder<T> {
|
||||
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<T>: RequestBuilder<T> {
|
||||
}
|
||||
|
||||
override open func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (_ result: Swift.Result<Response<T>, 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<T>: RequestBuilder<T> {
|
||||
}
|
||||
}
|
||||
|
||||
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<T>: RequestBuilder<T> {
|
||||
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<T: Decodable>: 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
|
||||
|
@ -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<String, URLSession>()
|
||||
private let defaultURLSession = URLSession(configuration: .default, delegate: sessionDelegate, delegateQueue: nil)
|
||||
|
||||
// Store current taskDidReceiveChallenge for every URLSessionTask
|
||||
private var challengeHandlerStore = SynchronizedDictionary<Int, PetstoreClientAPIChallengeHandler>()
|
||||
|
||||
// Store current URLCredential for every URLSessionTask
|
||||
private var credentialStore = SynchronizedDictionary<Int, URLCredential>()
|
||||
|
||||
open class URLSessionRequestBuilder<T>: RequestBuilder<T> {
|
||||
|
||||
/**
|
||||
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<T>: RequestBuilder<T> {
|
||||
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<T>: RequestBuilder<T> {
|
||||
}
|
||||
|
||||
override open func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (_ result: Swift.Result<Response<T>, 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<T>: RequestBuilder<T> {
|
||||
}
|
||||
}
|
||||
|
||||
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<T>: RequestBuilder<T> {
|
||||
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<T: Decodable>: 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
|
||||
|
@ -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<String, URLSession>()
|
||||
private let defaultURLSession = URLSession(configuration: .default, delegate: sessionDelegate, delegateQueue: nil)
|
||||
|
||||
// Store current taskDidReceiveChallenge for every URLSessionTask
|
||||
private var challengeHandlerStore = SynchronizedDictionary<Int, PetstoreClientAPIChallengeHandler>()
|
||||
|
||||
// Store current URLCredential for every URLSessionTask
|
||||
private var credentialStore = SynchronizedDictionary<Int, URLCredential>()
|
||||
|
||||
open class URLSessionRequestBuilder<T>: RequestBuilder<T> {
|
||||
|
||||
/**
|
||||
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<T>: RequestBuilder<T> {
|
||||
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<T>: RequestBuilder<T> {
|
||||
}
|
||||
|
||||
override open func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (_ result: Swift.Result<Response<T>, 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<T>: RequestBuilder<T> {
|
||||
}
|
||||
}
|
||||
|
||||
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<T>: RequestBuilder<T> {
|
||||
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<T: Decodable>: 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
|
||||
|
@ -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<String, URLSession>()
|
||||
private let defaultURLSession = URLSession(configuration: .default, delegate: sessionDelegate, delegateQueue: nil)
|
||||
|
||||
// Store current taskDidReceiveChallenge for every URLSessionTask
|
||||
private var challengeHandlerStore = SynchronizedDictionary<Int, PetstoreClientAPIChallengeHandler>()
|
||||
|
||||
// Store current URLCredential for every URLSessionTask
|
||||
private var credentialStore = SynchronizedDictionary<Int, URLCredential>()
|
||||
|
||||
open class URLSessionRequestBuilder<T>: RequestBuilder<T> {
|
||||
|
||||
/**
|
||||
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<T>: RequestBuilder<T> {
|
||||
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<T>: RequestBuilder<T> {
|
||||
}
|
||||
|
||||
override open func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (_ result: Swift.Result<Response<T>, 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<T>: RequestBuilder<T> {
|
||||
}
|
||||
}
|
||||
|
||||
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<T>: RequestBuilder<T> {
|
||||
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<T: Decodable>: 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
|
||||
|
@ -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<String, URLSession>()
|
||||
private let defaultURLSession = URLSession(configuration: .default, delegate: sessionDelegate, delegateQueue: nil)
|
||||
|
||||
// Store current taskDidReceiveChallenge for every URLSessionTask
|
||||
private var challengeHandlerStore = SynchronizedDictionary<Int, PetstoreClientAPIChallengeHandler>()
|
||||
|
||||
// Store current URLCredential for every URLSessionTask
|
||||
private var credentialStore = SynchronizedDictionary<Int, URLCredential>()
|
||||
|
||||
internal class URLSessionRequestBuilder<T>: RequestBuilder<T> {
|
||||
|
||||
/**
|
||||
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<T>: RequestBuilder<T> {
|
||||
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<T>: RequestBuilder<T> {
|
||||
}
|
||||
|
||||
override internal func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (_ result: Swift.Result<Response<T>, 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<T>: RequestBuilder<T> {
|
||||
}
|
||||
}
|
||||
|
||||
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<T>: RequestBuilder<T> {
|
||||
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<T: Decodable>: 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
|
||||
|
@ -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<String, URLSession>()
|
||||
private let defaultURLSession = URLSession(configuration: .default, delegate: sessionDelegate, delegateQueue: nil)
|
||||
|
||||
// Store current taskDidReceiveChallenge for every URLSessionTask
|
||||
private var challengeHandlerStore = SynchronizedDictionary<Int, PetstoreClientAPIChallengeHandler>()
|
||||
|
||||
// Store current URLCredential for every URLSessionTask
|
||||
private var credentialStore = SynchronizedDictionary<Int, URLCredential>()
|
||||
|
||||
open class URLSessionRequestBuilder<T>: RequestBuilder<T> {
|
||||
|
||||
/**
|
||||
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<T>: RequestBuilder<T> {
|
||||
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<T>: RequestBuilder<T> {
|
||||
}
|
||||
|
||||
override open func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (_ result: Swift.Result<Response<T>, 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<T>: RequestBuilder<T> {
|
||||
}
|
||||
}
|
||||
|
||||
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<T>: RequestBuilder<T> {
|
||||
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<T: Decodable>: 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
|
||||
|
@ -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<String, URLSession>()
|
||||
private let defaultURLSession = URLSession(configuration: .default, delegate: sessionDelegate, delegateQueue: nil)
|
||||
|
||||
// Store current taskDidReceiveChallenge for every URLSessionTask
|
||||
private var challengeHandlerStore = SynchronizedDictionary<Int, PetstoreClientAPIChallengeHandler>()
|
||||
|
||||
// Store current URLCredential for every URLSessionTask
|
||||
private var credentialStore = SynchronizedDictionary<Int, URLCredential>()
|
||||
|
||||
open class URLSessionRequestBuilder<T>: RequestBuilder<T> {
|
||||
|
||||
/**
|
||||
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<T>: RequestBuilder<T> {
|
||||
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<T>: RequestBuilder<T> {
|
||||
}
|
||||
|
||||
override open func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (_ result: Swift.Result<Response<T>, 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<T>: RequestBuilder<T> {
|
||||
}
|
||||
}
|
||||
|
||||
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<T>: RequestBuilder<T> {
|
||||
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<T: Decodable>: 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
|
||||
|
@ -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<String, URLSession>()
|
||||
private let defaultURLSession = URLSession(configuration: .default, delegate: sessionDelegate, delegateQueue: nil)
|
||||
|
||||
// Store current taskDidReceiveChallenge for every URLSessionTask
|
||||
private var challengeHandlerStore = SynchronizedDictionary<Int, PetstoreClientAPIChallengeHandler>()
|
||||
|
||||
// Store current URLCredential for every URLSessionTask
|
||||
private var credentialStore = SynchronizedDictionary<Int, URLCredential>()
|
||||
|
||||
open class URLSessionRequestBuilder<T>: RequestBuilder<T> {
|
||||
|
||||
/**
|
||||
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<T>: RequestBuilder<T> {
|
||||
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<T>: RequestBuilder<T> {
|
||||
}
|
||||
|
||||
override open func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (_ result: Swift.Result<Response<T>, 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<T>: RequestBuilder<T> {
|
||||
}
|
||||
}
|
||||
|
||||
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<T>: RequestBuilder<T> {
|
||||
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<T: Decodable>: 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
|
||||
|
@ -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<String, URLSession>()
|
||||
private let defaultURLSession = URLSession(configuration: .default, delegate: sessionDelegate, delegateQueue: nil)
|
||||
|
||||
// Store current taskDidReceiveChallenge for every URLSessionTask
|
||||
private var challengeHandlerStore = SynchronizedDictionary<Int, PetstoreClientAPIChallengeHandler>()
|
||||
|
||||
// Store current URLCredential for every URLSessionTask
|
||||
private var credentialStore = SynchronizedDictionary<Int, URLCredential>()
|
||||
|
||||
open class URLSessionRequestBuilder<T>: RequestBuilder<T> {
|
||||
|
||||
/**
|
||||
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<T>: RequestBuilder<T> {
|
||||
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<T>: RequestBuilder<T> {
|
||||
}
|
||||
|
||||
override open func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (_ result: Swift.Result<Response<T>, 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<T>: RequestBuilder<T> {
|
||||
}
|
||||
}
|
||||
|
||||
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<T>: RequestBuilder<T> {
|
||||
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<T: Decodable>: 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
|
||||
|
@ -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<String, URLSession>()
|
||||
private let defaultURLSession = URLSession(configuration: .default, delegate: sessionDelegate, delegateQueue: nil)
|
||||
|
||||
// Store current taskDidReceiveChallenge for every URLSessionTask
|
||||
private var challengeHandlerStore = SynchronizedDictionary<Int, PetstoreClientAPIChallengeHandler>()
|
||||
|
||||
// Store current URLCredential for every URLSessionTask
|
||||
private var credentialStore = SynchronizedDictionary<Int, URLCredential>()
|
||||
|
||||
open class URLSessionRequestBuilder<T>: RequestBuilder<T> {
|
||||
|
||||
/**
|
||||
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<T>: RequestBuilder<T> {
|
||||
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<T>: RequestBuilder<T> {
|
||||
}
|
||||
|
||||
override open func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (_ result: Swift.Result<Response<T>, 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<T>: RequestBuilder<T> {
|
||||
}
|
||||
}
|
||||
|
||||
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<T>: RequestBuilder<T> {
|
||||
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<T: Decodable>: 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
|
||||
|
@ -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<String, URLSession>()
|
||||
private let defaultURLSession = URLSession(configuration: .default, delegate: sessionDelegate, delegateQueue: nil)
|
||||
|
||||
// Store current taskDidReceiveChallenge for every URLSessionTask
|
||||
private var challengeHandlerStore = SynchronizedDictionary<Int, PetstoreClientAPIChallengeHandler>()
|
||||
|
||||
// Store current URLCredential for every URLSessionTask
|
||||
private var credentialStore = SynchronizedDictionary<Int, URLCredential>()
|
||||
|
||||
open class URLSessionRequestBuilder<T>: RequestBuilder<T> {
|
||||
|
||||
/**
|
||||
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<T>: RequestBuilder<T> {
|
||||
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<T>: RequestBuilder<T> {
|
||||
}
|
||||
|
||||
override open func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (_ result: Swift.Result<Response<T>, 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<T>: RequestBuilder<T> {
|
||||
}
|
||||
}
|
||||
|
||||
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<T>: RequestBuilder<T> {
|
||||
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<T: Decodable>: 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
|
||||
|
@ -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<String, URLSession>()
|
||||
private let defaultURLSession = URLSession(configuration: .default, delegate: sessionDelegate, delegateQueue: nil)
|
||||
|
||||
// Store current taskDidReceiveChallenge for every URLSessionTask
|
||||
private var challengeHandlerStore = SynchronizedDictionary<Int, PetstoreClientAPIChallengeHandler>()
|
||||
|
||||
// Store current URLCredential for every URLSessionTask
|
||||
private var credentialStore = SynchronizedDictionary<Int, URLCredential>()
|
||||
|
||||
open class URLSessionRequestBuilder<T>: RequestBuilder<T> {
|
||||
|
||||
/**
|
||||
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<T>: RequestBuilder<T> {
|
||||
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<T>: RequestBuilder<T> {
|
||||
}
|
||||
|
||||
override open func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (_ result: Swift.Result<Response<T>, 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<T>: RequestBuilder<T> {
|
||||
}
|
||||
}
|
||||
|
||||
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<T>: RequestBuilder<T> {
|
||||
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<T: Decodable>: 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
|
||||
|
@ -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<String, URLSession>()
|
||||
private let defaultURLSession = URLSession(configuration: .default, delegate: sessionDelegate, delegateQueue: nil)
|
||||
|
||||
// Store current taskDidReceiveChallenge for every URLSessionTask
|
||||
private var challengeHandlerStore = SynchronizedDictionary<Int, PetstoreClientAPIChallengeHandler>()
|
||||
|
||||
// Store current URLCredential for every URLSessionTask
|
||||
private var credentialStore = SynchronizedDictionary<Int, URLCredential>()
|
||||
|
||||
open class URLSessionRequestBuilder<T>: RequestBuilder<T> {
|
||||
|
||||
/**
|
||||
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<T>: RequestBuilder<T> {
|
||||
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<T>: RequestBuilder<T> {
|
||||
}
|
||||
|
||||
override open func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (_ result: Swift.Result<Response<T>, 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<T>: RequestBuilder<T> {
|
||||
}
|
||||
}
|
||||
|
||||
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<T>: RequestBuilder<T> {
|
||||
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<T: Decodable>: 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
|
||||
|
Loading…
x
Reference in New Issue
Block a user