1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
| import Foundation
@objc open class NFXProtocol: URLProtocol { private static let nfxInternalKey = "com.netfox.NFXInternal" private lazy var session: URLSession = { [unowned self] in return URLSession(configuration: .default, delegate: self, delegateQueue: nil) }() private let model = NFXHTTPModel() private var response: URLResponse? private var responseData: NSMutableData? override open class func canInit(with request: URLRequest) -> Bool { return canServeRequest(request) } override open class func canInit(with task: URLSessionTask) -> Bool { guard let request = task.currentRequest else { return false } return canServeRequest(request) } private class func canServeRequest(_ request: URLRequest) -> Bool { guard NFX.sharedInstance().isEnabled() else { return false } guard URLProtocol.property(forKey: NFXProtocol.nfxInternalKey, in: request) == nil, let url = request.url, (url.absoluteString.hasPrefix("http") || url.absoluteString.hasPrefix("https")) else { return false } let absoluteString = url.absoluteString guard !NFX.sharedInstance().getIgnoredURLs().contains(where: { absoluteString.hasPrefix($0) }) else { return false } return true } override open func startLoading() { model.saveRequest(request) let mutableRequest = (request as NSURLRequest).mutableCopy() as! NSMutableURLRequest URLProtocol.setProperty(true, forKey: NFXProtocol.nfxInternalKey, in: mutableRequest) session.dataTask(with: mutableRequest as URLRequest).resume() } override open func stopLoading() { session.getTasksWithCompletionHandler { dataTasks, _, _ in dataTasks.forEach { $0.cancel() } } } override open class func canonicalRequest(for request: URLRequest) -> URLRequest { return request } }
extension NFXProtocol: URLSessionDataDelegate { public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) { responseData?.append(data) client?.urlProtocol(self, didLoad: data) } public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) { self.response = response self.responseData = NSMutableData() client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: NFX.swiftSharedInstance.cacheStoragePolicy) completionHandler(.allow) } public func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { defer { if let error = error { client?.urlProtocol(self, didFailWithError: error) } else { client?.urlProtocolDidFinishLoading(self) } } guard let request = task.originalRequest else { return } model.saveRequestBody(request) model.logRequest(request) if error != nil { model.saveErrorResponse() } else if let response = response { let data = (responseData ?? NSMutableData()) as Data model.saveResponse(response, data: data) } NFXHTTPModelManager.sharedInstance.add(model) NotificationCenter.default.post(name: .NFXReloadData, object: nil) } public func urlSession(_ session: URLSession, task: URLSessionTask, willPerformHTTPRedirection response: HTTPURLResponse, newRequest request: URLRequest, completionHandler: @escaping (URLRequest?) -> Void) { let updatedRequest: URLRequest if URLProtocol.property(forKey: NFXProtocol.nfxInternalKey, in: request) != nil { let mutableRequest = (request as NSURLRequest).mutableCopy() as! NSMutableURLRequest URLProtocol.removeProperty(forKey: NFXProtocol.nfxInternalKey, in: mutableRequest) updatedRequest = mutableRequest as URLRequest } else { updatedRequest = request } client?.urlProtocol(self, wasRedirectedTo: updatedRequest, redirectResponse: response) completionHandler(updatedRequest) } public func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { let wrappedChallenge = URLAuthenticationChallenge(authenticationChallenge: challenge, sender: NFXAuthenticationChallengeSender(handler: completionHandler)) client?.urlProtocol(self, didReceive: wrappedChallenge) } #if !os(OSX) public func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) { client?.urlProtocolDidFinishLoading(self) } #endif
|