7
7
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
8
8
//
9
9
10
+ import CoreFoundation
11
+ import Dispatch
12
+
10
13
/*!
11
14
@header NSURLProtocol.h
12
15
@@ -142,6 +145,96 @@ public protocol URLProtocolClient : NSObjectProtocol {
142
145
func urlProtocol( _ protocol: URLProtocol , didCancel challenge: URLAuthenticationChallenge )
143
146
}
144
147
148
+ internal class _ProtocolClient : NSObject , URLProtocolClient {
149
+
150
+ func urlProtocol( _ protocol: URLProtocol , didReceive response: URLResponse , cacheStoragePolicy policy: URLCache . StoragePolicy ) {
151
+ `protocol`. task? . response = response
152
+ }
153
+
154
+ func urlProtocolDidFinishLoading( _ protocol: URLProtocol ) {
155
+ guard let task = `protocol`. task else { fatalError ( ) }
156
+ guard let session = task. session as? URLSession else { fatalError ( ) }
157
+ switch session. behaviour ( for: task) {
158
+ case . taskDelegate( let delegate) :
159
+ guard let s = session as? URLSession else { fatalError ( ) }
160
+ s. delegateQueue. addOperation {
161
+ delegate. urlSession ( s, task: task, didCompleteWithError: nil )
162
+ task. state = . completed
163
+ }
164
+ case . noDelegate:
165
+ task. state = . completed
166
+ case . dataCompletionHandler( let completion) :
167
+ let data = Data ( )
168
+ guard let client = `protocol`. client else { fatalError ( ) }
169
+ client. urlProtocol ( `protocol`, didLoad: data)
170
+ return
171
+ case . downloadCompletionHandler( let completion) :
172
+ guard let s = session as? URLSession else { fatalError ( ) }
173
+ s. delegateQueue. addOperation {
174
+ completion ( task. currentRequest? . url, task. response, nil )
175
+ task. state = . completed
176
+ }
177
+ }
178
+ }
179
+
180
+ func urlProtocol( _ protocol: URLProtocol , didCancel challenge: URLAuthenticationChallenge ) {
181
+ NSUnimplemented ( )
182
+ }
183
+
184
+ func urlProtocol( _ protocol: URLProtocol , didReceive challenge: URLAuthenticationChallenge ) {
185
+ NSUnimplemented ( )
186
+ }
187
+
188
+ func urlProtocol( _ protocol: URLProtocol , didLoad data: Data ) {
189
+ guard let task = `protocol`. task else { fatalError ( ) }
190
+ guard let session = task. session as? URLSession else { fatalError ( ) }
191
+ switch session. behaviour ( for: task) {
192
+ case . dataCompletionHandler( let completion) :
193
+ guard let s = task. session as? URLSession else { fatalError ( ) }
194
+ s. delegateQueue. addOperation {
195
+ completion ( data, task. response, nil )
196
+ task. state = . completed
197
+ }
198
+ default : return
199
+ }
200
+ }
201
+
202
+ func urlProtocol( _ protocol: URLProtocol , didFailWithError error: Error ) {
203
+ guard let task = `protocol`. task else { fatalError ( ) }
204
+ guard let session = task. session as? URLSession else { fatalError ( ) }
205
+ switch session. behaviour ( for: task) {
206
+ case . taskDelegate( let delegate) :
207
+ guard let s = session as? URLSession else { fatalError ( ) }
208
+ s. delegateQueue. addOperation {
209
+ delegate. urlSession ( s, task: task, didCompleteWithError: error as Error )
210
+ task. state = . completed
211
+ }
212
+ case . noDelegate:
213
+ task. state = . completed
214
+ case . dataCompletionHandler( let completion) :
215
+ guard let s = session as? URLSession else { fatalError ( ) }
216
+ s. delegateQueue. addOperation {
217
+ completion ( nil , nil , error)
218
+ task. state = . completed
219
+ }
220
+ case . downloadCompletionHandler( let completion) :
221
+ guard let s = session as? URLSession else { fatalError ( ) }
222
+ s. delegateQueue. addOperation {
223
+ completion ( nil , nil , error)
224
+ task. state = . completed
225
+ }
226
+ }
227
+ }
228
+
229
+ func urlProtocol( _ protocol: URLProtocol , cachedResponseIsValid cachedResponse: CachedURLResponse ) {
230
+ NSUnimplemented ( )
231
+ }
232
+
233
+ func urlProtocol( _ protocol: URLProtocol , wasRedirectedTo request: URLRequest , redirectResponse: URLResponse ) {
234
+ NSUnimplemented ( )
235
+ }
236
+ }
237
+
145
238
/*!
146
239
@class NSURLProtocol
147
240
@@ -151,7 +244,9 @@ public protocol URLProtocolClient : NSObjectProtocol {
151
244
or more protocols or URL schemes.
152
245
*/
153
246
open class URLProtocol : NSObject {
154
-
247
+
248
+ private static var _registeredProtocolClasses = [ AnyClass] ( )
249
+ private static var _classesLock = NSLock ( )
155
250
/*!
156
251
@method initWithRequest:cachedResponse:client:
157
252
@abstract Initializes an NSURLProtocol given request,
@@ -165,28 +260,43 @@ open class URLProtocol : NSObject {
165
260
interface the protocol implementation can use to report results back
166
261
to the URL loading system.
167
262
*/
168
- public init ( request: URLRequest , cachedResponse: CachedURLResponse ? , client: URLProtocolClient ? ) { NSUnimplemented ( ) }
169
-
263
+ public required init ( request: URLRequest , cachedResponse: CachedURLResponse ? , client: URLProtocolClient ? ) {
264
+ self . _request = request
265
+ self . _cachedResponse = cachedResponse
266
+ self . _client = client ?? _ProtocolClient ( )
267
+ }
268
+
269
+ private var _request : URLRequest
270
+ private var _cachedResponse : CachedURLResponse ?
271
+ private var _client : URLProtocolClient ?
272
+
170
273
/*!
171
274
@method client
172
275
@abstract Returns the NSURLProtocolClient of the receiver.
173
276
@result The NSURLProtocolClient of the receiver.
174
277
*/
175
- open var client : URLProtocolClient ? { NSUnimplemented ( ) }
278
+ open var client : URLProtocolClient ? {
279
+ set { self . _client = newValue }
280
+ get { return self . _client }
281
+ }
176
282
177
283
/*!
178
284
@method request
179
285
@abstract Returns the NSURLRequest of the receiver.
180
286
@result The NSURLRequest of the receiver.
181
287
*/
182
- /*@NSCopying*/ open var request : URLRequest { NSUnimplemented ( ) }
288
+ /*@NSCopying*/ open var request : URLRequest {
289
+ return _request
290
+ }
183
291
184
292
/*!
185
293
@method cachedResponse
186
294
@abstract Returns the NSCachedURLResponse of the receiver.
187
295
@result The NSCachedURLResponse of the receiver.
188
296
*/
189
- /*@NSCopying*/ open var cachedResponse : CachedURLResponse ? { NSUnimplemented ( ) }
297
+ /*@NSCopying*/ open var cachedResponse : CachedURLResponse ? {
298
+ return _cachedResponse
299
+ }
190
300
191
301
/*======================================================================
192
302
Begin responsibilities for protocol implementors
@@ -207,7 +317,9 @@ open class URLProtocol : NSObject {
207
317
@param request A request to inspect.
208
318
@result YES if the protocol can handle the given request, NO if not.
209
319
*/
210
- open class func canInit( with request: URLRequest ) -> Bool { NSUnimplemented ( ) }
320
+ open class func canInit( with request: URLRequest ) -> Bool {
321
+ NSRequiresConcreteImplementation ( )
322
+ }
211
323
212
324
/*!
213
325
@method canonicalRequestForRequest:
@@ -246,7 +358,9 @@ open class URLProtocol : NSObject {
246
358
@discussion When this method is called, the protocol implementation
247
359
should start loading a request.
248
360
*/
249
- open func startLoading( ) { NSUnimplemented ( ) }
361
+ open func startLoading( ) {
362
+ NSRequiresConcreteImplementation ( )
363
+ }
250
364
251
365
/*!
252
366
@method stopLoading
@@ -256,7 +370,9 @@ open class URLProtocol : NSObject {
256
370
to a cancel operation, so protocol implementations must be able to
257
371
handle this call while a load is in progress.
258
372
*/
259
- open func stopLoading( ) { NSUnimplemented ( ) }
373
+ open func stopLoading( ) {
374
+ NSRequiresConcreteImplementation ( )
375
+ }
260
376
261
377
/*======================================================================
262
378
End responsibilities for protocol implementors
@@ -323,19 +439,65 @@ open class URLProtocol : NSObject {
323
439
The only way that failure can occur is if the given class is not a
324
440
subclass of NSURLProtocol.
325
441
*/
326
- open class func registerClass( _ protocolClass: AnyClass ) -> Bool { NSUnimplemented ( ) }
327
-
442
+ open class func registerClass( _ protocolClass: AnyClass ) -> Bool {
443
+ if protocolClass is URLProtocol . Type {
444
+ _classesLock. lock ( )
445
+ guard !_registeredProtocolClasses. contains ( where: { $0 === protocolClass } ) else {
446
+ _classesLock. unlock ( )
447
+ return true
448
+ }
449
+ _registeredProtocolClasses. append ( protocolClass)
450
+ _classesLock. unlock ( )
451
+ return true
452
+ }
453
+ return false
454
+ }
455
+
456
+ internal class func getProtocolClass( protocols: [ AnyClass ] , request: URLRequest ) -> AnyClass ? {
457
+ // Registered protocols are consulted in reverse order.
458
+ // This behaviour makes the latest registered protocol to be consulted first
459
+ _classesLock. lock ( )
460
+ let protocolClasses = protocols
461
+ for protocolClass in protocolClasses {
462
+ let urlProtocolClass : AnyClass = protocolClass
463
+ guard let urlProtocol = urlProtocolClass as? URLProtocol . Type else { fatalError ( ) }
464
+ if urlProtocol. canInit ( with: request) {
465
+ _classesLock. unlock ( )
466
+ return urlProtocol
467
+ }
468
+ }
469
+ _classesLock. unlock ( )
470
+ return nil
471
+ }
472
+
473
+ internal class func getProtocols( ) -> [ AnyClass ] ? {
474
+ return _registeredProtocolClasses
475
+ }
328
476
/*!
329
477
@method unregisterClass:
330
478
@abstract This method unregisters a protocol.
331
479
@discussion After unregistration, a protocol class is no longer
332
480
consulted in calls to NSURLProtocol class methods.
333
481
@param protocolClass The class to unregister.
334
482
*/
335
- open class func unregisterClass( _ protocolClass: AnyClass ) { NSUnimplemented ( ) }
483
+ open class func unregisterClass( _ protocolClass: AnyClass ) {
484
+ _classesLock. lock ( )
485
+ if let idx = _registeredProtocolClasses. index ( where: { $0 === protocolClass } ) {
486
+ _registeredProtocolClasses. remove ( at: idx)
487
+ }
488
+ _classesLock. unlock ( )
489
+ }
336
490
337
491
open class func canInit( with task: URLSessionTask ) -> Bool { NSUnimplemented ( ) }
338
- public convenience init ( task: URLSessionTask , cachedResponse: CachedURLResponse ? , client: URLProtocolClient ? ) { NSUnimplemented ( ) }
339
- /*@NSCopying*/ open var task : URLSessionTask ? { NSUnimplemented ( ) }
340
- }
492
+ public required convenience init ( task: URLSessionTask , cachedResponse: CachedURLResponse ? , client: URLProtocolClient ? ) {
493
+ let urlRequest = task. originalRequest
494
+ self . init ( request: urlRequest!, cachedResponse: cachedResponse, client: client)
495
+ self . task = task
496
+ }
497
+ /*@NSCopying*/ open var task : URLSessionTask ? {
498
+ set { self . _task = newValue }
499
+ get { return self . _task }
500
+ }
341
501
502
+ private var _task : URLSessionTask ? = nil
503
+ }
0 commit comments