Joseph Heenan
Committed by Ben Copsey

Defer cancellation to run on the request thread.

Cancellation ends up addressing runloop objects and CF objects (and also accesses the runloop for the current thread), at least some of which will only work on the thread the request is running on.

For example, cancel calls cancelLoad which calls destroyReadStream which needs to access the runloop for the request for this:

[[self readStream] removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:[self runLoopMode]];
@@ -506,11 +506,14 @@ static NSOperationQueue *sharedQueue = nil; @@ -506,11 +506,14 @@ static NSOperationQueue *sharedQueue = nil;
506 506
507 #pragma mark get information about this request 507 #pragma mark get information about this request
508 508
509 -- (void)cancel 509 +// cancel the request - this must be run on the same thread as the request is running on
  510 +- (void)cancelOnRequestThread
510 { 511 {
511 #if DEBUG_REQUEST_STATUS 512 #if DEBUG_REQUEST_STATUS
512 NSLog(@"Request cancelled: %@",self); 513 NSLog(@"Request cancelled: %@",self);
513 #endif 514 #endif
  515 +
  516 + [self autorelease];
514 517
515 [[self cancelledLock] lock]; 518 [[self cancelledLock] lock];
516 519
@@ -529,6 +532,14 @@ static NSOperationQueue *sharedQueue = nil; @@ -529,6 +532,14 @@ static NSOperationQueue *sharedQueue = nil;
529 [[self cancelledLock] unlock]; 532 [[self cancelledLock] unlock];
530 } 533 }
531 534
  535 +- (void)cancel
  536 +{
  537 + [self retain];
  538 + [self performSelector:@selector(cancelOnRequestThread)
  539 + onThread:[[self class] threadForRequest:self]
  540 + withObject:nil
  541 + waitUntilDone:NO];
  542 +}
532 543
533 // Call this method to get the received data as an NSString. Don't use for binary data! 544 // Call this method to get the received data as an NSString. Don't use for binary data!
534 - (NSString *)responseString 545 - (NSString *)responseString