Skip to content

Commit

Permalink
use Cache-Control en Pragma
Browse files Browse the repository at this point in the history
  • Loading branch information
evermeer committed Aug 23, 2016
1 parent 8a406e3 commit ad3e55e
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 9 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 = "2.9.0"
s.version = "2.10.0"
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
36 changes: 28 additions & 8 deletions EVURLCache/Pod/EVURLCache.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ import Foundation
public class EVURLCache: NSURLCache {

public static var URLCACHE_CACHE_KEY = "MobileAppCacheKey" // Add this header variable to the response if you want to save the response using this key as the filename.
public static var URLCACHE_EXPIRATION_AGE_KEY = "MobileAppExpirationAgeKey" // Add this header variable to the response to set the expiration age.
public static var MAX_AGE = "604800000" // The default maximum age of a cached file in miliseconds. (1 week)
public static var MAX_AGE = "604800" // The default maximum age of a cached file in seconds. (1 week)
public static var PRE_CACHE_FOLDER = "PreCache" // The folder in your app with the prefilled cache content
public static var CACHE_FOLDER = "Cache" // The folder in the Documents folder where cached files will be saved
public static var MAX_FILE_SIZE = 24 // The maximum file size that will be cached (2^24 = 16MB)
Expand Down Expand Up @@ -93,8 +92,8 @@ public class EVURLCache: NSURLCache {
// Check file status only if we have network, otherwise return it anyway.
if EVURLCache.networkAvailable() {
if cacheItemExpired(request, storagePath: storagePath) {
let maxAge: String = request.valueForHTTPHeaderField(EVURLCache.URLCACHE_EXPIRATION_AGE_KEY) ?? EVURLCache.MAX_AGE
EVURLCache.debugLog("CACHE item older than \(maxAge) maxAgeHours")
let maxAge: String = request.valueForHTTPHeaderField("Access-Control-Max-Age") ?? EVURLCache.MAX_AGE
EVURLCache.debugLog("CACHE item older than \(maxAge) seconds")
return nil
}
}
Expand Down Expand Up @@ -129,15 +128,36 @@ public class EVURLCache: NSURLCache {
}
}

// check if caching is allowed
var shouldSkipCache: String? = nil

// check if caching is allowed according to the request
if request.cachePolicy == NSURLRequestCachePolicy.ReloadIgnoringCacheData {
shouldSkipCache = "request cache policy"
}

// check if caching is allowed according to the response Cache-Control or Pragma header
if let httpResponse = cachedResponse.response as? NSHTTPURLResponse {
if let cacheControl = httpResponse.allHeaderFields["Cache-Control"] as? String {
if cacheControl.lowercaseString.containsString("no-cache") || cacheControl.lowercaseString.containsString("no-store") {
shouldSkipCache = "response cache control"
}
}

if let cacheControl = httpResponse.allHeaderFields["Pragma"] as? String {
if cacheControl.lowercaseString.containsString("no-cache") {
shouldSkipCache = "response pragma"
}
}
}

if shouldSkipCache != nil {
// If the file is in the PreCache folder, then we do want to save a copy in case we are without internet connection
let storagePath = EVURLCache.storagePathForRequest(request, rootPath: EVURLCache._preCacheDirectory) ?? ""
if !NSFileManager.defaultManager().fileExistsAtPath(storagePath) {
EVURLCache.debugLog("CACHE not storing file, it's not allowed by the cachePolicy : \(request.URL)")
EVURLCache.debugLog("CACHE not storing file, it's not allowed by the \(shouldSkipCache) : \(request.URL)")
return
}
EVURLCache.debugLog("CACHE file in PreCache folder, overriding cachePolicy : \(request.URL)")
EVURLCache.debugLog("CACHE file in PreCache folder, overriding \(shouldSkipCache) : \(request.URL)")
}

// create storrage folder
Expand Down Expand Up @@ -176,7 +196,7 @@ public class EVURLCache: NSURLCache {

private func cacheItemExpired(request: NSURLRequest, storagePath: String) -> Bool {
// Max cache age for request
let maxAge: String = request.valueForHTTPHeaderField(EVURLCache.URLCACHE_EXPIRATION_AGE_KEY) ?? EVURLCache.MAX_AGE
let maxAge: String = request.valueForHTTPHeaderField("Access-Control-Max-Age") ?? EVURLCache.MAX_AGE

do {
let attributes = try NSFileManager.defaultManager().attributesOfItemAtPath(storagePath)
Expand Down
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,22 @@ Since (most likely, see limitations) all files will be cached, you do not have t
You can do a NSURLRequest and then in the connectionDidFinishLoading you can use the file from
the cache. You can get the full path of that file by calling: EVURLCache.storagePathForRequest(theRequest)

## Controlling the cache

EVURLCache respects the HTTP header variables 'Cache-Control' and 'Pragma' when these contain 'no-cache' or 'no-store' then the response will not be written to the cache. You do have to be aware that if the file is already in the cache because you have put it in the PreCache folder yourself or the file was previously fetched with different header variables, the file will be written to the cache in order to update it's contents and the HTTP header varialbes will be ignored.

EVURLCache will also take into account the HTTP header variable 'Access-Control-Max-Age' when reading from the cache. When the content is older it will try to fetch it again.

Caching is done based on the complete URL including the querystring parameters. If for some reason you want multiple URL's to be stored and fetched as the same cache item, then you can add the HTTP header variable (server side) MobileAppCacheKey

Most webservers interpit url's' case insesnsitive. Since iOS and OSX (not always) have a case sensitive file system it could be that a URL is requested that do not have a case sensitive match on the file system. By default EVURLCache stores all files while converting the path to lowercase. If you do want a case sensitive match, then you could set the EVURLCache.FORCE_LOWERCASE to false

You can influence the maximum file size that will be cached by EVURLCache. This is a setting that is handled by the NSURLCache base class. By default it's set to 16MB. You can influence this by setting the EVURLCache.MAX_FILE_SIZE. It's set as number of bits. So setting it to 24 will mean a cache size of 2^24 = 16MB

You can influence the maximum total size that will be cached by EVURLCache. This is a setting that is handled by the NSURLCache base class. By default it's set to 256MB. You can influence this by setting the EVURLCache.MAX_CACHE_SIZE It's set as number of bits. So setting it to 30 will mean a cache size of 2^30 = 256MB. Make sure it's at least 16 times larger than the Maximum file size or the maximum file size will not be used

If you want to see what EVURLCache is doing, then set EVURLCache.LOGGING to true

## See the demo in action

Follow these steps to see the demo app in action. Logging is enabled, so watch the output window to see what's happening.
Expand Down

0 comments on commit ad3e55e

Please sign in to comment.