Showing
3 changed files
with
103 additions
and
39 deletions
@@ -21,6 +21,7 @@ typedef enum _ASIWebContentType { | @@ -21,6 +21,7 @@ typedef enum _ASIWebContentType { | ||
21 | ASICSSWebContentType = 2 | 21 | ASICSSWebContentType = 2 |
22 | } ASIWebContentType; | 22 | } ASIWebContentType; |
23 | 23 | ||
24 | + | ||
24 | @interface ASIWebPageRequest : ASIHTTPRequest { | 25 | @interface ASIWebPageRequest : ASIHTTPRequest { |
25 | ASINetworkQueue *externalResourceQueue; | 26 | ASINetworkQueue *externalResourceQueue; |
26 | NSMutableDictionary *resourceList; | 27 | NSMutableDictionary *resourceList; |
@@ -31,6 +32,8 @@ typedef enum _ASIWebContentType { | @@ -31,6 +32,8 @@ typedef enum _ASIWebContentType { | ||
31 | ASIWebPageRequest *parentRequest; | 32 | ASIWebPageRequest *parentRequest; |
32 | } | 33 | } |
33 | 34 | ||
35 | +- (NSString *)contentForExternalURL:(NSString *)theURL; | ||
36 | +- (NSString *)cachePathForRequest:(ASIWebPageRequest *)theRequest; | ||
34 | 37 | ||
35 | @property (assign, nonatomic) ASIWebPageRequest *parentRequest; | 38 | @property (assign, nonatomic) ASIWebPageRequest *parentRequest; |
36 | @end | 39 | @end |
@@ -66,8 +66,18 @@ static NSMutableArray *requestsUsingXMLParser = nil; | @@ -66,8 +66,18 @@ static NSMutableArray *requestsUsingXMLParser = nil; | ||
66 | - (void)parseAsCSS | 66 | - (void)parseAsCSS |
67 | { | 67 | { |
68 | webContentType = ASICSSWebContentType; | 68 | webContentType = ASICSSWebContentType; |
69 | - NSString *responseCSS = [self responseString]; | 69 | + |
70 | - if (!responseCSS) { | 70 | + NSString *responseCSS = nil; |
71 | + NSError *err = nil; | ||
72 | + if ([self downloadDestinationPath]) { | ||
73 | + responseCSS = [NSString stringWithContentsOfFile:[self downloadDestinationPath] encoding:[self responseEncoding] error:&err]; | ||
74 | + } else { | ||
75 | + responseCSS = [self responseString]; | ||
76 | + } | ||
77 | + if (err) { | ||
78 | + [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:100 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Unable to read HTML string from response",NSLocalizedDescriptionKey,err,NSUnderlyingErrorKey,nil]]]; | ||
79 | + return; | ||
80 | + } else if (!responseCSS) { | ||
71 | [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:100 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Unable to read HTML string from response",NSLocalizedDescriptionKey,nil]]]; | 81 | [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:100 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Unable to read HTML string from response",NSLocalizedDescriptionKey,nil]]]; |
72 | return; | 82 | return; |
73 | } | 83 | } |
@@ -99,6 +109,9 @@ static NSMutableArray *requestsUsingXMLParser = nil; | @@ -99,6 +109,9 @@ static NSMutableArray *requestsUsingXMLParser = nil; | ||
99 | [externalResourceRequest setUserInfo:[NSDictionary dictionaryWithObject:theURL forKey:@"Path"]]; | 109 | [externalResourceRequest setUserInfo:[NSDictionary dictionaryWithObject:theURL forKey:@"Path"]]; |
100 | [externalResourceRequest setParentRequest:self]; | 110 | [externalResourceRequest setParentRequest:self]; |
101 | [externalResourceRequest setShouldResetDownloadProgress:NO]; | 111 | [externalResourceRequest setShouldResetDownloadProgress:NO]; |
112 | + if ([self downloadDestinationPath]) { | ||
113 | + [externalResourceRequest setDownloadDestinationPath:[self cachePathForRequest:externalResourceRequest]]; | ||
114 | + } | ||
102 | [[self externalResourceQueue] addOperation:externalResourceRequest]; | 115 | [[self externalResourceQueue] addOperation:externalResourceRequest]; |
103 | [externalResourceRequest setShowAccurateProgress:YES]; | 116 | [externalResourceRequest setShowAccurateProgress:YES]; |
104 | } | 117 | } |
@@ -111,20 +124,6 @@ static NSMutableArray *requestsUsingXMLParser = nil; | @@ -111,20 +124,6 @@ static NSMutableArray *requestsUsingXMLParser = nil; | ||
111 | - (void)parseAsHTML | 124 | - (void)parseAsHTML |
112 | { | 125 | { |
113 | webContentType = ASIHTMLWebContentType; | 126 | webContentType = ASIHTMLWebContentType; |
114 | - NSString *responseHTML = [self responseString]; | ||
115 | - if (!responseHTML) { | ||
116 | - [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:100 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Unable to read HTML string from response",NSLocalizedDescriptionKey,nil]]]; | ||
117 | - return; | ||
118 | - } | ||
119 | - | ||
120 | - NSError *err = nil; | ||
121 | - if (err) { | ||
122 | - [self failWithError:err]; | ||
123 | - return; | ||
124 | - } else if (!responseHTML) { | ||
125 | - [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:101 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Unable to convert response string to XHTML",NSLocalizedDescriptionKey,nil]]]; | ||
126 | - return; | ||
127 | - } | ||
128 | 127 | ||
129 | // Only allow parsing of a single document at a time | 128 | // Only allow parsing of a single document at a time |
130 | [xmlParsingLock lock]; | 129 | [xmlParsingLock lock]; |
@@ -134,10 +133,14 @@ static NSMutableArray *requestsUsingXMLParser = nil; | @@ -134,10 +133,14 @@ static NSMutableArray *requestsUsingXMLParser = nil; | ||
134 | } | 133 | } |
135 | [requestsUsingXMLParser addObject:self]; | 134 | [requestsUsingXMLParser addObject:self]; |
136 | 135 | ||
137 | - NSData *data = [responseHTML dataUsingEncoding:[self responseEncoding]]; | ||
138 | 136 | ||
139 | /* Load XML document */ | 137 | /* Load XML document */ |
138 | + if ([self downloadDestinationPath]) { | ||
139 | + doc = htmlReadFile([[self downloadDestinationPath] cStringUsingEncoding:NSUTF8StringEncoding], NULL, HTML_PARSE_NONET | HTML_PARSE_NOWARNING | HTML_PARSE_NOERROR); | ||
140 | + } else { | ||
141 | + NSData *data = [self responseData]; | ||
140 | doc = htmlReadMemory([data bytes], (int)[data length], "", NULL, HTML_PARSE_NONET | HTML_PARSE_NOWARNING | HTML_PARSE_NOERROR); | 142 | doc = htmlReadMemory([data bytes], (int)[data length], "", NULL, HTML_PARSE_NONET | HTML_PARSE_NOWARNING | HTML_PARSE_NOERROR); |
143 | + } | ||
141 | if (doc == NULL) { | 144 | if (doc == NULL) { |
142 | xmlFreeDoc(doc); | 145 | xmlFreeDoc(doc); |
143 | [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:101 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Error: unable to parse reponse XML",NSLocalizedDescriptionKey,nil]]]; | 146 | [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:101 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Error: unable to parse reponse XML",NSLocalizedDescriptionKey,nil]]]; |
@@ -172,6 +175,9 @@ static NSMutableArray *requestsUsingXMLParser = nil; | @@ -172,6 +175,9 @@ static NSMutableArray *requestsUsingXMLParser = nil; | ||
172 | [externalResourceRequest setUserInfo:[NSDictionary dictionaryWithObject:theURL forKey:@"Path"]]; | 175 | [externalResourceRequest setUserInfo:[NSDictionary dictionaryWithObject:theURL forKey:@"Path"]]; |
173 | [externalResourceRequest setParentRequest:self]; | 176 | [externalResourceRequest setParentRequest:self]; |
174 | [externalResourceRequest setShouldResetDownloadProgress:NO]; | 177 | [externalResourceRequest setShouldResetDownloadProgress:NO]; |
178 | + if ([self downloadDestinationPath]) { | ||
179 | + [externalResourceRequest setDownloadDestinationPath:[self cachePathForRequest:externalResourceRequest]]; | ||
180 | + } | ||
175 | [[self externalResourceQueue] addOperation:externalResourceRequest]; | 181 | [[self externalResourceQueue] addOperation:externalResourceRequest]; |
176 | [externalResourceRequest setShowAccurateProgress:YES]; | 182 | [externalResourceRequest setShowAccurateProgress:YES]; |
177 | [self incrementDownloadSizeBy:1]; | 183 | [self incrementDownloadSizeBy:1]; |
@@ -214,7 +220,11 @@ static NSMutableArray *requestsUsingXMLParser = nil; | @@ -214,7 +220,11 @@ static NSMutableArray *requestsUsingXMLParser = nil; | ||
214 | contentType = @"application/octet-stream"; | 220 | contentType = @"application/octet-stream"; |
215 | } | 221 | } |
216 | [requestResponse setObject:contentType forKey:@"ContentType"]; | 222 | [requestResponse setObject:contentType forKey:@"ContentType"]; |
223 | + if ([self downloadDestinationPath]) { | ||
224 | + [requestResponse setObject:[externalResourceRequest downloadDestinationPath] forKey:@"DataPath"]; | ||
225 | + } else { | ||
217 | [requestResponse setObject:[externalResourceRequest responseData] forKey:@"Data"]; | 226 | [requestResponse setObject:[externalResourceRequest responseData] forKey:@"Data"]; |
227 | + } | ||
218 | } | 228 | } |
219 | 229 | ||
220 | - (void)externalResourceFetchFailed:(ASIHTTPRequest *)externalResourceRequest | 230 | - (void)externalResourceFetchFailed:(ASIHTTPRequest *)externalResourceRequest |
@@ -225,35 +235,58 @@ static NSMutableArray *requestsUsingXMLParser = nil; | @@ -225,35 +235,58 @@ static NSMutableArray *requestsUsingXMLParser = nil; | ||
225 | - (void)finishedFetchingExternalResources:(ASINetworkQueue *)queue | 235 | - (void)finishedFetchingExternalResources:(ASINetworkQueue *)queue |
226 | { | 236 | { |
227 | if (webContentType == ASICSSWebContentType) { | 237 | if (webContentType == ASICSSWebContentType) { |
228 | - NSMutableString *parsedResponse = [[[self responseString] mutableCopy] autorelease]; | 238 | + NSMutableString *parsedResponse; |
239 | + NSError *err = nil; | ||
240 | + if ([self downloadDestinationPath]) { | ||
241 | + parsedResponse = [NSMutableString stringWithContentsOfFile:[self downloadDestinationPath] encoding:[self responseEncoding] error:&err]; | ||
242 | + } else { | ||
243 | + parsedResponse = [[[self responseString] mutableCopy] autorelease]; | ||
244 | + } | ||
245 | + if (err) { | ||
246 | + [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:101 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Error: unable to read response CSS from disk",NSLocalizedDescriptionKey,nil]]]; | ||
247 | + return; | ||
248 | + } | ||
229 | if (![self error]) { | 249 | if (![self error]) { |
230 | for (NSString *resource in [[self resourceList] keyEnumerator]) { | 250 | for (NSString *resource in [[self resourceList] keyEnumerator]) { |
231 | - NSDictionary *resourceInfo = [[self resourceList] objectForKey:resource]; | 251 | + if ([parsedResponse rangeOfString:resource].location != NSNotFound) { |
232 | - NSData *data = [resourceInfo objectForKey:@"Data"]; | 252 | + NSString *newURL = [self contentForExternalURL:resource]; |
233 | - NSString *contentType = [resourceInfo objectForKey:@"ContentType"]; | 253 | + if (newURL) { |
234 | - if (data && contentType) { | 254 | + [parsedResponse replaceOccurrencesOfString:resource withString:newURL options:0 range:NSMakeRange(0, [parsedResponse length])]; |
235 | - if (data && contentType) { | ||
236 | - NSString *newData = [NSString stringWithFormat:@"data:%@;base64,",contentType]; | ||
237 | - newData = [newData stringByAppendingString:[ASIHTTPRequest base64forData:data]]; | ||
238 | - [parsedResponse replaceOccurrencesOfString:resource withString:newData options:0 range:NSMakeRange(0, [parsedResponse length])]; | ||
239 | } | 255 | } |
240 | } | 256 | } |
241 | } | 257 | } |
242 | } | 258 | } |
259 | + if ([self downloadDestinationPath]) { | ||
260 | + [parsedResponse writeToFile:[self downloadDestinationPath] atomically:NO encoding:[self responseEncoding] error:&err]; | ||
261 | + if (err) { | ||
262 | + [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:101 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Error: unable to write response CSS to disk",NSLocalizedDescriptionKey,nil]]]; | ||
263 | + return; | ||
264 | + } | ||
265 | + } else { | ||
243 | [self setRawResponseData:(id)[parsedResponse dataUsingEncoding:[self responseEncoding]]]; | 266 | [self setRawResponseData:(id)[parsedResponse dataUsingEncoding:[self responseEncoding]]]; |
244 | - | 267 | + } |
245 | } else { | 268 | } else { |
246 | [xmlParsingLock lock]; | 269 | [xmlParsingLock lock]; |
247 | 270 | ||
248 | [self updateResourceURLs]; | 271 | [self updateResourceURLs]; |
249 | xmlChar *bytes = nil; | 272 | xmlChar *bytes = nil; |
250 | int size = 0; | 273 | int size = 0; |
274 | + FILE *file = NULL; | ||
275 | + if ([self downloadDestinationPath]) { | ||
276 | + file = fdopen([[NSFileHandle fileHandleForWritingAtPath:[self downloadDestinationPath]] fileDescriptor], "w"); | ||
277 | + xmlDocDump(file, doc); | ||
278 | + } else { | ||
251 | xmlDocDumpMemory(doc,&bytes,&size); | 279 | xmlDocDumpMemory(doc,&bytes,&size); |
252 | [self setRawResponseData:[[[NSMutableData alloc] initWithBytes:bytes length:size] autorelease]]; | 280 | [self setRawResponseData:[[[NSMutableData alloc] initWithBytes:bytes length:size] autorelease]]; |
281 | + } | ||
253 | 282 | ||
254 | xmlFreeDoc(doc); | 283 | xmlFreeDoc(doc); |
255 | doc = nil; | 284 | doc = nil; |
256 | 285 | ||
286 | + if (file) { | ||
287 | + fclose(file); | ||
288 | + } | ||
289 | + | ||
257 | [requestsUsingXMLParser removeObject:self]; | 290 | [requestsUsingXMLParser removeObject:self]; |
258 | if (![requestsUsingXMLParser count]) { | 291 | if (![requestsUsingXMLParser count]) { |
259 | xmlCleanupParser(); | 292 | xmlCleanupParser(); |
@@ -374,22 +407,18 @@ static NSMutableArray *requestsUsingXMLParser = nil; | @@ -374,22 +407,18 @@ static NSMutableArray *requestsUsingXMLParser = nil; | ||
374 | if ([[nodeName lowercaseString] isEqualToString:@"style"]) { | 407 | if ([[nodeName lowercaseString] isEqualToString:@"style"]) { |
375 | NSArray *externalResources = [[self class] CSSURLsFromString:value]; | 408 | NSArray *externalResources = [[self class] CSSURLsFromString:value]; |
376 | for (NSString *theURL in externalResources) { | 409 | for (NSString *theURL in externalResources) { |
377 | - NSData *data = [[resourceList objectForKey:theURL] objectForKey:@"Data"]; | 410 | + if ([value rangeOfString:theURL].location != NSNotFound) { |
378 | - NSString *contentType = [[resourceList objectForKey:theURL] objectForKey:@"ContentType"]; | 411 | + NSString *newURL = [self contentForExternalURL:theURL]; |
379 | - if (data && contentType) { | 412 | + if (newURL) { |
380 | - NSString *newData = [NSString stringWithFormat:@"data:%@;base64,",contentType]; | 413 | + value = [value stringByReplacingOccurrencesOfString:theURL withString:newURL]; |
381 | - newData = [newData stringByAppendingString:[ASIHTTPRequest base64forData:data]]; | 414 | + } |
382 | - value = [value stringByReplacingOccurrencesOfString:theURL withString:newData]; | ||
383 | } | 415 | } |
384 | } | 416 | } |
385 | xmlNodeSetContent(nodes->nodeTab[i], (xmlChar *)[value cStringUsingEncoding:[self responseEncoding]]); | 417 | xmlNodeSetContent(nodes->nodeTab[i], (xmlChar *)[value cStringUsingEncoding:[self responseEncoding]]); |
386 | } else { | 418 | } else { |
387 | - NSData *data = [[resourceList objectForKey:value] objectForKey:@"Data"]; | 419 | + NSString *newURL = [self contentForExternalURL:value]; |
388 | - NSString *contentType = [[resourceList objectForKey:value] objectForKey:@"ContentType"]; | 420 | + if (newURL) { |
389 | - if (data && contentType) { | 421 | + xmlNodeSetContent(nodes->nodeTab[i], (xmlChar *)[newURL cStringUsingEncoding:[self responseEncoding]]); |
390 | - NSString *newData = [NSString stringWithFormat:@"data:%@;base64,",contentType]; | ||
391 | - newData = [newData stringByAppendingString:[ASIHTTPRequest base64forData:data]]; | ||
392 | - xmlNodeSetContent(nodes->nodeTab[i], (xmlChar *)[newData cStringUsingEncoding:[self responseEncoding]]); | ||
393 | } | 422 | } |
394 | } | 423 | } |
395 | 424 | ||
@@ -423,6 +452,30 @@ static NSMutableArray *requestsUsingXMLParser = nil; | @@ -423,6 +452,30 @@ static NSMutableArray *requestsUsingXMLParser = nil; | ||
423 | return urls; | 452 | return urls; |
424 | } | 453 | } |
425 | 454 | ||
455 | +- (NSString *)contentForExternalURL:(NSString *)theURL | ||
456 | +{ | ||
457 | + NSData *data; | ||
458 | + if ([[resourceList objectForKey:theURL] objectForKey:@"DataPath"]) { | ||
459 | + data = [NSData dataWithContentsOfFile:[[resourceList objectForKey:theURL] objectForKey:@"DataPath"]]; | ||
460 | + } else { | ||
461 | + data = [[resourceList objectForKey:theURL] objectForKey:@"Data"]; | ||
462 | + } | ||
463 | + NSString *contentType = [[resourceList objectForKey:theURL] objectForKey:@"ContentType"]; | ||
464 | + if (data && contentType) { | ||
465 | + NSString *dataURI = [NSString stringWithFormat:@"data:%@;base64,",contentType]; | ||
466 | + dataURI = [dataURI stringByAppendingString:[ASIHTTPRequest base64forData:data]]; | ||
467 | + return dataURI; | ||
468 | + } | ||
469 | + return nil; | ||
470 | +} | ||
471 | + | ||
472 | +static int resourceNum = 0; | ||
473 | +- (NSString *)cachePathForRequest:(ASIWebPageRequest *)theRequest | ||
474 | +{ | ||
475 | + resourceNum++; | ||
476 | + return [NSString stringWithFormat:@"/Users/ben/Desktop/%i",resourceNum]; | ||
477 | +} | ||
478 | + | ||
426 | @synthesize externalResourceQueue; | 479 | @synthesize externalResourceQueue; |
427 | @synthesize resourceList; | 480 | @synthesize resourceList; |
428 | @synthesize parentRequest; | 481 | @synthesize parentRequest; |
@@ -406,6 +406,7 @@ | @@ -406,6 +406,7 @@ | ||
406 | [request setShowAccurateProgress:NO]; | 406 | [request setShowAccurateProgress:NO]; |
407 | [request setDownloadProgressDelegate:progressIndicator]; | 407 | [request setDownloadProgressDelegate:progressIndicator]; |
408 | [request setDownloadCache:[ASIDownloadCache sharedCache]]; | 408 | [request setDownloadCache:[ASIDownloadCache sharedCache]]; |
409 | + [request setDownloadDestinationPath:@"/Users/ben/Desktop/fink"]; | ||
409 | [[ASIDownloadCache sharedCache] setDefaultCachePolicy:ASIOnlyLoadIfNotCachedCachePolicy]; | 410 | [[ASIDownloadCache sharedCache] setDefaultCachePolicy:ASIOnlyLoadIfNotCachedCachePolicy]; |
410 | [[ASIDownloadCache sharedCache] setShouldRespectCacheControlHeaders:NO]; | 411 | [[ASIDownloadCache sharedCache] setShouldRespectCacheControlHeaders:NO]; |
411 | [request startAsynchronous]; | 412 | [request startAsynchronous]; |
@@ -418,8 +419,15 @@ | @@ -418,8 +419,15 @@ | ||
418 | 419 | ||
419 | - (void)webPageFetchSucceeded:(ASIHTTPRequest *)request | 420 | - (void)webPageFetchSucceeded:(ASIHTTPRequest *)request |
420 | { | 421 | { |
422 | + if ([request downloadDestinationPath]) { | ||
423 | + NSString *response = [NSString stringWithContentsOfFile:[request downloadDestinationPath] encoding:[request responseEncoding] error:nil]; | ||
424 | + [webPageSource setString:response]; | ||
425 | + [[webView mainFrame] loadHTMLString:response baseURL:[request url]]; | ||
426 | + } else { | ||
421 | [webPageSource setString:[request responseString]]; | 427 | [webPageSource setString:[request responseString]]; |
422 | [[webView mainFrame] loadHTMLString:[request responseString] baseURL:[request url]]; | 428 | [[webView mainFrame] loadHTMLString:[request responseString] baseURL:[request url]]; |
429 | + } | ||
430 | + | ||
423 | [urlField setStringValue:[[request url] absoluteString]]; | 431 | [urlField setStringValue:[[request url] absoluteString]]; |
424 | } | 432 | } |
425 | 433 |
-
Please register or login to post a comment