Ben Copsey

ASIDownloadCache now stores files with extensions for common web scripting langu…

…ages with a .html extension
This will help users that need to cache HTML content for display in a webview
closes gh-241
@@ -35,6 +35,10 @@ @@ -35,6 +35,10 @@
35 // A helper function that determines if the server has requested data should not be cached by looking at the request's response headers 35 // A helper function that determines if the server has requested data should not be cached by looking at the request's response headers
36 + (BOOL)serverAllowsResponseCachingForRequest:(ASIHTTPRequest *)request; 36 + (BOOL)serverAllowsResponseCachingForRequest:(ASIHTTPRequest *)request;
37 37
  38 +// A list of file extensions that we know won't be readable by a webview when accessed locally
  39 +// If we're asking for a path to cache a particular url and it has one of these extensions, we change it to '.html'
  40 ++ (NSArray *)fileExtensionsToHandleAsHTML;
  41 +
38 @property (assign, nonatomic) ASICachePolicy defaultCachePolicy; 42 @property (assign, nonatomic) ASICachePolicy defaultCachePolicy;
39 @property (retain, nonatomic) NSString *storagePath; 43 @property (retain, nonatomic) NSString *storagePath;
40 @property (retain) NSRecursiveLock *accessLock; 44 @property (retain) NSRecursiveLock *accessLock;
@@ -14,6 +14,7 @@ static ASIDownloadCache *sharedCache = nil; @@ -14,6 +14,7 @@ static ASIDownloadCache *sharedCache = nil;
14 14
15 static NSString *sessionCacheFolder = @"SessionStore"; 15 static NSString *sessionCacheFolder = @"SessionStore";
16 static NSString *permanentCacheFolder = @"PermanentStore"; 16 static NSString *permanentCacheFolder = @"PermanentStore";
  17 +static NSArray *fileExtensionsToHandleAsHTML = nil;
17 18
18 @interface ASIDownloadCache () 19 @interface ASIDownloadCache ()
19 + (NSString *)keyForURL:(NSURL *)url; 20 + (NSString *)keyForURL:(NSURL *)url;
@@ -22,6 +23,15 @@ static NSString *permanentCacheFolder = @"PermanentStore"; @@ -22,6 +23,15 @@ static NSString *permanentCacheFolder = @"PermanentStore";
22 23
23 @implementation ASIDownloadCache 24 @implementation ASIDownloadCache
24 25
  26 ++ (void)initialize
  27 +{
  28 + if (self == [ASIDownloadCache class]) {
  29 + // Obviously this is not an exhaustive list, but hopefully these are the most commonly used and this will 'just work' for the widest range of people
  30 + // I imagine many web developers probably use url rewriting anyway
  31 + fileExtensionsToHandleAsHTML = [[NSArray alloc] initWithObjects:@"asp",@"aspx",@"jsp",@"php",@"rb",@"py",@"pl",@"cgi", nil];
  32 + }
  33 +}
  34 +
25 - (id)init 35 - (id)init
26 { 36 {
27 self = [super init]; 37 self = [super init];
@@ -193,12 +203,21 @@ static NSString *permanentCacheFolder = @"PermanentStore"; @@ -193,12 +203,21 @@ static NSString *permanentCacheFolder = @"PermanentStore";
193 { 203 {
194 // Grab the file extension, if there is one. We do this so we can save the cached response with the same file extension - this is important if you want to display locally cached data in a web view 204 // Grab the file extension, if there is one. We do this so we can save the cached response with the same file extension - this is important if you want to display locally cached data in a web view
195 NSString *extension = [[url path] pathExtension]; 205 NSString *extension = [[url path] pathExtension];
196 - if (![extension length]) { 206 +
  207 + // If the url doesn't have an extension, we'll add one so a webview can read it when locally cached
  208 + // If the url has the extension of a common web scripting language, we'll change the extension on the cached path to html for the same reason
  209 + if (![extension length] || [[[self class] fileExtensionsToHandleAsHTML] containsObject:[extension lowercaseString]]) {
197 extension = @"html"; 210 extension = @"html";
198 } 211 }
199 return [self pathToFile:[[[self class] keyForURL:url] stringByAppendingPathExtension:extension]]; 212 return [self pathToFile:[[[self class] keyForURL:url] stringByAppendingPathExtension:extension]];
200 } 213 }
201 214
  215 ++ (NSArray *)fileExtensionsToHandleAsHTML
  216 +{
  217 + return fileExtensionsToHandleAsHTML;
  218 +}
  219 +
  220 +
202 - (NSString *)pathToCachedResponseHeadersForURL:(NSURL *)url 221 - (NSString *)pathToCachedResponseHeadersForURL:(NSURL *)url
203 { 222 {
204 return [self pathToFile:[[[self class] keyForURL:url] stringByAppendingPathExtension:@"cachedheaders"]]; 223 return [self pathToFile:[[[self class] keyForURL:url] stringByAppendingPathExtension:@"cachedheaders"]];
@@ -243,7 +262,10 @@ static NSString *permanentCacheFolder = @"PermanentStore"; @@ -243,7 +262,10 @@ static NSString *permanentCacheFolder = @"PermanentStore";
243 262
244 // Grab the file extension, if there is one. We do this so we can save the cached response with the same file extension - this is important if you want to display locally cached data in a web view 263 // Grab the file extension, if there is one. We do this so we can save the cached response with the same file extension - this is important if you want to display locally cached data in a web view
245 NSString *extension = [[[request url] path] pathExtension]; 264 NSString *extension = [[[request url] path] pathExtension];
246 - if (![extension length]) { 265 +
  266 + // If the url doesn't have an extension, we'll add one so a webview can read it when locally cached
  267 + // If the url has the extension of a common web scripting language, we'll change the extension on the cached path to html for the same reason
  268 + if (![extension length] || [[[self class] fileExtensionsToHandleAsHTML] containsObject:[extension lowercaseString]]) {
247 extension = @"html"; 269 extension = @"html";
248 } 270 }
249 path = [path stringByAppendingPathComponent:[[[self class] keyForURL:[request url]] stringByAppendingPathExtension:extension]]; 271 path = [path stringByAppendingPathComponent:[[[self class] keyForURL:[request url]] stringByAppendingPathExtension:extension]];
@@ -24,7 +24,7 @@ @@ -24,7 +24,7 @@
24 #import "ASIDataCompressor.h" 24 #import "ASIDataCompressor.h"
25 25
26 // Automatically set on build 26 // Automatically set on build
27 -NSString *ASIHTTPRequestVersion = @"v1.8.1-27 2011-08-07"; 27 +NSString *ASIHTTPRequestVersion = @"v1.8.1-28 2011-08-20";
28 28
29 static NSString *defaultUserAgent = nil; 29 static NSString *defaultUserAgent = nil;
30 30
@@ -4026,7 +4026,6 @@ static NSOperationQueue *sharedQueue = nil; @@ -4026,7 +4026,6 @@ static NSOperationQueue *sharedQueue = nil;
4026 } 4026 }
4027 4027
4028 #pragma mark NSCopying 4028 #pragma mark NSCopying
4029 -  
4030 - (id)copyWithZone:(NSZone *)zone 4029 - (id)copyWithZone:(NSZone *)zone
4031 { 4030 {
4032 // Don't forget - this will return a retained copy! 4031 // Don't forget - this will return a retained copy!
@@ -4420,6 +4419,7 @@ static NSOperationQueue *sharedQueue = nil; @@ -4420,6 +4419,7 @@ static NSOperationQueue *sharedQueue = nil;
4420 } 4419 }
4421 return [[defaultUserAgent retain] autorelease]; 4420 return [[defaultUserAgent retain] autorelease];
4422 } 4421 }
  4422 + return nil;
4423 } 4423 }
4424 4424
4425 + (void)setDefaultUserAgentString:(NSString *)agent 4425 + (void)setDefaultUserAgentString:(NSString *)agent
@@ -4690,6 +4690,7 @@ static NSOperationQueue *sharedQueue = nil; @@ -4690,6 +4690,7 @@ static NSOperationQueue *sharedQueue = nil;
4690 @synchronized(self) { 4690 @synchronized(self) {
4691 return [[defaultCache retain] autorelease]; 4691 return [[defaultCache retain] autorelease];
4692 } 4692 }
  4693 + return nil;
4693 } 4694 }
4694 4695
4695 4696
@@ -298,6 +298,30 @@ @@ -298,6 +298,30 @@
298 GHAssertTrue(success,@"Failed to use cached response"); 298 GHAssertTrue(success,@"Failed to use cached response");
299 } 299 }
300 300
  301 +- (void)testExtensionHandling
  302 +{
  303 + NSArray *extensions = [ASIDownloadCache fileExtensionsToHandleAsHTML];
  304 + for (NSString *extension in extensions) {
  305 + NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://allseeing-i.com/file.%@",extension]];
  306 + ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
  307 + NSString *path = [[ASIDownloadCache sharedCache] pathToStoreCachedResponseDataForRequest:request];
  308 + BOOL success = [[path pathExtension] isEqualToString:@"html"];
  309 + GHAssertTrue(success, @"Failed to use html extension on cached path for a resource we know a webview won't be able to open locally");
  310 + }
  311 +
  312 + NSURL *url = [NSURL URLWithString:@"http://allseeing-i.com/"];
  313 + ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
  314 + NSString *path = [[ASIDownloadCache sharedCache] pathToStoreCachedResponseDataForRequest:request];
  315 + BOOL success = [[path pathExtension] isEqualToString:@"html"];
  316 + GHAssertTrue(success, @"Failed to use html extension on cached path for a url without an extension");
  317 +
  318 + url = [NSURL URLWithString:@"http://allseeing-i.com/i/logo.png"];
  319 + request = [ASIHTTPRequest requestWithURL:url];
  320 + path = [[ASIDownloadCache sharedCache] pathToStoreCachedResponseDataForRequest:request];
  321 + success = [[path pathExtension] isEqualToString:@"png"];
  322 + GHAssertTrue(success, @"Failed to preserve file extension on cached path");
  323 +}
  324 +
301 - (void)testCustomExpiry 325 - (void)testCustomExpiry
302 { 326 {
303 [[ASIDownloadCache sharedCache] clearCachedResponsesForStoragePolicy:ASICacheForSessionDurationCacheStoragePolicy]; 327 [[ASIDownloadCache sharedCache] clearCachedResponsesForStoragePolicy:ASICacheForSessionDurationCacheStoragePolicy];