Ben Copsey

Fix leaks in ASIWebPageRequest

@@ -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-129 2010-11-07"; 27 +NSString *ASIHTTPRequestVersion = @"v1.7-131 2010-11-07";
28 28
29 NSString* const NetworkRequestErrorDomain = @"ASIHTTPRequestErrorDomain"; 29 NSString* const NetworkRequestErrorDomain = @"ASIHTTPRequestErrorDomain";
30 30
@@ -42,6 +42,9 @@ static NSMutableArray *requestsUsingXMLParser = nil; @@ -42,6 +42,9 @@ static NSMutableArray *requestsUsingXMLParser = nil;
42 42
43 - (void)dealloc 43 - (void)dealloc
44 { 44 {
  45 + [externalResourceQueue cancelAllOperations];
  46 + [externalResourceQueue release];
  47 + [resourceList release];
45 [parentRequest release]; 48 [parentRequest release];
46 [super dealloc]; 49 [super dealloc];
47 } 50 }
@@ -158,7 +161,6 @@ static NSMutableArray *requestsUsingXMLParser = nil; @@ -158,7 +161,6 @@ static NSMutableArray *requestsUsingXMLParser = nil;
158 doc = htmlReadMemory([data bytes], (int)[data length], "", NULL, HTML_PARSE_NONET | HTML_PARSE_NOWARNING | HTML_PARSE_NOERROR); 161 doc = htmlReadMemory([data bytes], (int)[data length], "", NULL, HTML_PARSE_NONET | HTML_PARSE_NOWARNING | HTML_PARSE_NOERROR);
159 } 162 }
160 if (doc == NULL) { 163 if (doc == NULL) {
161 - xmlFreeDoc(doc);  
162 [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:101 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Error: unable to parse reponse XML",NSLocalizedDescriptionKey,nil]]]; 164 [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:101 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Error: unable to parse reponse XML",NSLocalizedDescriptionKey,nil]]];
163 return; 165 return;
164 } 166 }
@@ -168,9 +170,17 @@ static NSMutableArray *requestsUsingXMLParser = nil; @@ -168,9 +170,17 @@ static NSMutableArray *requestsUsingXMLParser = nil;
168 // Populate the list of URLS to download 170 // Populate the list of URLS to download
169 [self readResourceURLs]; 171 [self readResourceURLs];
170 172
  173 + if ([self error] || ![[self resourceList] count]) {
  174 + [requestsUsingXMLParser removeObject:self];
  175 + xmlFreeDoc(doc);
  176 + doc = NULL;
  177 + }
  178 +
171 [xmlParsingLock unlock]; 179 [xmlParsingLock unlock];
172 180
173 - if (![[self resourceList] count]) { 181 + if ([self error]) {
  182 + return;
  183 + } else if (![[self resourceList] count]) {
174 [super requestFinished]; 184 [super requestFinished];
175 [super markAsFinished]; 185 [super markAsFinished];
176 return; 186 return;
@@ -268,37 +278,39 @@ static NSMutableArray *requestsUsingXMLParser = nil; @@ -268,37 +278,39 @@ static NSMutableArray *requestsUsingXMLParser = nil;
268 278
269 [self updateResourceURLs]; 279 [self updateResourceURLs];
270 280
  281 + if (![self error]) {
271 282
272 - // We'll use the xmlsave API so we can strip the xml declaration 283 + // We'll use the xmlsave API so we can strip the xml declaration
273 - xmlSaveCtxtPtr saveContext; 284 + xmlSaveCtxtPtr saveContext;
274 - 285 +
275 - if ([self downloadDestinationPath]) { 286 + if ([self downloadDestinationPath]) {
276 - saveContext = xmlSaveToFd([[NSFileHandle fileHandleForWritingAtPath:[self downloadDestinationPath]] fileDescriptor],NULL,2); // 2 == XML_SAVE_NO_DECL, this isn't declared on Mac OS 10.5 287 + saveContext = xmlSaveToFd([[NSFileHandle fileHandleForWritingAtPath:[self downloadDestinationPath]] fileDescriptor],NULL,2); // 2 == XML_SAVE_NO_DECL, this isn't declared on Mac OS 10.5
277 - xmlSaveDoc(saveContext, doc); 288 + xmlSaveDoc(saveContext, doc);
278 - xmlSaveClose(saveContext); 289 + xmlSaveClose(saveContext);
  290 +
  291 + } else {
  292 + #if TARGET_OS_MAC && MAC_OS_X_VERSION_MAX_ALLOWED <= __MAC_10_5
  293 + // xmlSaveToBuffer() is not implemented in the 10.5 version of libxml
  294 + NSString *tempPath = [NSTemporaryDirectory() stringByAppendingPathComponent:[[NSProcessInfo processInfo] globallyUniqueString]];
  295 + [[NSFileManager defaultManager] createFileAtPath:tempPath contents:nil attributes:nil];
  296 + saveContext = xmlSaveToFd([[NSFileHandle fileHandleForWritingAtPath:tempPath] fileDescriptor],NULL,2); // 2 == XML_SAVE_NO_DECL, this isn't declared on Mac OS 10.5
  297 + xmlSaveDoc(saveContext, doc);
  298 + xmlSaveClose(saveContext);
  299 + [self setRawResponseData:[NSMutableData dataWithContentsOfFile:tempPath]];
  300 + #else
  301 + xmlBufferPtr buffer = xmlBufferCreate();
  302 + saveContext = xmlSaveToBuffer(buffer,NULL,2); // 2 == XML_SAVE_NO_DECL, this isn't declared on Mac OS 10.5
  303 + xmlSaveDoc(saveContext, doc);
  304 + xmlSaveClose(saveContext);
  305 + [self setRawResponseData:[[[NSMutableData alloc] initWithBytes:buffer->content length:buffer->use] autorelease]];
  306 + xmlBufferFree(buffer);
  307 + #endif
  308 + }
279 309
280 - } else { 310 + // libxml will generate UTF-8
281 -#if TARGET_OS_MAC && MAC_OS_X_VERSION_MAX_ALLOWED <= __MAC_10_5 311 + [self setResponseEncoding:NSUTF8StringEncoding];
282 - // xmlSaveToBuffer() is not implemented in the 10.5 version of libxml  
283 - NSString *tempPath = [NSTemporaryDirectory() stringByAppendingPathComponent:[[NSProcessInfo processInfo] globallyUniqueString]];  
284 - [[NSFileManager defaultManager] createFileAtPath:tempPath contents:nil attributes:nil];  
285 - saveContext = xmlSaveToFd([[NSFileHandle fileHandleForWritingAtPath:tempPath] fileDescriptor],NULL,2); // 2 == XML_SAVE_NO_DECL, this isn't declared on Mac OS 10.5  
286 - xmlSaveDoc(saveContext, doc);  
287 - xmlSaveClose(saveContext);  
288 - [self setRawResponseData:[NSMutableData dataWithContentsOfFile:tempPath]];  
289 -#else  
290 - xmlBufferPtr buffer = xmlBufferCreate();  
291 - saveContext = xmlSaveToBuffer(buffer,NULL,2); // 2 == XML_SAVE_NO_DECL, this isn't declared on Mac OS 10.5  
292 - xmlSaveDoc(saveContext, doc);  
293 - xmlSaveClose(saveContext);  
294 - [self setRawResponseData:[[[NSMutableData alloc] initWithBytes:buffer->content length:buffer->use] autorelease]];  
295 - xmlBufferFree(buffer);  
296 -#endif  
297 } 312 }
298 313
299 - // libxml will generate UTF-8  
300 - [self setResponseEncoding:NSUTF8StringEncoding];  
301 -  
302 xmlFreeDoc(doc); 314 xmlFreeDoc(doc);
303 doc = nil; 315 doc = nil;
304 316
@@ -339,7 +351,6 @@ static NSMutableArray *requestsUsingXMLParser = nil; @@ -339,7 +351,6 @@ static NSMutableArray *requestsUsingXMLParser = nil;
339 xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression(xpathExpr, xpathCtx); 351 xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression(xpathExpr, xpathCtx);
340 if(xpathObj == NULL) { 352 if(xpathObj == NULL) {
341 xmlXPathFreeContext(xpathCtx); 353 xmlXPathFreeContext(xpathCtx);
342 - xmlFreeDoc(doc);  
343 [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:101 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Error: unable to evaluate XPath expression!",NSLocalizedDescriptionKey,nil]]]; 354 [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:101 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Error: unable to evaluate XPath expression!",NSLocalizedDescriptionKey,nil]]];
344 return; 355 return;
345 } 356 }
@@ -353,14 +364,21 @@ static NSMutableArray *requestsUsingXMLParser = nil; @@ -353,14 +364,21 @@ static NSMutableArray *requestsUsingXMLParser = nil;
353 assert(nodes->nodeTab[i]); 364 assert(nodes->nodeTab[i]);
354 NSString *parentName = [NSString stringWithCString:(char *)nodes->nodeTab[i]->parent->name encoding:[self responseEncoding]]; 365 NSString *parentName = [NSString stringWithCString:(char *)nodes->nodeTab[i]->parent->name encoding:[self responseEncoding]];
355 NSString *nodeName = [NSString stringWithCString:(char *)nodes->nodeTab[i]->name encoding:[self responseEncoding]]; 366 NSString *nodeName = [NSString stringWithCString:(char *)nodes->nodeTab[i]->name encoding:[self responseEncoding]];
356 - NSString *value = [NSString stringWithCString:(char *)xmlNodeGetContent(nodes->nodeTab[i]) encoding:[self responseEncoding]]; 367 +
  368 + xmlChar *nodeValue = xmlNodeGetContent(nodes->nodeTab[i]);
  369 + NSString *value = [NSString stringWithCString:(char *)nodeValue encoding:[self responseEncoding]];
  370 + xmlFree(nodeValue);
357 371
358 // Our xpath query matched all <link> elements, but we're only interested in stylesheets 372 // Our xpath query matched all <link> elements, but we're only interested in stylesheets
359 // We do the work here rather than in the xPath query because the query is case-sensitive, and we want to match on 'stylesheet', 'StyleSHEEt' etc 373 // We do the work here rather than in the xPath query because the query is case-sensitive, and we want to match on 'stylesheet', 'StyleSHEEt' etc
360 if ([[parentName lowercaseString] isEqualToString:@"link"]) { 374 if ([[parentName lowercaseString] isEqualToString:@"link"]) {
361 - NSString *rel = [NSString stringWithCString:(char *)xmlGetNoNsProp(nodes->nodeTab[i]->parent,(xmlChar *)"rel") encoding:[self responseEncoding]]; 375 + xmlChar *relAttribute = xmlGetNoNsProp(nodes->nodeTab[i]->parent,(xmlChar *)"rel");
362 - if ([[rel lowercaseString] isEqualToString:@"stylesheet"]) { 376 + if (relAttribute) {
363 - [self addURLToFetch:value]; 377 + NSString *rel = [NSString stringWithCString:(char *)relAttribute encoding:[self responseEncoding]];
  378 + xmlFree(relAttribute);
  379 + if ([[rel lowercaseString] isEqualToString:@"stylesheet"]) {
  380 + [self addURLToFetch:value];
  381 + }
364 } 382 }
365 383
366 // Parse the content of <style> tags and style attributes to find external image urls or external css files 384 // Parse the content of <style> tags and style attributes to find external image urls or external css files
@@ -414,7 +432,6 @@ static NSMutableArray *requestsUsingXMLParser = nil; @@ -414,7 +432,6 @@ static NSMutableArray *requestsUsingXMLParser = nil;
414 // Create xpath evaluation context 432 // Create xpath evaluation context
415 xmlXPathContextPtr xpathCtx = xmlXPathNewContext(doc); 433 xmlXPathContextPtr xpathCtx = xmlXPathNewContext(doc);
416 if(xpathCtx == NULL) { 434 if(xpathCtx == NULL) {
417 - xmlFreeDoc(doc);  
418 [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:101 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Error: unable to create new XPath context",NSLocalizedDescriptionKey,nil]]]; 435 [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:101 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Error: unable to create new XPath context",NSLocalizedDescriptionKey,nil]]];
419 return; 436 return;
420 } 437 }
@@ -423,7 +440,6 @@ static NSMutableArray *requestsUsingXMLParser = nil; @@ -423,7 +440,6 @@ static NSMutableArray *requestsUsingXMLParser = nil;
423 xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression(xpathExpr, xpathCtx); 440 xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression(xpathExpr, xpathCtx);
424 if(xpathObj == NULL) { 441 if(xpathObj == NULL) {
425 xmlXPathFreeContext(xpathCtx); 442 xmlXPathFreeContext(xpathCtx);
426 - xmlFreeDoc(doc);  
427 [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:101 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Error: unable to evaluate XPath expression!",NSLocalizedDescriptionKey,nil]]]; 443 [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:101 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Error: unable to evaluate XPath expression!",NSLocalizedDescriptionKey,nil]]];
428 return; 444 return;
429 } 445 }
@@ -436,7 +452,10 @@ static NSMutableArray *requestsUsingXMLParser = nil; @@ -436,7 +452,10 @@ static NSMutableArray *requestsUsingXMLParser = nil;
436 assert(nodes->nodeTab[i]); 452 assert(nodes->nodeTab[i]);
437 NSString *parentName = [NSString stringWithCString:(char *)nodes->nodeTab[i]->parent->name encoding:[self responseEncoding]]; 453 NSString *parentName = [NSString stringWithCString:(char *)nodes->nodeTab[i]->parent->name encoding:[self responseEncoding]];
438 NSString *nodeName = [NSString stringWithCString:(char *)nodes->nodeTab[i]->name encoding:[self responseEncoding]]; 454 NSString *nodeName = [NSString stringWithCString:(char *)nodes->nodeTab[i]->name encoding:[self responseEncoding]];
439 - NSString *value = [NSString stringWithCString:(char *)xmlNodeGetContent(nodes->nodeTab[i]) encoding:[self responseEncoding]]; 455 +
  456 + xmlChar *nodeValue = xmlNodeGetContent(nodes->nodeTab[i]);
  457 + NSString *value = [NSString stringWithCString:(char *)nodeValue encoding:[self responseEncoding]];
  458 + xmlFree(nodeValue);
440 459
441 // Replace external urls in <style> tags or in style attributes 460 // Replace external urls in <style> tags or in style attributes
442 if ([[nodeName lowercaseString] isEqualToString:@"style"]) { 461 if ([[nodeName lowercaseString] isEqualToString:@"style"]) {