Ben Copsey

Cache fixes - compare headers when ASIReloadIfDifferentCachePolicy

Added starting point tests for ASIDownloadCache
//
// ASIDownloadCacheTests.h
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
//
// Created by Ben Copsey on 03/05/2010.
// Copyright 2010 All-Seeing Interactive. All rights reserved.
//
#import "ASITestCase.h"
@interface ASIDownloadCacheTests : ASITestCase {
}
@end
... ...
//
// ASIDownloadCacheTests.m
// Part of ASIHTTPRequest -> http://asi/ASIHTTPRequest
//
// Created by Ben Copsey on 03/05/2010.
// Copyright 2010 All-Seeing Interactive. All rights reserved.
//
#import "ASIDownloadCacheTests.h"
#import "ASIDownloadCache.h"
#import "ASIHTTPRequest.h"
@implementation ASIDownloadCacheTests
- (void)testDownloadCache
{
[[ASIDownloadCache sharedCache] clearCachedResponsesForStoragePolicy:ASICacheForSessionDurationCacheStoragePolicy];
[[ASIDownloadCache sharedCache] clearCachedResponsesForStoragePolicy:ASICachePermanentlyCacheStoragePolicy];
[[ASIDownloadCache sharedCache] setDefaultCachePolicy:ASIReloadIfDifferentCachePolicy];
// Ensure a request without a download cache does not pull from the cache
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://asi/ASIHTTPRequest/tests/cache-away"]];
[request startSynchronous];
BOOL success = ![request didUseCachedResponse];
GHAssertTrue(success,@"Used cached response when we shouldn't have");
// Check a request isn't setting didUseCachedResponse when the data is not in the cache
request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://asi/ASIHTTPRequest/tests/cache-away"]];
[request setDownloadCache:[ASIDownloadCache sharedCache]];
[request startSynchronous];
success = ![request didUseCachedResponse];
GHAssertTrue(success,@"Cached response should not have been available");
// Ensure the cache works
request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://asi/ASIHTTPRequest/tests/cache-away"]];
[request setDownloadCache:[ASIDownloadCache sharedCache]];
[request startSynchronous];
success = [request didUseCachedResponse];
GHAssertTrue(success,@"Failed to use cached response");
// Test respecting etag
request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://asi/ASIHTTPRequest/tests/content-always-new"]];
[request setDownloadCache:[ASIDownloadCache sharedCache]];
[request startSynchronous];
success = ![request didUseCachedResponse];
GHAssertTrue(success,@"Used cached response when we shouldn't have");
// Etag will be different on the second request
request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://asi/ASIHTTPRequest/tests/content-always-new"]];
[request setDownloadCache:[ASIDownloadCache sharedCache]];
[request startSynchronous];
success = ![request didUseCachedResponse];
GHAssertTrue(success,@"Used cached response when we shouldn't have");
// Test ignoring server headers
request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://asi/ASIHTTPRequest/tests/no-cache"]];
[request setDownloadCache:[ASIDownloadCache sharedCache]];
[[ASIDownloadCache sharedCache] setShouldRespectCacheControlHeaders:NO];
[request startSynchronous];
request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://asi/ASIHTTPRequest/tests/no-cache"]];
[request setDownloadCache:[ASIDownloadCache sharedCache]];
[[ASIDownloadCache sharedCache] setShouldRespectCacheControlHeaders:NO];
[request startSynchronous];
success = [request didUseCachedResponse];
GHAssertTrue(success,@"Failed to use cached response");
// Test ASIOnlyLoadIfNotCachedCachePolicy
[[ASIDownloadCache sharedCache] setShouldRespectCacheControlHeaders:YES];
request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://asi/ASIHTTPRequest/tests/content-always-new"]];
[request setDownloadCache:[ASIDownloadCache sharedCache]];
[[ASIDownloadCache sharedCache] setDefaultCachePolicy:ASIOnlyLoadIfNotCachedCachePolicy];
[request startSynchronous];
success = [request didUseCachedResponse];
GHAssertTrue(success,@"Failed to use cached response");
// Test clearing the cache
[[ASIDownloadCache sharedCache] clearCachedResponsesForStoragePolicy:ASICacheForSessionDurationCacheStoragePolicy];
request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://asi/ASIHTTPRequest/tests/cache-away"]];
[request setDownloadCache:[ASIDownloadCache sharedCache]];
[request startSynchronous];
success = ![request didUseCachedResponse];
GHAssertTrue(success,@"Cached response should not have been available");
}
- (void)testDefaultPolicy
{
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://asi/ASIHTTPRequest/tests/the_great_american_novel_(abridged).txt"]];
[request setDownloadCache:[ASIDownloadCache sharedCache]];
[request startSynchronous];
BOOL success = ([request cachePolicy] == [[ASIDownloadCache sharedCache] defaultCachePolicy]);
GHAssertTrue(success,@"Failed to use the cache policy from the cache");
request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://asi/ASIHTTPRequest/tests/the_great_american_novel_(abridged).txt"]];
[request setDownloadCache:[ASIDownloadCache sharedCache]];
[request setCachePolicy:ASIOnlyLoadIfNotCachedCachePolicy];
[request startSynchronous];
success = ([request cachePolicy] == ASIOnlyLoadIfNotCachedCachePolicy);
GHAssertTrue(success,@"Failed to use the cache policy from the cache");
}
- (void)testNoCache
{
// Test default cache policy
[[ASIDownloadCache sharedCache] clearCachedResponsesForStoragePolicy:ASICacheForSessionDurationCacheStoragePolicy];
[[ASIDownloadCache sharedCache] setDefaultCachePolicy:ASIIgnoreCachePolicy];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://asi/ASIHTTPRequest/tests/the_great_american_novel_(abridged).txt"]];
[request setDownloadCache:[ASIDownloadCache sharedCache]];
[request startSynchronous];
request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://asi/ASIHTTPRequest/tests/the_great_american_novel_(abridged).txt"]];
[request setDownloadCache:[ASIDownloadCache sharedCache]];
[request startSynchronous];
BOOL success = ![request didUseCachedResponse];
GHAssertTrue(success,@"Data should not have been stored in the cache");
// Test request cache policy
[[ASIDownloadCache sharedCache] setDefaultCachePolicy:ASIDefaultCachePolicy];
request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://asi/ASIHTTPRequest/tests/the_great_american_novel_(abridged).txt"]];
[request setCachePolicy:ASIIgnoreCachePolicy];
[request setDownloadCache:[ASIDownloadCache sharedCache]];
[request startSynchronous];
request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://asi/ASIHTTPRequest/tests/the_great_american_novel_(abridged).txt"]];
[request setDownloadCache:[ASIDownloadCache sharedCache]];
[request startSynchronous];
success = ![request didUseCachedResponse];
GHAssertTrue(success,@"Data should not have been stored in the cache");
// Test server no-cache headers
[[ASIDownloadCache sharedCache] clearCachedResponsesForStoragePolicy:ASICacheForSessionDurationCacheStoragePolicy];
NSArray *cacheHeaders = [NSArray arrayWithObjects:@"cache-control/no-cache",@"cache-control/no-store",@"pragma/no-cache",nil];
for (NSString *cacheType in cacheHeaders) {
NSString *url = [NSString stringWithFormat:@"http://asi/ASIHTTPRequest/tests/%@",cacheType];
request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:url]];
[request setDownloadCache:[ASIDownloadCache sharedCache]];
[request startSynchronous];
request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:url]];
[request setDownloadCache:[ASIDownloadCache sharedCache]];
[request startSynchronous];
success = ![request didUseCachedResponse];
GHAssertTrue(success,@"Data should not have been stored in the cache");
}
}
- (void)testSharedCache
{
[[ASIDownloadCache sharedCache] clearCachedResponsesForStoragePolicy:ASICacheForSessionDurationCacheStoragePolicy];
// Make using the cache automatic
[ASIHTTPRequest setDefaultCache:[ASIDownloadCache sharedCache]];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://asi/ASIHTTPRequest/tests/the_great_american_novel_(abridged).txt"]];
[request startSynchronous];
request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://asi/ASIHTTPRequest/tests/the_great_american_novel_(abridged).txt"]];
[request startSynchronous];
BOOL success = [request didUseCachedResponse];
GHAssertTrue(success,@"Failed to use data cached in default cache");
[ASIHTTPRequest setDefaultCache:nil];
request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://asi/ASIHTTPRequest/tests/the_great_american_novel_(abridged).txt"]];
[request startSynchronous];
success = ![request didUseCachedResponse];
GHAssertTrue(success,@"Should not have used data cached in default cache");
}
@end
... ...
... ... @@ -27,6 +27,7 @@ typedef enum _ASICacheStoragePolicy {
@required
- (ASICachePolicy)defaultCachePolicy;
- (BOOL)isCachedDataCurrentForRequest:(ASIHTTPRequest *)request;
- (void)storeResponseForRequest:(ASIHTTPRequest *)request;
- (NSDictionary *)cachedHeadersForRequest:(ASIHTTPRequest *)request;
- (NSData *)cachedResponseDataForRequest:(ASIHTTPRequest *)request;
... ...
... ... @@ -14,7 +14,7 @@
ASICacheStoragePolicy defaultCacheStoragePolicy;
NSString *storagePath;
NSRecursiveLock *accessLock;
BOOL shouldRespectCacheHeaders;
BOOL shouldRespectCacheControlHeaders;
}
+ (id)sharedCache;
+ (BOOL)serverAllowsResponseCachingForRequest:(ASIHTTPRequest *)request;
... ... @@ -23,5 +23,5 @@
@property (assign) ASICacheStoragePolicy defaultCacheStoragePolicy;
@property (retain) NSString *storagePath;
@property (retain) NSRecursiveLock *accessLock;
@property (assign) BOOL shouldRespectCacheHeaders;
@property (assign) BOOL shouldRespectCacheControlHeaders;
@end
... ...
... ... @@ -80,7 +80,7 @@ static NSString *permanentCacheFolder = @"PermanentStore";
return;
}
if ([self shouldRespectCacheHeaders] && ![[self class] serverAllowsResponseCachingForRequest:request]) {
if ([self shouldRespectCacheControlHeaders] && ![[self class] serverAllowsResponseCachingForRequest:request]) {
[[self accessLock] unlock];
return;
}
... ... @@ -287,5 +287,5 @@ static NSString *permanentCacheFolder = @"PermanentStore";
@synthesize defaultCachePolicy;
@synthesize defaultCacheStoragePolicy;
@synthesize accessLock;
@synthesize shouldRespectCacheHeaders;
@synthesize shouldRespectCacheControlHeaders;
@end
... ...
... ... @@ -399,6 +399,9 @@ extern unsigned long const ASIWWANBandwidthThrottleAmount;
// The cache storage policy that will be used for this request - See ASICacheDelegate.h for possible values
ASICacheStoragePolicy cacheStoragePolicy;
// Will be true when the response was pulled from the cache rather than downloaded
BOOL didUseCachedResponse;
}
... ... @@ -788,4 +791,5 @@ extern unsigned long const ASIWWANBandwidthThrottleAmount;
@property (assign) id <ASICacheDelegate> downloadCache;
@property (assign) ASICachePolicy cachePolicy;
@property (assign) ASICacheStoragePolicy cacheStoragePolicy;
@property (assign, readonly) BOOL didUseCachedResponse;
@end
... ...
... ... @@ -23,7 +23,7 @@
// Automatically set on build
NSString *ASIHTTPRequestVersion = @"v1.6.2-11 2010-05-02";
NSString *ASIHTTPRequestVersion = @"v1.6.2-12 2010-05-03";
NSString* const NetworkRequestErrorDomain = @"ASIHTTPRequestErrorDomain";
... ... @@ -192,6 +192,7 @@ static id <ASICacheDelegate> defaultCache = nil;
@property (assign, nonatomic) BOOL downloadComplete;
@property (retain) NSNumber *requestID;
@property (assign, nonatomic) NSString *runLoopMode;
@property (assign) BOOL didUseCachedResponse;
@end
... ... @@ -2460,6 +2461,11 @@ static id <ASICacheDelegate> defaultCache = nil;
[self readResponseHeaders];
}
// If we've cancelled the load part way through (for example, after deciding to use a cached version)
if ([self complete]) {
return;
}
// In certain (presumably very rare) circumstances, handleBytesAvailable seems to be called when there isn't actually any data available
// We'll check that there is actually data available to prevent blocking on CFReadStreamRead()
// So far, I've only seen this in the stress tests, so it might never happen in real-world situations.
... ... @@ -2674,6 +2680,13 @@ static id <ASICacheDelegate> defaultCache = nil;
return NO;
}
if ([self cachePolicy] == ASIReloadIfDifferentCachePolicy) {
if (![[self downloadCache] isCachedDataCurrentForRequest:self]) {
return NO;
}
}
[self setDidUseCachedResponse:YES];
[self cancelLoad];
ASIHTTPRequest *theRequest = self;
... ... @@ -3872,4 +3885,5 @@ static id <ASICacheDelegate> defaultCache = nil;
@synthesize downloadCache;
@synthesize cachePolicy;
@synthesize cacheStoragePolicy;
@synthesize didUseCachedResponse;
@end
... ...
... ... @@ -313,6 +313,9 @@
- (IBAction)reloadTableData:(id)sender
{
[[self tableQueue] cancelAllOperations];
[self setRowData:[NSMutableArray array]];
[tableView reloadData];
[self setTableQueue:[ASINetworkQueue queue]];
[[ASIDownloadCache sharedCache] setDefaultCachePolicy:ASIOnlyLoadIfNotCachedCachePolicy];
... ... @@ -333,7 +336,6 @@
- (void)tableViewDataFetchFinished:(ASIHTTPRequest *)request
{
[self setRowData:[NSMutableArray array]];
NSXMLDocument *xml = [[[NSXMLDocument alloc] initWithData:[request responseData] options:NSXMLDocumentValidate error:nil] autorelease];
for (NSXMLElement *row in [[xml rootElement] elementsForName:@"row"]) {
NSMutableDictionary *rowInfo = [NSMutableDictionary dictionary];
... ...
This diff was suppressed by a .gitattributes entry.