Skip to content
GitLab
    • Explore Projects Groups Snippets
Projects Groups Snippets
  • /
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
  • Sign in / Register
  • O openapi-generator
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
  • Issues 3,476
    • Issues 3,476
    • List
    • Boards
    • Service Desk
    • Milestones
  • Merge requests 402
    • Merge requests 402
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
  • Deployments
    • Deployments
    • Environments
    • Releases
  • Packages and registries
    • Packages and registries
    • Package Registry
    • Infrastructure Registry
  • Monitor
    • Monitor
    • Incidents
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • OpenAPI Tools
  • openapi-generator
  • Merge requests
  • !10790

[swift5] Reuse URLSessions

  • Review changes

  • Download
  • Email patches
  • Plain diff
Merged Administrator requested to merge github/fork/DavidHorvath/swift5-reuse-urlsession into master 3 years ago
  • Overview 0
  • Commits 3
  • Pipelines 0
  • Changes 14

Created by: DavidHorvath

resolve #8562 (closed)

Creating new URLSession for every request isn't optimal and it is not recommended by Apple. Also, NSPOSIXErrorDomain Code=28 "No space left on device" will get thrown after too many URLSessions get created.

https://developer.apple.com/videos/play/wwdc2018/714/?time=1646 https://developer.apple.com/videos/play/wwdc2017/709/ https://developer.apple.com/forums/thread/84663 https://stackoverflow.com/questions/67318867/error-domain-nsposixerrordomain-code-28-no-space-left-on-device-userinfo-kcf/67507327#67507327

I've hashed the session's configuration, credentials and sessionDelegate with Hasher so we can reuse URLSessions with the same settings.

PR checklist

  • Read the contribution guidelines.
  • Pull Request title clearly describes the work in the pull request and Pull Request description provides details about how to validate the work. Missing information here may result in delayed response from the community.
  • Run the following to build the project and update samples:
    ./mvnw clean package 
    ./bin/generate-samples.sh
    ./bin/utils/export_docs_generators.sh
    Commit all changed files. This is important, as CI jobs will verify all generator outputs of your HEAD commit as it would merge with master. These must match the expectations made by your contribution. You may regenerate an individual generator by passing the relevant config(s) as an argument to the script, for example ./bin/generate-samples.sh bin/configs/java*. For Windows users, please run the script in Git BASH.
  • File the PR against the correct branch: master (5.3.0), 6.0.x
  • If your PR is targeting a particular programming language, @mention the technical committee members, so they are more likely to review the pull request. @4brunu
Compare
  • master (base)

and
  • latest version
    d2e001d0
    3 commits, 2 years ago

14 files
+ 406
- 350

    Preferences

    File browser
    Compare changes
modules/…/…/…/…‎/…/…/urlsession‎
URLSessionImpleme‎ntations.mustache‎ +29 -25
samples/client/‎petstore/swift5‎
asyncAwaitLibra‎ry/…/…/OpenAPIs‎
URLSessionImple‎mentations.swift‎ +29 -25
combineLibrar‎y/…/…/OpenAPIs‎
URLSessionImple‎mentations.swift‎ +29 -25
default/PetstoreCli‎ent/Classes/OpenAPIs‎
URLSessionImple‎mentations.swift‎ +29 -25
deprecated/Petstor‎eClient/…/OpenAPIs‎
URLSessionImple‎mentations.swift‎ +29 -25
nonPublicApi/Petsto‎reClient/…/OpenAPIs‎
URLSessionImple‎mentations.swift‎ +29 -25
objcCompatibl‎e/…/…/OpenAPIs‎
URLSessionImple‎mentations.swift‎ +29 -25
oneOf/PetstoreClie‎nt/Classes/OpenAPIs‎
URLSessionImple‎mentations.swift‎ +29 -25
promisekitLibra‎ry/…/…/OpenAPIs‎
URLSessionImple‎mentations.swift‎ +29 -25
readonlyPropert‎ies/…/…/OpenAPIs‎
URLSessionImple‎mentations.swift‎ +29 -25
resultLibrary/Petst‎oreClient/…/OpenAPIs‎
URLSessionImple‎mentations.swift‎ +29 -25
rxswiftLibrar‎y/…/…/OpenAPIs‎
URLSessionImple‎mentations.swift‎ +29 -25
urlsessionLibrary‎/…/PetstoreClient‎
URLSessionImple‎mentations.swift‎ +29 -25
x-swift-hashab‎le/…/…/OpenAPIs‎
URLSessionImple‎mentations.swift‎ +29 -25
modules/openapi-generator/src/main/resources/swift5/libraries/urlsession/URLSessionImplementations.mustache
+ 29
- 25
  • View file @ d2e001d0

  • Edit in single-file editor

  • Open in Web IDE


@@ -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
samples/client/petstore/swift5/asyncAwaitLibrary/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift
+ 29
- 25
  • View file @ d2e001d0

  • Edit in single-file editor

  • Open in Web IDE


@@ -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
samples/client/petstore/swift5/combineLibrary/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift
+ 29
- 25
  • View file @ d2e001d0

  • Edit in single-file editor

  • Open in Web IDE


@@ -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
samples/client/petstore/swift5/default/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift
+ 29
- 25
  • View file @ d2e001d0

  • Edit in single-file editor

  • Open in Web IDE


@@ -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
samples/client/petstore/swift5/deprecated/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift
+ 29
- 25
  • View file @ d2e001d0

  • Edit in single-file editor

  • Open in Web IDE


@@ -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
0 Assignees
None
Assign to
0 Reviewers
Request review from
Labels
0
None
0
None
    Assign labels
  • Manage project labels

Milestone
No milestone
None
None
Time tracking
Lock merge request
Unlocked
participants
Reference:
Source branch: github/fork/DavidHorvath/swift5-reuse-urlsession

Menu

Explore Projects Groups Snippets