Ben Copsey

* ASIWebPageRequest now has three url-replacement modes, see ASIWebPageRequest.h for details

* ASIDownloadCache now strips trailing slashes from urls when building the key used to store the data. Now it doesn't matter if the request's url includes the trailing slash or not
* ASIDownloadCache now names all data-files with an .html extension. This allows ASIWebPageRequest to display frames and iframes with local content.
* Remove broken NSURLCache compatibility from ASIDownloadCache
* ASIDownloadCache now stores its data in the NSCachesDirectory instead of  NSTemporaryDirectory (Thanks to Dincho Todorov for pointing this out!)
@@ -9,7 +9,7 @@ @@ -9,7 +9,7 @@
9 #import <Foundation/Foundation.h> 9 #import <Foundation/Foundation.h>
10 #import "ASICacheDelegate.h" 10 #import "ASICacheDelegate.h"
11 11
12 -@interface ASIDownloadCache : NSURLCache <ASICacheDelegate> { 12 +@interface ASIDownloadCache : NSObject <ASICacheDelegate> {
13 13
14 // The default cache policy for this cache 14 // The default cache policy for this cache
15 // Requests that store data in the cache will use this cache policy if their cache policy is set to ASIDefaultCachePolicy 15 // Requests that store data in the cache will use this cache policy if their cache policy is set to ASIDefaultCachePolicy
@@ -34,7 +34,7 @@ static NSString *permanentCacheFolder = @"PermanentStore"; @@ -34,7 +34,7 @@ static NSString *permanentCacheFolder = @"PermanentStore";
34 { 34 {
35 if (!sharedCache) { 35 if (!sharedCache) {
36 sharedCache = [[self alloc] init]; 36 sharedCache = [[self alloc] init];
37 - [sharedCache setStoragePath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"ASIHTTPRequestCache"]]; 37 + [sharedCache setStoragePath:[[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:@"ASIHTTPRequestCache"]];
38 38
39 } 39 }
40 return sharedCache; 40 return sharedCache;
@@ -146,14 +146,14 @@ static NSString *permanentCacheFolder = @"PermanentStore"; @@ -146,14 +146,14 @@ static NSString *permanentCacheFolder = @"PermanentStore";
146 } 146 }
147 // Look in the session store 147 // Look in the session store
148 NSString *path = [[self storagePath] stringByAppendingPathComponent:sessionCacheFolder]; 148 NSString *path = [[self storagePath] stringByAppendingPathComponent:sessionCacheFolder];
149 - NSString *dataPath = [path stringByAppendingPathComponent:[[[self class] keyForURL:url] stringByAppendingPathExtension:@"cacheddata"]]; 149 + NSString *dataPath = [path stringByAppendingPathComponent:[[[self class] keyForURL:url] stringByAppendingPathExtension:@"html"]];
150 if ([[NSFileManager defaultManager] fileExistsAtPath:dataPath]) { 150 if ([[NSFileManager defaultManager] fileExistsAtPath:dataPath]) {
151 [[self accessLock] unlock]; 151 [[self accessLock] unlock];
152 return dataPath; 152 return dataPath;
153 } 153 }
154 // Look in the permanent store 154 // Look in the permanent store
155 path = [[self storagePath] stringByAppendingPathComponent:permanentCacheFolder]; 155 path = [[self storagePath] stringByAppendingPathComponent:permanentCacheFolder];
156 - dataPath = [path stringByAppendingPathComponent:[[[self class] keyForURL:url] stringByAppendingPathExtension:@"cacheddata"]]; 156 + dataPath = [path stringByAppendingPathComponent:[[[self class] keyForURL:url] stringByAppendingPathExtension:@"html"]];
157 if ([[NSFileManager defaultManager] fileExistsAtPath:dataPath]) { 157 if ([[NSFileManager defaultManager] fileExistsAtPath:dataPath]) {
158 [[self accessLock] unlock]; 158 [[self accessLock] unlock];
159 return dataPath; 159 return dataPath;
@@ -195,7 +195,7 @@ static NSString *permanentCacheFolder = @"PermanentStore"; @@ -195,7 +195,7 @@ static NSString *permanentCacheFolder = @"PermanentStore";
195 return nil; 195 return nil;
196 } 196 }
197 NSString *path = [[self storagePath] stringByAppendingPathComponent:([request cacheStoragePolicy] == ASICacheForSessionDurationCacheStoragePolicy ? sessionCacheFolder : permanentCacheFolder)]; 197 NSString *path = [[self storagePath] stringByAppendingPathComponent:([request cacheStoragePolicy] == ASICacheForSessionDurationCacheStoragePolicy ? sessionCacheFolder : permanentCacheFolder)];
198 - path = [path stringByAppendingPathComponent:[[[self class] keyForURL:[request url]] stringByAppendingPathExtension:@"cacheddata"]]; 198 + path = [path stringByAppendingPathComponent:[[[self class] keyForURL:[request url]] stringByAppendingPathExtension:@"html"]];
199 [[self accessLock] unlock]; 199 [[self accessLock] unlock];
200 return path; 200 return path;
201 } 201 }
@@ -382,7 +382,12 @@ static NSString *permanentCacheFolder = @"PermanentStore"; @@ -382,7 +382,12 @@ static NSString *permanentCacheFolder = @"PermanentStore";
382 // Borrowed from: http://stackoverflow.com/questions/652300/using-md5-hash-on-a-string-in-cocoa 382 // Borrowed from: http://stackoverflow.com/questions/652300/using-md5-hash-on-a-string-in-cocoa
383 + (NSString *)keyForURL:(NSURL *)url 383 + (NSString *)keyForURL:(NSURL *)url
384 { 384 {
385 - const char *cStr = [[url absoluteString] UTF8String]; 385 + NSString *urlString = [url absoluteString];
  386 + // Strip trailing slashes so http://allseeing-i.com/ASIHTTPRequest/ is cached the same as http://allseeing-i.com/ASIHTTPRequest
  387 + if ([[urlString substringFromIndex:[urlString length]-1] isEqualToString:@"/"]) {
  388 + urlString = [urlString substringToIndex:[urlString length]-1];
  389 + }
  390 + const char *cStr = [urlString UTF8String];
386 unsigned char result[16]; 391 unsigned char result[16];
387 CC_MD5(cStr, (CC_LONG)strlen(cStr), result); 392 CC_MD5(cStr, (CC_LONG)strlen(cStr), result);
388 return [NSString stringWithFormat:@"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",result[0], result[1], result[2], result[3], result[4], result[5], result[6], result[7],result[8], result[9], result[10], result[11],result[12], result[13], result[14], result[15]]; 393 return [NSString stringWithFormat:@"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",result[0], result[1], result[2], result[3], result[4], result[5], result[6], result[7],result[8], result[9], result[10], result[11],result[12], result[13], result[14], result[15]];
@@ -446,23 +451,6 @@ static NSString *permanentCacheFolder = @"PermanentStore"; @@ -446,23 +451,6 @@ static NSString *permanentCacheFolder = @"PermanentStore";
446 return NO; 451 return NO;
447 } 452 }
448 453
449 -/*  
450 -NSURLCache compatibility  
451 -*/  
452 -- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request  
453 -{  
454 - NSData *data = [self cachedResponseDataForURL:[request URL]];  
455 - NSDictionary *headers = [self cachedResponseHeadersForURL:[request URL]];  
456 - if (!data || !headers) {  
457 - return [super cachedResponseForRequest:request];  
458 - }  
459 - NSString *mimeType = nil;  
460 - NSStringEncoding charset;  
461 - [ASIHTTPRequest parseMimeType:&mimeType andResponseEncoding:&charset fromContentType:[headers objectForKey:@"Content-Type"]];  
462 - NSURLResponse *urlResponse = [[[NSURLResponse alloc] initWithURL:[request URL] MIMEType:mimeType expectedContentLength:[data length] textEncodingName:nil] autorelease];  
463 - return [[NSCachedURLResponse alloc] initWithResponse:urlResponse data:data];  
464 -}  
465 -  
466 @synthesize storagePath; 454 @synthesize storagePath;
467 @synthesize defaultCachePolicy; 455 @synthesize defaultCachePolicy;
468 @synthesize accessLock; 456 @synthesize accessLock;
@@ -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.7-102 2010-10-03"; 27 +NSString *ASIHTTPRequestVersion = @"v1.7-106 2010-10-09";
28 28
29 NSString* const NetworkRequestErrorDomain = @"ASIHTTPRequestErrorDomain"; 29 NSString* const NetworkRequestErrorDomain = @"ASIHTTPRequestErrorDomain";
30 30
@@ -17,12 +17,30 @@ @@ -17,12 +17,30 @@
17 17
18 @class ASINetworkQueue; 18 @class ASINetworkQueue;
19 19
  20 +// Used internally for storing what type of data we got from the server
20 typedef enum _ASIWebContentType { 21 typedef enum _ASIWebContentType {
21 ASINotParsedWebContentType = 0, 22 ASINotParsedWebContentType = 0,
22 ASIHTMLWebContentType = 1, 23 ASIHTMLWebContentType = 1,
23 ASICSSWebContentType = 2 24 ASICSSWebContentType = 2
24 } ASIWebContentType; 25 } ASIWebContentType;
25 26
  27 +// These correspond with the urlReplacementMode property of ASIWebPageRequest
  28 +typedef enum _ASIURLReplacementMode {
  29 +
  30 + // Don't modify html or css content at all
  31 + ASIDontModifyURLs = 0,
  32 +
  33 + // Replace external resources urls (images, stylesheets etc) with data uris, so their content is embdedded directly in the html/css
  34 + ASIReplaceExternalResourcesWithData = 1,
  35 +
  36 + // Replace external resource urls with the url of locally cached content
  37 + // You must set the baseURL of a WebView / UIWebView to a file url pointing at the downloadDestinationPath of the main ASIWebPageRequest if you want to display your content
  38 + // See the Mac or iPhone example projects for a demonstration of how to do this
  39 + // The hrefs of all hyperlinks are changed to use absolute urls when using this mode
  40 + ASIReplaceExternalResourcesWithLocalURLs = 2
  41 +} ASIURLReplacementMode;
  42 +
  43 +
26 44
27 @interface ASIWebPageRequest : ASIHTTPRequest { 45 @interface ASIWebPageRequest : ASIHTTPRequest {
28 46
@@ -43,11 +61,8 @@ typedef enum _ASIWebContentType { @@ -43,11 +61,8 @@ typedef enum _ASIWebContentType {
43 // For example, a request for an image can be created by a request for a stylesheet which was created by a request for a web page 61 // For example, a request for an image can be created by a request for a stylesheet which was created by a request for a web page
44 ASIWebPageRequest *parentRequest; 62 ASIWebPageRequest *parentRequest;
45 63
46 - // If set to YES, ASIWebPageRequest will replace the urls of supported external resources with data urls that contain the the content of the external url 64 + // Controls what ASIWebPageRequest does with external resources. See the notes above for more.
47 - // This allows you to cache a complete webpage in a single file 65 + ASIURLReplacementMode urlReplacementMode;
48 - // If set to NO, ASIWebPageRequest will still download the content of external resource URLS, but will not make changes to CSS or HTML  
49 - // If you set an ASIDownloadCache for this request and also use it as NSURLCache's sharedCache, webViews and UIWebViews should still be able load many external resources from disk without fetching them again  
50 - BOOL replaceURLsWithDataURLs;  
51 } 66 }
52 67
53 // Will return a data URI that contains a base64 version of the content at this url 68 // Will return a data URI that contains a base64 version of the content at this url
@@ -60,5 +75,5 @@ typedef enum _ASIWebContentType { @@ -60,5 +75,5 @@ typedef enum _ASIWebContentType {
60 75
61 76
62 @property (retain, nonatomic) ASIWebPageRequest *parentRequest; 77 @property (retain, nonatomic) ASIWebPageRequest *parentRequest;
63 -@property (assign, nonatomic) BOOL replaceURLsWithDataURLs; 78 +@property (assign, nonatomic) ASIURLReplacementMode urlReplacementMode;
64 @end 79 @end
@@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@
13 13
14 // An xPath query that controls the external resources ASIWebPageRequest will fetch 14 // An xPath query that controls the external resources ASIWebPageRequest will fetch
15 // By default, it will fetch stylesheets, javascript files, images, frames, iframes, and html 5 video / audio 15 // By default, it will fetch stylesheets, javascript files, images, frames, iframes, and html 5 video / audio
16 -static xmlChar *xpathExpr = (xmlChar *)"//link/@href|//script/@src|//img/@src|//frame/@src|//iframe/@src|//style|//*/@style|//source/@src"; 16 +static xmlChar *xpathExpr = (xmlChar *)"//link/@href|//a/@href|//script/@src|//img/@src|//frame/@src|//iframe/@src|//style|//*/@style|//source/@src";
17 17
18 static NSLock *xmlParsingLock = nil; 18 static NSLock *xmlParsingLock = nil;
19 static NSMutableArray *requestsUsingXMLParser = nil; 19 static NSMutableArray *requestsUsingXMLParser = nil;
@@ -25,6 +25,7 @@ static NSMutableArray *requestsUsingXMLParser = nil; @@ -25,6 +25,7 @@ static NSMutableArray *requestsUsingXMLParser = nil;
25 - (void)parseAsCSS; 25 - (void)parseAsCSS;
26 - (void)addURLToFetch:(NSString *)newURL; 26 - (void)addURLToFetch:(NSString *)newURL;
27 + (NSArray *)CSSURLsFromString:(NSString *)string; 27 + (NSArray *)CSSURLsFromString:(NSString *)string;
  28 +- (NSString *)relativePathTo:(NSString *)destinationPath fromPath:(NSString *)sourcePath;
28 @property (retain, nonatomic) ASINetworkQueue *externalResourceQueue; 29 @property (retain, nonatomic) ASINetworkQueue *externalResourceQueue;
29 @property (retain, nonatomic) NSMutableDictionary *resourceList; 30 @property (retain, nonatomic) NSMutableDictionary *resourceList;
30 @end 31 @end
@@ -52,7 +53,7 @@ static NSMutableArray *requestsUsingXMLParser = nil; @@ -52,7 +53,7 @@ static NSMutableArray *requestsUsingXMLParser = nil;
52 - (void)requestFinished 53 - (void)requestFinished
53 { 54 {
54 complete = NO; 55 complete = NO;
55 - if ([self mainRequest]) { 56 + if ([self mainRequest] || [self didUseCachedResponse]) {
56 [super requestFinished]; 57 [super requestFinished];
57 [super markAsFinished]; 58 [super markAsFinished];
58 return; 59 return;
@@ -117,7 +118,7 @@ static NSMutableArray *requestsUsingXMLParser = nil; @@ -117,7 +118,7 @@ static NSMutableArray *requestsUsingXMLParser = nil;
117 [externalResourceRequest setCacheStoragePolicy:[self cacheStoragePolicy]]; 118 [externalResourceRequest setCacheStoragePolicy:[self cacheStoragePolicy]];
118 [externalResourceRequest setUserInfo:[NSDictionary dictionaryWithObject:theURL forKey:@"Path"]]; 119 [externalResourceRequest setUserInfo:[NSDictionary dictionaryWithObject:theURL forKey:@"Path"]];
119 [externalResourceRequest setParentRequest:self]; 120 [externalResourceRequest setParentRequest:self];
120 - [externalResourceRequest setReplaceURLsWithDataURLs:[self replaceURLsWithDataURLs]]; 121 + [externalResourceRequest setUrlReplacementMode:[self urlReplacementMode]];
121 [externalResourceRequest setShouldResetDownloadProgress:NO]; 122 [externalResourceRequest setShouldResetDownloadProgress:NO];
122 [externalResourceRequest setDelegate:self]; 123 [externalResourceRequest setDelegate:self];
123 [externalResourceRequest setUploadProgressDelegate:self]; 124 [externalResourceRequest setUploadProgressDelegate:self];
@@ -185,7 +186,7 @@ static NSMutableArray *requestsUsingXMLParser = nil; @@ -185,7 +186,7 @@ static NSMutableArray *requestsUsingXMLParser = nil;
185 [externalResourceRequest setCacheStoragePolicy:[self cacheStoragePolicy]]; 186 [externalResourceRequest setCacheStoragePolicy:[self cacheStoragePolicy]];
186 [externalResourceRequest setUserInfo:[NSDictionary dictionaryWithObject:theURL forKey:@"Path"]]; 187 [externalResourceRequest setUserInfo:[NSDictionary dictionaryWithObject:theURL forKey:@"Path"]];
187 [externalResourceRequest setParentRequest:self]; 188 [externalResourceRequest setParentRequest:self];
188 - [externalResourceRequest setReplaceURLsWithDataURLs:[self replaceURLsWithDataURLs]]; 189 + [externalResourceRequest setUrlReplacementMode:[self urlReplacementMode]];
189 [externalResourceRequest setShouldResetDownloadProgress:NO]; 190 [externalResourceRequest setShouldResetDownloadProgress:NO];
190 [externalResourceRequest setDelegate:self]; 191 [externalResourceRequest setDelegate:self];
191 [externalResourceRequest setUploadProgressDelegate:self]; 192 [externalResourceRequest setUploadProgressDelegate:self];
@@ -222,7 +223,7 @@ static NSMutableArray *requestsUsingXMLParser = nil; @@ -222,7 +223,7 @@ static NSMutableArray *requestsUsingXMLParser = nil;
222 223
223 - (void)finishedFetchingExternalResources:(ASINetworkQueue *)queue 224 - (void)finishedFetchingExternalResources:(ASINetworkQueue *)queue
224 { 225 {
225 - if ([self replaceURLsWithDataURLs]) { 226 + if ([self urlReplacementMode] != ASIDontModifyURLs) {
226 if (webContentType == ASICSSWebContentType) { 227 if (webContentType == ASICSSWebContentType) {
227 NSMutableString *parsedResponse; 228 NSMutableString *parsedResponse;
228 NSError *err = nil; 229 NSError *err = nil;
@@ -292,8 +293,8 @@ static NSMutableArray *requestsUsingXMLParser = nil; @@ -292,8 +293,8 @@ static NSMutableArray *requestsUsingXMLParser = nil;
292 [self setResponseHeaders:newHeaders]; 293 [self setResponseHeaders:newHeaders];
293 294
294 // Write the parsed content back to the cache 295 // Write the parsed content back to the cache
295 - if ([self replaceURLsWithDataURLs]) { 296 + if ([self urlReplacementMode] != ASIDontModifyURLs) {
296 - [[self downloadCache] storeResponseForRequest:self maxAge:[self secondsToCache]]; 297 + //[[self downloadCache] storeResponseForRequest:self maxAge:[self secondsToCache]];
297 } 298 }
298 299
299 [super requestFinished]; 300 [super requestFinished];
@@ -341,7 +342,8 @@ static NSMutableArray *requestsUsingXMLParser = nil; @@ -341,7 +342,8 @@ static NSMutableArray *requestsUsingXMLParser = nil;
341 for (NSString *theURL in externalResources) { 342 for (NSString *theURL in externalResources) {
342 [self addURLToFetch:theURL]; 343 [self addURLToFetch:theURL];
343 } 344 }
344 - } else { 345 + } else if (![[parentName lowercaseString] isEqualToString:@"a"]) {
  346 + NSLog(@"%@",value);
345 [self addURLToFetch:value]; 347 [self addURLToFetch:value];
346 } 348 }
347 if (nodes->nodeTab[i]->type != XML_NAMESPACE_DECL) { 349 if (nodes->nodeTab[i]->type != XML_NAMESPACE_DECL) {
@@ -395,6 +397,7 @@ static NSMutableArray *requestsUsingXMLParser = nil; @@ -395,6 +397,7 @@ static NSMutableArray *requestsUsingXMLParser = nil;
395 int i; 397 int i;
396 for(i = size - 1; i >= 0; i--) { 398 for(i = size - 1; i >= 0; i--) {
397 assert(nodes->nodeTab[i]); 399 assert(nodes->nodeTab[i]);
  400 + NSString *parentName = [NSString stringWithCString:(char *)nodes->nodeTab[i]->parent->name encoding:[self responseEncoding]];
398 NSString *nodeName = [NSString stringWithCString:(char *)nodes->nodeTab[i]->name encoding:[self responseEncoding]]; 401 NSString *nodeName = [NSString stringWithCString:(char *)nodes->nodeTab[i]->name encoding:[self responseEncoding]];
399 NSString *value = [NSString stringWithCString:(char *)xmlNodeGetContent(nodes->nodeTab[i]) encoding:[self responseEncoding]]; 402 NSString *value = [NSString stringWithCString:(char *)xmlNodeGetContent(nodes->nodeTab[i]) encoding:[self responseEncoding]];
400 if ([[nodeName lowercaseString] isEqualToString:@"style"]) { 403 if ([[nodeName lowercaseString] isEqualToString:@"style"]) {
@@ -408,6 +411,11 @@ static NSMutableArray *requestsUsingXMLParser = nil; @@ -408,6 +411,11 @@ static NSMutableArray *requestsUsingXMLParser = nil;
408 } 411 }
409 } 412 }
410 xmlNodeSetContent(nodes->nodeTab[i], (xmlChar *)[value cStringUsingEncoding:[self responseEncoding]]); 413 xmlNodeSetContent(nodes->nodeTab[i], (xmlChar *)[value cStringUsingEncoding:[self responseEncoding]]);
  414 + } else if ([self urlReplacementMode] == ASIReplaceExternalResourcesWithLocalURLs && [[parentName lowercaseString] isEqualToString:@"a"]) {
  415 + NSString *newURL = [[NSURL URLWithString:value relativeToURL:[self url]] absoluteString];
  416 + if (newURL) {
  417 + xmlNodeSetContent(nodes->nodeTab[i], (xmlChar *)[newURL cStringUsingEncoding:[self responseEncoding]]);
  418 + }
411 } else { 419 } else {
412 NSString *newURL = [self contentForExternalURL:value]; 420 NSString *newURL = [self contentForExternalURL:value];
413 if (newURL) { 421 if (newURL) {
@@ -491,8 +499,39 @@ static NSMutableArray *requestsUsingXMLParser = nil; @@ -491,8 +499,39 @@ static NSMutableArray *requestsUsingXMLParser = nil;
491 return urls; 499 return urls;
492 } 500 }
493 501
  502 +- (NSString *)relativePathTo:(NSString *)destinationPath fromPath:(NSString *)sourcePath
  503 +{
  504 + NSArray *sourcePathComponents = [sourcePath pathComponents];
  505 + NSArray *destinationPathComponents = [destinationPath pathComponents];
  506 + NSUInteger i;
  507 + NSString *newPath = @"";
  508 + NSString *sourcePathComponent, *destinationPathComponent;
  509 + for (i=0; i<[sourcePathComponents count]; i++) {
  510 + sourcePathComponent = [sourcePathComponents objectAtIndex:i];
  511 + if ([destinationPathComponents count] > i) {
  512 + destinationPathComponent = [destinationPathComponents objectAtIndex:i];
  513 + if (![sourcePathComponent isEqualToString:destinationPathComponent]) {
  514 + NSUInteger i2;
  515 + for (i2=i+1; i2<[sourcePathComponents count]; i2++) {
  516 + newPath = [newPath stringByAppendingPathComponent:@".."];
  517 + }
  518 + newPath = [newPath stringByAppendingPathComponent:destinationPathComponent];
  519 + for (i2=i+1; i2<[destinationPathComponents count]; i2++) {
  520 + newPath = [newPath stringByAppendingPathComponent:[destinationPathComponents objectAtIndex:i2]];
  521 + }
  522 + break;
  523 + }
  524 + }
  525 + }
  526 + return newPath;
  527 +}
  528 +
494 - (NSString *)contentForExternalURL:(NSString *)theURL 529 - (NSString *)contentForExternalURL:(NSString *)theURL
495 { 530 {
  531 + if ([self urlReplacementMode] == ASIReplaceExternalResourcesWithLocalURLs) {
  532 + NSString *resourcePath = [[resourceList objectForKey:theURL] objectForKey:@"DataPath"];
  533 + return [self relativePathTo:resourcePath fromPath:[self downloadDestinationPath]];
  534 + }
496 NSData *data; 535 NSData *data;
497 if ([[resourceList objectForKey:theURL] objectForKey:@"DataPath"]) { 536 if ([[resourceList objectForKey:theURL] objectForKey:@"DataPath"]) {
498 data = [NSData dataWithContentsOfFile:[[resourceList objectForKey:theURL] objectForKey:@"DataPath"]]; 537 data = [NSData dataWithContentsOfFile:[[resourceList objectForKey:theURL] objectForKey:@"DataPath"]];
@@ -522,7 +561,7 @@ static NSMutableArray *requestsUsingXMLParser = nil; @@ -522,7 +561,7 @@ static NSMutableArray *requestsUsingXMLParser = nil;
522 unsigned char result[16]; 561 unsigned char result[16];
523 CC_MD5(cStr, (CC_LONG)strlen(cStr), result); 562 CC_MD5(cStr, (CC_LONG)strlen(cStr), result);
524 NSString *md5 = [NSString stringWithFormat:@"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",result[0], result[1], result[2], result[3], result[4], result[5], result[6], result[7],result[8], result[9], result[10], result[11],result[12], result[13], result[14], result[15]]; 563 NSString *md5 = [NSString stringWithFormat:@"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",result[0], result[1], result[2], result[3], result[4], result[5], result[6], result[7],result[8], result[9], result[10], result[11],result[12], result[13], result[14], result[15]];
525 - return [NSTemporaryDirectory() stringByAppendingPathComponent:md5]; 564 + return [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:[md5 stringByAppendingPathExtension:@"html"]];
526 } 565 }
527 } 566 }
528 567
@@ -530,5 +569,5 @@ static NSMutableArray *requestsUsingXMLParser = nil; @@ -530,5 +569,5 @@ static NSMutableArray *requestsUsingXMLParser = nil;
530 @synthesize externalResourceQueue; 569 @synthesize externalResourceQueue;
531 @synthesize resourceList; 570 @synthesize resourceList;
532 @synthesize parentRequest; 571 @synthesize parentRequest;
533 -@synthesize replaceURLsWithDataURLs; 572 +@synthesize urlReplacementMode;
534 @end 573 @end
@@ -393,6 +393,7 @@ @@ -393,6 +393,7 @@
393 [listener use]; 393 [listener use];
394 return; 394 return;
395 } 395 }
  396 +
396 // If the user clicked on a link, let's tell the webview to ignore it, and we'll load it ourselves 397 // If the user clicked on a link, let's tell the webview to ignore it, and we'll load it ourselves
397 [self fetchURL:[NSURL URLWithString:[[request URL] absoluteString] relativeToURL:[NSURL URLWithString:[urlField stringValue]]]]; 398 [self fetchURL:[NSURL URLWithString:[[request URL] absoluteString] relativeToURL:[NSURL URLWithString:[urlField stringValue]]]];
398 [listener ignore]; 399 [listener ignore];
@@ -400,22 +401,19 @@ @@ -400,22 +401,19 @@
400 401
401 - (void)fetchURL:(NSURL *)url 402 - (void)fetchURL:(NSURL *)url
402 { 403 {
403 - // This allows our ASIDownloadCache to masquerade as as NSURLCache  
404 - // It allows the webView to load the content we downloaded when replaceURLsWithDataURLs is NO  
405 - [NSURLCache setSharedURLCache:[ASIDownloadCache sharedCache]];  
406 ASIWebPageRequest *request = [ASIWebPageRequest requestWithURL:url]; 404 ASIWebPageRequest *request = [ASIWebPageRequest requestWithURL:url];
407 [request setDidFailSelector:@selector(webPageFetchFailed:)]; 405 [request setDidFailSelector:@selector(webPageFetchFailed:)];
408 [request setDidFinishSelector:@selector(webPageFetchSucceeded:)]; 406 [request setDidFinishSelector:@selector(webPageFetchSucceeded:)];
409 [request setDelegate:self]; 407 [request setDelegate:self];
410 [request setShowAccurateProgress:NO]; 408 [request setShowAccurateProgress:NO];
411 [request setDownloadProgressDelegate:progressIndicator]; 409 [request setDownloadProgressDelegate:progressIndicator];
412 - [request setReplaceURLsWithDataURLs:([dataURICheckbox state] == NSOnState)]; 410 + [request setUrlReplacementMode:([dataURICheckbox state] == NSOnState ? ASIReplaceExternalResourcesWithData : ASIReplaceExternalResourcesWithLocalURLs)];
413 411
414 // It is strongly recommended that you set both a downloadCache and a downloadDestinationPath for all ASIWebPageRequests 412 // It is strongly recommended that you set both a downloadCache and a downloadDestinationPath for all ASIWebPageRequests
415 [request setDownloadCache:[ASIDownloadCache sharedCache]]; 413 [request setDownloadCache:[ASIDownloadCache sharedCache]];
416 - [request setDownloadDestinationPath:[[[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"fink"]]; 414 + [request setDownloadDestinationPath:[[ASIDownloadCache sharedCache] pathToStoreCachedResponseDataForRequest:request]];
417 415
418 - [[ASIDownloadCache sharedCache] setShouldRespectCacheControlHeaders:NO]; 416 + //[[ASIDownloadCache sharedCache] setShouldRespectCacheControlHeaders:NO];
419 [request startAsynchronous]; 417 [request startAsynchronous];
420 } 418 }
421 419
@@ -426,13 +424,22 @@ @@ -426,13 +424,22 @@
426 424
427 - (void)webPageFetchSucceeded:(ASIHTTPRequest *)request 425 - (void)webPageFetchSucceeded:(ASIHTTPRequest *)request
428 { 426 {
  427 + NSURL *baseURL;
  428 + if ([dataURICheckbox state] == NSOnState) {
  429 + baseURL = [request url];
  430 +
  431 + // If we're using ASIReplaceExternalResourcesWithLocalURLs, we must set the baseURL to point to our locally cached file
  432 + } else {
  433 + baseURL = [NSURL fileURLWithPath:[request downloadDestinationPath]];
  434 + }
  435 +
429 if ([request downloadDestinationPath]) { 436 if ([request downloadDestinationPath]) {
430 NSString *response = [NSString stringWithContentsOfFile:[request downloadDestinationPath] encoding:[request responseEncoding] error:nil]; 437 NSString *response = [NSString stringWithContentsOfFile:[request downloadDestinationPath] encoding:[request responseEncoding] error:nil];
431 [webPageSource setString:response]; 438 [webPageSource setString:response];
432 - [[webView mainFrame] loadHTMLString:response baseURL:[request url]]; 439 + [[webView mainFrame] loadHTMLString:response baseURL:baseURL];
433 } else { 440 } else {
434 [webPageSource setString:[request responseString]]; 441 [webPageSource setString:[request responseString]];
435 - [[webView mainFrame] loadHTMLString:[request responseString] baseURL:[request url]]; 442 + [[webView mainFrame] loadHTMLString:[request responseString] baseURL:baseURL];
436 } 443 }
437 444
438 [urlField setStringValue:[[request url] absoluteString]]; 445 [urlField setStringValue:[[request url] absoluteString]];
This diff was suppressed by a .gitattributes entry.
@@ -14,5 +14,5 @@ @@ -14,5 +14,5 @@
14 } 14 }
15 + (id)cell; 15 + (id)cell;
16 16
17 -@property (assign, nonatomic) UIProgressView *progressView; 17 +@property (retain, nonatomic) UIProgressView *progressView;
18 @end 18 @end
@@ -22,6 +22,12 @@ @@ -22,6 +22,12 @@
22 return cell; 22 return cell;
23 } 23 }
24 24
  25 +- (void)dealloc
  26 +{
  27 + [progressView release];
  28 + [super dealloc];
  29 +}
  30 +
25 - (void)layoutSubviews 31 - (void)layoutSubviews
26 { 32 {
27 [super layoutSubviews]; 33 [super layoutSubviews];
@@ -32,10 +32,6 @@ @@ -32,10 +32,6 @@
32 32
33 [self setRequestsInProgress:[NSMutableArray array]]; 33 [self setRequestsInProgress:[NSMutableArray array]];
34 [[self tableView] reloadData]; 34 [[self tableView] reloadData];
35 -  
36 - // This allows our ASIDownloadCache to masquerade as as NSURLCache  
37 - // It allows the webView to load the content we downloaded when replaceURLsWithDataURLs is NO  
38 - [NSURLCache setSharedURLCache:[ASIDownloadCache sharedCache]];  
39 35
40 [request setDelegate:nil]; 36 [request setDelegate:nil];
41 [request cancel]; 37 [request cancel];
@@ -46,11 +42,12 @@ @@ -46,11 +42,12 @@
46 [request setDelegate:self]; 42 [request setDelegate:self];
47 [request setDownloadProgressDelegate:self]; 43 [request setDownloadProgressDelegate:self];
48 [request setShowAccurateProgress:NO]; 44 [request setShowAccurateProgress:NO];
49 - [request setReplaceURLsWithDataURLs:[replaceURLsSwitch isOn]]; 45 + [request setUrlReplacementMode:([replaceURLsSwitch isOn] ? ASIReplaceExternalResourcesWithData : ASIReplaceExternalResourcesWithLocalURLs)];
50 46
51 // It is strongly recommended that you set both a downloadCache and a downloadDestinationPath for all ASIWebPageRequests 47 // It is strongly recommended that you set both a downloadCache and a downloadDestinationPath for all ASIWebPageRequests
52 [request setDownloadCache:[ASIDownloadCache sharedCache]]; 48 [request setDownloadCache:[ASIDownloadCache sharedCache]];
53 - [request setDownloadDestinationPath:[[NSHomeDirectory() stringByAppendingPathComponent:@"Documents"] stringByAppendingPathComponent:@"webpage"]]; 49 + [request setCachePolicy:ASIOnlyLoadIfNotCachedCachePolicy];
  50 + [request setDownloadDestinationPath:[[ASIDownloadCache sharedCache] pathToStoreCachedResponseDataForRequest:request]];
54 51
55 [[ASIDownloadCache sharedCache] setShouldRespectCacheControlHeaders:NO]; 52 [[ASIDownloadCache sharedCache] setShouldRespectCacheControlHeaders:NO];
56 [request startAsynchronous]; 53 [request startAsynchronous];
@@ -63,13 +60,22 @@ @@ -63,13 +60,22 @@
63 60
64 - (void)webPageFetchSucceeded:(ASIHTTPRequest *)theRequest 61 - (void)webPageFetchSucceeded:(ASIHTTPRequest *)theRequest
65 { 62 {
  63 + NSURL *baseURL;
  64 + if ([replaceURLsSwitch isOn]) {
  65 + baseURL = [theRequest url];
  66 +
  67 + // If we're using ASIReplaceExternalResourcesWithLocalURLs, we must set the baseURL to point to our locally cached file
  68 + } else {
  69 + baseURL = [NSURL fileURLWithPath:[request downloadDestinationPath]];
  70 + }
  71 +
66 if ([theRequest downloadDestinationPath]) { 72 if ([theRequest downloadDestinationPath]) {
67 NSString *response = [NSString stringWithContentsOfFile:[theRequest downloadDestinationPath] encoding:[theRequest responseEncoding] error:nil]; 73 NSString *response = [NSString stringWithContentsOfFile:[theRequest downloadDestinationPath] encoding:[theRequest responseEncoding] error:nil];
68 [responseField setText:response]; 74 [responseField setText:response];
69 - [webView loadHTMLString:response baseURL:[theRequest url]]; 75 + [webView loadHTMLString:response baseURL:baseURL];
70 } else { 76 } else {
71 [responseField setText:[theRequest responseString]]; 77 [responseField setText:[theRequest responseString]];
72 - [webView loadHTMLString:[theRequest responseString] baseURL:[theRequest url]]; 78 + [webView loadHTMLString:[theRequest responseString] baseURL:baseURL];
73 } 79 }
74 80
75 [urlField setText:[[theRequest url] absoluteString]]; 81 [urlField setText:[[theRequest url] absoluteString]];