Skip to content

Commit

Permalink
Cache fixes - compare headers when ASIReloadIfDifferentCachePolicy
Browse files Browse the repository at this point in the history
Added starting point tests for ASIDownloadCache
  • Loading branch information
pokeb committed May 3, 2010
1 parent 6b5c04b commit 399ff4a
Show file tree
Hide file tree
Showing 9 changed files with 218 additions and 6 deletions.
16 changes: 16 additions & 0 deletions ASIDownloadCacheTests.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// 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
169 changes: 169 additions & 0 deletions ASIDownloadCacheTests.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
//
// 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
1 change: 1 addition & 0 deletions Classes/ASICacheDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions Classes/ASIDownloadCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
ASICacheStoragePolicy defaultCacheStoragePolicy;
NSString *storagePath;
NSRecursiveLock *accessLock;
BOOL shouldRespectCacheHeaders;
BOOL shouldRespectCacheControlHeaders;
}
+ (id)sharedCache;
+ (BOOL)serverAllowsResponseCachingForRequest:(ASIHTTPRequest *)request;
Expand All @@ -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
4 changes: 2 additions & 2 deletions Classes/ASIDownloadCache.m
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ - (void)storeResponseForRequest:(ASIHTTPRequest *)request
return;
}

if ([self shouldRespectCacheHeaders] && ![[self class] serverAllowsResponseCachingForRequest:request]) {
if ([self shouldRespectCacheControlHeaders] && ![[self class] serverAllowsResponseCachingForRequest:request]) {
[[self accessLock] unlock];
return;
}
Expand Down Expand Up @@ -287,5 +287,5 @@ + (NSString *)responseHeader:(NSString *)header fromHeaders:(NSDictionary *)head
@synthesize defaultCachePolicy;
@synthesize defaultCacheStoragePolicy;
@synthesize accessLock;
@synthesize shouldRespectCacheHeaders;
@synthesize shouldRespectCacheControlHeaders;
@end
4 changes: 4 additions & 0 deletions Classes/ASIHTTPRequest.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

}

Expand Down Expand Up @@ -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
16 changes: 15 additions & 1 deletion Classes/ASIHTTPRequest.m
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -192,6 +192,7 @@ + (void)reachabilityChanged:(NSNotification *)note;
@property (assign, nonatomic) BOOL downloadComplete;
@property (retain) NSNumber *requestID;
@property (assign, nonatomic) NSString *runLoopMode;
@property (assign) BOOL didUseCachedResponse;
@end


Expand Down Expand Up @@ -2460,6 +2461,11 @@ - (void)handleBytesAvailable
[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.
Expand Down Expand Up @@ -2674,6 +2680,13 @@ - (BOOL)useDataFromCache
return NO;
}

if ([self cachePolicy] == ASIReloadIfDifferentCachePolicy) {
if (![[self downloadCache] isCachedDataCurrentForRequest:self]) {
return NO;
}
}

[self setDidUseCachedResponse:YES];
[self cancelLoad];

ASIHTTPRequest *theRequest = self;
Expand Down Expand Up @@ -3872,4 +3885,5 @@ + (NSString*)base64forData:(NSData*)theData {
@synthesize downloadCache;
@synthesize cachePolicy;
@synthesize cacheStoragePolicy;
@synthesize didUseCachedResponse;
@end
4 changes: 3 additions & 1 deletion Mac Sample/AppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,9 @@ - (void)postFailed:(ASIHTTPRequest *)request
- (IBAction)reloadTableData:(id)sender
{
[[self tableQueue] cancelAllOperations];
[self setRowData:[NSMutableArray array]];
[tableView reloadData];

[self setTableQueue:[ASINetworkQueue queue]];
[[ASIDownloadCache sharedCache] setDefaultCachePolicy:ASIOnlyLoadIfNotCachedCachePolicy];

Expand All @@ -333,7 +336,6 @@ - (void)tableViewDataFetchFailed:(ASIHTTPRequest *)request

- (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];
Expand Down
6 changes: 6 additions & 0 deletions Mac.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
B5873FA310FF2890001E145F /* ASICloudFilesObjectRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = B5873F9B10FF2890001E145F /* ASICloudFilesObjectRequest.m */; };
B5873FA410FF2890001E145F /* ASICloudFilesRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = B5873F9D10FF2890001E145F /* ASICloudFilesRequest.m */; };
B587400810FF2913001E145F /* ASICloudFilesRequestTests.m in Sources */ = {isa = PBXBuildFile; fileRef = B587400610FF2913001E145F /* ASICloudFilesRequestTests.m */; };
B591E7AE118ECC0200B85497 /* ASIDownloadCacheTests.m in Sources */ = {isa = PBXBuildFile; fileRef = B591E7AD118ECC0200B85497 /* ASIDownloadCacheTests.m */; };
B5B513860FBEE515002C74D0 /* GHUnitTestMain.m in Sources */ = {isa = PBXBuildFile; fileRef = B5B513850FBEE515002C74D0 /* GHUnitTestMain.m */; };
B5C664BC100A6220004F3C96 /* ASIS3RequestTests.m in Sources */ = {isa = PBXBuildFile; fileRef = B5C664BB100A6220004F3C96 /* ASIS3RequestTests.m */; };
B5DB49CA115627300062DB57 /* GHUnit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5DB497C115624BF0062DB57 /* GHUnit.framework */; };
Expand Down Expand Up @@ -167,6 +168,8 @@
B5873F9D10FF2890001E145F /* ASICloudFilesRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASICloudFilesRequest.m; sourceTree = "<group>"; };
B587400610FF2913001E145F /* ASICloudFilesRequestTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASICloudFilesRequestTests.m; sourceTree = "<group>"; };
B587400710FF2913001E145F /* ASICloudFilesRequestTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASICloudFilesRequestTests.h; sourceTree = "<group>"; };
B591E7AC118ECC0200B85497 /* ASIDownloadCacheTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASIDownloadCacheTests.h; path = ../../ASIDownloadCacheTests.h; sourceTree = "<group>"; };
B591E7AD118ECC0200B85497 /* ASIDownloadCacheTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ASIDownloadCacheTests.m; path = ../../ASIDownloadCacheTests.m; sourceTree = "<group>"; };
B5B513850FBEE515002C74D0 /* GHUnitTestMain.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GHUnitTestMain.m; sourceTree = "<group>"; };
B5C664BA100A6220004F3C96 /* ASIS3RequestTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIS3RequestTests.h; sourceTree = "<group>"; };
B5C664BB100A6220004F3C96 /* ASIS3RequestTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASIS3RequestTests.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -324,6 +327,8 @@
B5B513850FBEE515002C74D0 /* GHUnitTestMain.m */,
B565297D101C8D01000499CF /* ASITestCase.h */,
B565297C101C8D01000499CF /* ASITestCase.m */,
B591E7AC118ECC0200B85497 /* ASIDownloadCacheTests.h */,
B591E7AD118ECC0200B85497 /* ASIDownloadCacheTests.m */,
B55B5D1A0F76568E0064029C /* ASIFormDataRequestTests.h */,
B55B5D1B0F76568E0064029C /* ASIFormDataRequestTests.m */,
B55B5D1C0F76568E0064029C /* ASIHTTPRequestTests.h */,
Expand Down Expand Up @@ -553,6 +558,7 @@
B5403FF01151149E00D8BE63 /* ASIS3ObjectRequest.m in Sources */,
B5403FF11151149E00D8BE63 /* ASIS3ServiceRequest.m in Sources */,
B502593A118C6C0800EF1983 /* ASIDownloadCache.m in Sources */,
B591E7AE118ECC0200B85497 /* ASIDownloadCacheTests.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down

0 comments on commit 399ff4a

Please sign in to comment.