@@ -11,7 +11,10 @@ extension OAuth {
1111
1212 /// A custom `URLProtocol` that can be registered with any `URLSessionConfiguration` that will automatically inject
1313 /// `Authorization: Bearer <<token>>` headers into outbound HTTP URLRequests based on ``Provider/authorizationPattern``.
14- public class URLProtocol : Foundation . URLProtocol {
14+ public class URLProtocol : Foundation . URLProtocol , URLSessionDataDelegate , @unchecked Sendable {
15+
16+ private var session : URLSession ?
17+ private var sessionDataTask : URLSessionDataTask ?
1518
1619 /// The lock that provides manual synchronization around access to authorization tokens.
1720 private static let lock : NSLock = . init( )
@@ -22,6 +25,18 @@ extension OAuth {
2225 set { lock. withLock { _authorizations = newValue } }
2326 }
2427
28+ /// Common Initializer.
29+ /// - Parameters:
30+ /// - request: the url requesy
31+ /// - cachedResponse: the cached response
32+ /// - client: the client
33+ override public init ( request: URLRequest , cachedResponse: CachedURLResponse ? , client: ( any URLProtocolClient ) ? ) {
34+ super. init ( request: request, cachedResponse: cachedResponse, client: client)
35+ if session == nil {
36+ session = . init( configuration: . default, delegate: self , delegateQueue: nil )
37+ }
38+ }
39+
2540 /// Adds an authorization for the given provider that can be used inject `Authorization: Bearer <<token>>` headers into a request.
2641 /// - Parameters:
2742 /// - authorization: the authorization issued by the provider
@@ -47,7 +62,7 @@ extension OAuth {
4762
4863 /// Determines whether this protocol can handle the given request.
4964 /// - Parameter request: the request to handle
50- /// - Returns: always true
65+ /// - Returns: true if this protocl can handle the given request.
5166 override public class func canInit( with request: URLRequest ) -> Bool {
5267 // Remove any expired authorizations
5368 let expiredEntries = authorizations. filter { $0. value. isExpired }
@@ -64,6 +79,14 @@ extension OAuth {
6479 return false
6580 }
6681
82+ /// Determines whether this protocol can handle the given task.
83+ /// - Parameter task: the task to handle
84+ /// - Returns: true if this protocl can handle the given task.
85+ override public class func canInit( with task: URLSessionTask ) -> Bool {
86+ guard let request = task. originalRequest else { return false }
87+ return canInit ( with: request)
88+ }
89+
6790 /// If an authorized provider matches the given request, then this method returns a canonical version
6891 /// of the given request with an additional `Authorization: Bearer <<token>>` header field.
6992 /// - Parameter request: the request
@@ -80,6 +103,55 @@ extension OAuth {
80103 }
81104 return request
82105 }
106+
107+ /// Starts the loading of the current request.
108+ override public func startLoading( ) {
109+ sessionDataTask = session? . dataTask ( with: request)
110+ sessionDataTask? . resume ( )
111+ }
112+
113+ /// Stops the loading of the current request.
114+ override public func stopLoading( ) {
115+ sessionDataTask? . cancel ( )
116+ }
117+
118+ /// Called when data is available to consume.
119+ /// - Parameters:
120+ /// - session: the url session
121+ /// - dataTask: the data task
122+ /// - data: the data to consume
123+ public func urlSession( _ session: URLSession , dataTask: URLSessionDataTask , didReceive data: Data ) {
124+ guard let response = dataTask. response else { return }
125+ client? . urlProtocol ( self , didReceive: response, cacheStoragePolicy: . notAllowed)
126+ client? . urlProtocol ( self , didLoad: data)
127+ }
128+
129+ /// Called when task is done loading data.
130+ /// - Parameters:
131+ /// - session: the url session
132+ /// - task: the session task
133+ /// - error: any error that may have occurred
134+ public func urlSession( _ session: URLSession , task: URLSessionTask , didCompleteWithError error: ( any Error ) ? ) {
135+ if let error {
136+ client? . urlProtocol ( self , didFailWithError: error)
137+ } else {
138+ client? . urlProtocolDidFinishLoading ( self )
139+ }
140+ }
141+
142+ public func urlSession( _ session: URLSession , task: URLSessionTask , willPerformHTTPRedirection response: HTTPURLResponse , newRequest request: URLRequest , completionHandler: @escaping ( URLRequest ? ) -> Void ) {
143+ client? . urlProtocol ( self , wasRedirectedTo: request, redirectResponse: response)
144+ completionHandler ( request)
145+ }
146+
147+ public func urlSession( _ session: URLSession , didBecomeInvalidWithError error: ( any Error ) ? ) {
148+ guard let error = error else { return }
149+ client? . urlProtocol ( self , didFailWithError: error)
150+ }
151+
152+ public func urlSessionDidFinishEvents( forBackgroundURLSession session: URLSession ) {
153+ client? . urlProtocolDidFinishLoading ( self )
154+ }
83155 }
84156}
85157
0 commit comments