[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:
David Horvath 2021-11-14 03:33:18 +01:00 committed by GitHub
parent 65f3845c17
commit 552a31d85c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 406 additions and 350 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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