Skip to content

Commit

Permalink
fix optional in url
Browse files Browse the repository at this point in the history
  • Loading branch information
evermeer committed Mar 10, 2017
1 parent 58399c4 commit daafbde
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 10 deletions.
2 changes: 1 addition & 1 deletion EVURLCache.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Pod::Spec.new do |s|
#

s.name = "EVURLCache"
s.version = "3.2.0"
s.version = "3.2.1"
s.summary = "NSURLCache subclass for handeling all web requests that use NSURLRequest"
s.description = "This is a NSURLCache subclass for handeling all web requests that use NSURLRequest. (This includes UIWebView)"
s.homepage = "https://github.com/evermeer/EVURLCache"
Expand Down
4 changes: 4 additions & 0 deletions EVURLCache.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
objects = {

/* Begin PBXBuildFile section */
7F06B2451E38C6FF00925047 /* EVURLProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F06B2441E38C6FF00925047 /* EVURLProtocol.swift */; };
7F4A0D4F1BEE481400059923 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F4A0D4E1BEE481400059923 /* AppDelegate.swift */; };
7F4A0D511BEE481400059923 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F4A0D501BEE481400059923 /* ViewController.swift */; };
7F4A0D541BEE481400059923 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7F4A0D521BEE481400059923 /* Main.storyboard */; };
Expand All @@ -28,6 +29,7 @@
05EE26FC72733C70FFA7F10C /* Pods.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods.framework; sourceTree = BUILT_PRODUCTS_DIR; };
144C37334311C3DEAAAE46C3 /* Pods-OSXcompileTest.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OSXcompileTest.release.xcconfig"; path = "Pods/Target Support Files/Pods-OSXcompileTest/Pods-OSXcompileTest.release.xcconfig"; sourceTree = "<group>"; };
7566676951737F7DE11E9363 /* Pods_EVURLCache.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_EVURLCache.framework; sourceTree = BUILT_PRODUCTS_DIR; };
7F06B2441E38C6FF00925047 /* EVURLProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = EVURLProtocol.swift; path = Pod/EVURLProtocol.swift; sourceTree = "<group>"; };
7F4A0D4B1BEE481400059923 /* EVURLCache.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = EVURLCache.app; sourceTree = BUILT_PRODUCTS_DIR; };
7F4A0D4E1BEE481400059923 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7F4A0D501BEE481400059923 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -144,6 +146,7 @@
children = (
7F4A0D611BEE497100059923 /* EVURLCache.swift */,
7FFF79271CCD0A6A0085E6E4 /* Reachability.swift */,
7F06B2441E38C6FF00925047 /* EVURLProtocol.swift */,
);
name = Pod;
sourceTree = "<group>";
Expand Down Expand Up @@ -361,6 +364,7 @@
buildActionMask = 2147483647;
files = (
7F4A0D511BEE481400059923 /* ViewController.swift in Sources */,
7F06B2451E38C6FF00925047 /* EVURLProtocol.swift in Sources */,
7F4A0D621BEE497100059923 /* EVURLCache.swift in Sources */,
7FFF79281CCD0A6A0085E6E4 /* Reachability.swift in Sources */,
7F4A0D4F1BEE481400059923 /* AppDelegate.swift in Sources */,
Expand Down
2 changes: 1 addition & 1 deletion EVURLCache/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
}
return true
}

// Now activate this cache
EVURLCache.activate()
NSLog("Cache is now active")
Expand Down
44 changes: 39 additions & 5 deletions EVURLCache/Pod/EVURLCache.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ open class EVURLCache: URLCache {
let urlCache = EVURLCache(memoryCapacity: 1<<MAX_FILE_SIZE, diskCapacity: 1<<MAX_CACHE_SIZE, diskPath: _cacheDirectory)

URLCache.shared = urlCache
URLProtocol.registerClass(EVURLProtocol.self)

}

open class func filter (_ filterFor: @escaping ((_ request: URLRequest) -> Bool)) {
Expand All @@ -76,9 +78,24 @@ open class EVURLCache: URLCache {
print("\(dateFormatter.string(from: Date())) \(process.processName))[\(process.processIdentifier):\(threadId)] \((filename as NSString).lastPathComponent)(\(line)) \(funcname):\r\t\(object)\n")
}
}

open static func shouldRedirect(request: URLRequest) -> URL? {
if let cache = EVURLCache.cachedResponse(for: request) {
if (cache.response as? HTTPURLResponse)?.statusCode == 302 {
let headerFiels: [String:String] = (cache.response as? HTTPURLResponse)?.allHeaderFields as! [String : String]
let redirectTo = headerFiels["Location"] ?? ""
return URL(string: redirectTo)
}
}
return nil
}

// Will be called by a NSURLConnection when it's wants to know if there is something in the cache.
open override func cachedResponse(for request: URLRequest) -> CachedURLResponse? {
return EVURLCache.cachedResponse(for: request)
}

open static func cachedResponse(for request: URLRequest) -> CachedURLResponse? {
guard let url = request.url else {
EVURLCache.debugLog("CACHE not allowed for nil URLs")
return nil
Expand All @@ -88,7 +105,7 @@ open class EVURLCache: URLCache {
EVURLCache.debugLog("CACHE not allowed for empty URLs")
return nil
}

if !EVURLCache._filter(request) {
EVURLCache.debugLog("CACHE skipped because of filter")
return nil
Expand All @@ -100,6 +117,7 @@ open class EVURLCache: URLCache {
return nil
}

// Check if there is a cache for this request
let storagePath = EVURLCache.storagePathForRequest(request, rootPath: EVURLCache._cacheDirectory) ?? ""
if !FileManager.default.fileExists(atPath: storagePath) {
EVURLCache.debugLog("PRECACHE not found \(storagePath)")
Expand All @@ -116,6 +134,7 @@ open class EVURLCache: URLCache {
let maxAge: String = request.value(forHTTPHeaderField: "Access-Control-Max-Age") ?? EVURLCache.MAX_AGE
EVURLCache.debugLog("CACHE item older than \(maxAge) seconds")
return nil

}
}

Expand All @@ -126,6 +145,21 @@ open class EVURLCache: URLCache {
// I have to find out the difrence. For now I will let the developer checkt which version to use
if EVURLCache.RECREATE_CACHE_RESPONSE {
// This works for most sites, but aperently not for the game as in the alternate url you see in ViewController
if (response.response as? HTTPURLResponse)?.statusCode == 302 {

let headerFiels: [String:String] = (response.response as? HTTPURLResponse)?.allHeaderFields as! [String : String]
let redirectTo = headerFiels["Location"] ?? ""
print("Redirecting from: \(response.response.url?.absoluteString ?? "")\nto: \(redirectTo)")

// returning the actual redirect response
// let r = URLResponse(url: URL(string: redirectTo)!, mimeType: response.response.mimeType, expectedContentLength: response.data.count, textEncodingName: response.response.textEncodingName)
// return CachedURLResponse(response: r, data: response.data, userInfo: response.userInfo, storagePolicy: .allowed)

// returning the response of the redirected url
let redirectRequest = URLRequest(url: URL(string: redirectTo)!, cachePolicy: request.cachePolicy, timeoutInterval: request.timeoutInterval)
return self.cachedResponse(for: redirectRequest)
}

let r = URLResponse(url: response.response.url!, mimeType: response.response.mimeType, expectedContentLength: response.data.count, textEncodingName: response.response.textEncodingName)
return CachedURLResponse(response: r, data: response.data, userInfo: response.userInfo, storagePolicy: .allowed)
}
Expand Down Expand Up @@ -197,7 +231,7 @@ open class EVURLCache: URLCache {
}

if let previousResponse = NSKeyedUnarchiver.unarchiveObject(withFile: storagePath) as? CachedURLResponse {
if previousResponse.data == cachedResponse.data && !cacheItemExpired(request, storagePath: storagePath) {
if previousResponse.data == cachedResponse.data && !EVURLCache.cacheItemExpired(request, storagePath: storagePath) {
EVURLCache.debugLog("CACHE not rewriting stored file")
return
}
Expand All @@ -216,7 +250,7 @@ open class EVURLCache: URLCache {
}
}

fileprivate func cacheItemExpired(_ request: URLRequest, storagePath: String) -> Bool {
fileprivate static func cacheItemExpired(_ request: URLRequest, storagePath: String) -> Bool {
// Max cache age for request
let maxAge: String = request.value(forHTTPHeaderField: "Access-Control-Max-Age") ?? EVURLCache.MAX_AGE

Expand Down Expand Up @@ -273,7 +307,7 @@ open class EVURLCache: URLCache {

// build up the complete storrage path for a request plus root folder.
open static func storagePathForRequest(_ request: URLRequest, rootPath: String) -> String? {
var localUrl: String!
var localUrl: String = ""
let host: String = request.url?.host ?? "default"

let urlString = request.url?.absoluteString ?? ""
Expand All @@ -285,7 +319,7 @@ open class EVURLCache: URLCache {
if let cacheKey = request.value(forHTTPHeaderField: URLCACHE_CACHE_KEY) {
localUrl = "\(host)/\(cacheKey)"
} else {
if let path = request.url?.path {
if let path: String = request.url?.path {
localUrl = "\(host)\(path)"
} else {
NSLog("WARNING: Unable to get the path from the request: \(request)")
Expand Down
87 changes: 87 additions & 0 deletions EVURLCache/Pod/EVURLProtocol.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
//
// EVURLProtocol.swift
// EVURLCache
//
// Created by Edwin Vermeer on 25/1/17.
// Copyright © 2017 evict. All rights reserved.
//

import Foundation

/// The intercepting URL protocol.
internal final class EVURLProtocol: URLProtocol, URLSessionTaskDelegate, URLSessionDataDelegate {

/// Internal session object used to perform the request.
private var internalSession: URLSession!

/// Internal session data dark responsible for request execution.
private var internalTask: URLSessionDataTask!

/// Internal task response storage.
private var internalResponse: HTTPURLResponse?

/// Internal response data storage.
private lazy var internalResponseData = NSMutableData()


// MARK: NSURLProtocol

internal override init(request: URLRequest, cachedResponse: CachedURLResponse?, client: URLProtocolClient?) {
super.init(request: request, cachedResponse: cachedResponse, client: client)
internalSession = URLSession(configuration: URLSessionConfiguration.default, delegate: self, delegateQueue: nil)
internalTask = internalSession.dataTask(with: request)
}

internal override static func canInit(with request: URLRequest) -> Bool {
return true
}

internal override static func canonicalRequest(for request: URLRequest) -> URLRequest {
return request
}

internal override func startLoading() {
internalTask.resume()
}

internal override func stopLoading() {
internalSession.invalidateAndCancel()
}


// MARK: NSURLSessionTaskDelegate

internal func urlSession(_ session: URLSession, task: URLSessionTask, willPerformHTTPRedirection response: HTTPURLResponse, newRequest request: URLRequest, completionHandler: @escaping (URLRequest?) -> Void) {
let from = response.url
let to = request.url
print("====> Was redirected\n\tFrom: \(from?.absoluteString ?? "")\n\tTo: \(to?.absoluteString ?? "")")
let cacheResponse = CachedURLResponse(response: response, data: Data())
let originalRequest = URLRequest(url: from!, cachePolicy: request.cachePolicy, timeoutInterval: request.timeoutInterval)
EVURLCache.shared.storeCachedResponse(cacheResponse, for: originalRequest)
client?.urlProtocol(self, wasRedirectedTo: request, redirectResponse: response)
}

internal func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
if let error = error {
client?.urlProtocol(self, didFailWithError: error)
} else if let _ = internalResponse {
client?.urlProtocolDidFinishLoading(self)
}
internalSession.finishTasksAndInvalidate()
}


// MARK: NSURLSessionDataDelegate

internal func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) {
internalResponse = response as? HTTPURLResponse
completionHandler(.allow)
client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .allowed)
}

internal func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
internalResponseData.append(data as Data)
client?.urlProtocol(self, didLoad: data as Data)
}

}
15 changes: 12 additions & 3 deletions EVURLCache/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,28 @@

import UIKit

class ViewController: UIViewController {
class ViewController: UIViewController, UIWebViewDelegate {

@IBOutlet weak var webView: UIWebView!

override func viewDidLoad() {
super.viewDidLoad()
webView.delegate = self
//EVURLCache.RECREATE_CACHE_RESPONSE = false // This flag is only used for debuging the small difference between recreating a response and unarchiving a response. Recreating (which is the default) seems to be working best...
if let url = URL(string: "http://evict.nl") {
if let url = URL(string: "http://www.newser.com/story/229485/aetna-doing-something-about-workers-student-loans.html") {
NSLog("navigating to \(url)")
webView.loadRequest(URLRequest(url: url))
webView.loadRequest(URLRequest(url: url))
}
}

func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool {
if let redirectURL = EVURLCache.shouldRedirect(request: request) {
let r = URLRequest(url: redirectURL)
webView.loadRequest(r)
return false
}
return true
}


// Other test url's that were used to debug specific situations
Expand Down

0 comments on commit daafbde

Please sign in to comment.