* 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!)
Showing
10 changed files
with
118 additions
and
57 deletions
| @@ -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.
| @@ -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]]; |
-
Please register or login to post a comment