Ben Copsey

Fix a nasty crash:

* re-order stream schedule/open/setclient
* stop unscheduling stream on complete when using persistent connections
@@ -21,7 +21,7 @@ @@ -21,7 +21,7 @@
21 #import "ASIInputStream.h" 21 #import "ASIInputStream.h"
22 22
23 // Automatically set on build 23 // Automatically set on build
24 -NSString *ASIHTTPRequestVersion = @"v1.5-24 2010-01-14"; 24 +NSString *ASIHTTPRequestVersion = @"v1.5-25 2010-01-18";
25 25
26 NSString* const NetworkRequestErrorDomain = @"ASIHTTPRequestErrorDomain"; 26 NSString* const NetworkRequestErrorDomain = @"ASIHTTPRequestErrorDomain";
27 27
@@ -780,7 +780,6 @@ static BOOL isiPhoneOS2; @@ -780,7 +780,6 @@ static BOOL isiPhoneOS2;
780 // Create the stream for the request 780 // Create the stream for the request
781 [self setReadStreamIsScheduled:NO]; 781 [self setReadStreamIsScheduled:NO];
782 782
783 -  
784 // Do we need to stream the request body from disk 783 // Do we need to stream the request body from disk
785 if ([self shouldStreamPostDataFromDisk] && [self postBodyFilePath] && [[NSFileManager defaultManager] fileExistsAtPath:[self postBodyFilePath]]) { 784 if ([self shouldStreamPostDataFromDisk] && [self postBodyFilePath] && [[NSFileManager defaultManager] fileExistsAtPath:[self postBodyFilePath]]) {
786 785
@@ -965,17 +964,13 @@ static BOOL isiPhoneOS2; @@ -965,17 +964,13 @@ static BOOL isiPhoneOS2;
965 964
966 [connectionsLock unlock]; 965 [connectionsLock unlock];
967 966
968 - BOOL streamSuccessfullyOpened = NO; 967 + // Schedule the stream
969 - 968 + if (![self readStreamIsScheduled] && (!throttleWakeUpTime || [throttleWakeUpTime timeIntervalSinceDate:[NSDate date]] < 0)) {
970 - // Set the client 969 + [self scheduleReadStream];
971 - CFStreamClientContext ctxt = {0, self, NULL, NULL, NULL};  
972 - if (CFReadStreamSetClient((CFReadStreamRef)[self readStream], kNetworkEvents, ReadStreamClientCallBack, &ctxt)) {  
973 - // Start the HTTP connection  
974 - if (CFReadStreamOpen((CFReadStreamRef)[self readStream])) {  
975 - streamSuccessfullyOpened = YES;  
976 - }  
977 } 970 }
978 971
  972 + BOOL streamSuccessfullyOpened = NO;
  973 +
979 // Here, we'll close the stream that was previously using this connection, if there was one 974 // Here, we'll close the stream that was previously using this connection, if there was one
980 // We've kept it open until now (when we've just opened a new stream) so that the new stream can make use of the old connection 975 // We've kept it open until now (when we've just opened a new stream) so that the new stream can make use of the old connection
981 // http://lists.apple.com/archives/Macnetworkprog/2006/Mar/msg00119.html 976 // http://lists.apple.com/archives/Macnetworkprog/2006/Mar/msg00119.html
@@ -988,18 +983,24 @@ static BOOL isiPhoneOS2; @@ -988,18 +983,24 @@ static BOOL isiPhoneOS2;
988 oldStream = nil; 983 oldStream = nil;
989 } 984 }
990 985
  986 + // Set the client
  987 + CFStreamClientContext ctxt = {0, self, NULL, NULL, NULL};
  988 + if (CFReadStreamSetClient((CFReadStreamRef)[self readStream], kNetworkEvents, ReadStreamClientCallBack, &ctxt)) {
  989 + // Start the HTTP connection
  990 + if (CFReadStreamOpen((CFReadStreamRef)[self readStream])) {
  991 + streamSuccessfullyOpened = YES;
  992 + }
  993 + }
  994 +
991 if (!streamSuccessfullyOpened) { 995 if (!streamSuccessfullyOpened) {
  996 + [self setCanUsePersistentConnection:NO];
992 [self destroyReadStream]; 997 [self destroyReadStream];
993 [[self cancelledLock] unlock]; 998 [[self cancelledLock] unlock];
994 [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIInternalErrorWhileBuildingRequestType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Unable to start HTTP connection",NSLocalizedDescriptionKey,nil]]]; 999 [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIInternalErrorWhileBuildingRequestType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Unable to start HTTP connection",NSLocalizedDescriptionKey,nil]]];
995 return; 1000 return;
996 } 1001 }
997 1002
998 - 1003 +
999 - // Schedule the stream  
1000 - if (![self readStreamIsScheduled] && (!throttleWakeUpTime || [throttleWakeUpTime timeIntervalSinceDate:[NSDate date]] < 0)) {  
1001 - [self scheduleReadStream];  
1002 - }  
1003 1004
1004 [[self cancelledLock] unlock]; 1005 [[self cancelledLock] unlock];
1005 1006
@@ -2505,7 +2506,9 @@ static BOOL isiPhoneOS2; @@ -2505,7 +2506,9 @@ static BOOL isiPhoneOS2;
2505 2506
2506 2507
2507 [connectionsLock lock]; 2508 [connectionsLock lock];
2508 - [self unscheduleReadStream]; 2509 + if (![self canUsePersistentConnection]) {
  2510 + [self unscheduleReadStream];
  2511 + }
2509 #if DEBUG_PERSISTENT_CONNECTIONS 2512 #if DEBUG_PERSISTENT_CONNECTIONS
2510 NSLog(@"Request #%@ finished using connection #%@",[[self connectionInfo] objectForKey:@"request"], [[self connectionInfo] objectForKey:@"id"]); 2513 NSLog(@"Request #%@ finished using connection #%@",[[self connectionInfo] objectForKey:@"request"], [[self connectionInfo] objectForKey:@"id"]);
2511 #endif 2514 #endif
@@ -2582,10 +2585,11 @@ static BOOL isiPhoneOS2; @@ -2582,10 +2585,11 @@ static BOOL isiPhoneOS2;
2582 CFReadStreamSetClient((CFReadStreamRef)[self readStream], kCFStreamEventNone, NULL, NULL); 2585 CFReadStreamSetClient((CFReadStreamRef)[self readStream], kCFStreamEventNone, NULL, NULL);
2583 2586
2584 [connectionsLock lock]; 2587 [connectionsLock lock];
2585 - if ([self readStreamIsScheduled]) { 2588 +
2586 - CFReadStreamUnscheduleFromRunLoop((CFReadStreamRef)[self readStream], CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);  
2587 - }  
2588 if (![self canUsePersistentConnection]) { 2589 if (![self canUsePersistentConnection]) {
  2590 + if ([self readStreamIsScheduled]) {
  2591 + CFReadStreamUnscheduleFromRunLoop((CFReadStreamRef)[self readStream], CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
  2592 + }
2589 CFStreamStatus status = CFReadStreamGetStatus((CFReadStreamRef)[self readStream]); 2593 CFStreamStatus status = CFReadStreamGetStatus((CFReadStreamRef)[self readStream]);
2590 if (status != kCFStreamStatusClosed && status != kCFStreamStatusError) { 2594 if (status != kCFStreamStatusClosed && status != kCFStreamStatusError) {
2591 CFReadStreamClose((CFReadStreamRef)[self readStream]); 2595 CFReadStreamClose((CFReadStreamRef)[self readStream]);