Ben Copsey

Change timer behaviour to prevent endless recursion

Stop running runloop in checkRequestStatus, it's not nescessary and it meant we were updating progress every 0.5 secs rather than every 0.25 secs
Remove authenticationLock, delegate-style auth is now non-blocking
Requests on standard run loop
@@ -228,9 +228,6 @@ extern unsigned long const ASIWWANBandwidthThrottleAmount; @@ -228,9 +228,6 @@ extern unsigned long const ASIWWANBandwidthThrottleAmount;
228 // Last amount of data sent (used for incrementing progress) 228 // Last amount of data sent (used for incrementing progress)
229 unsigned long long lastBytesSent; 229 unsigned long long lastBytesSent;
230 230
231 - // This lock will block the request until the delegate supplies authentication info  
232 - NSConditionLock *authenticationLock;  
233 -  
234 // This lock prevents the operation from being cancelled at an inopportune moment 231 // This lock prevents the operation from being cancelled at an inopportune moment
235 NSRecursiveLock *cancelledLock; 232 NSRecursiveLock *cancelledLock;
236 233
@@ -20,10 +20,6 @@ @@ -20,10 +20,6 @@
20 #endif 20 #endif
21 #import "ASIInputStream.h" 21 #import "ASIInputStream.h"
22 22
23 -  
24 -// We use our own custom run loop mode as CoreAnimation seems to want to hijack our threads otherwise  
25 -static CFStringRef ASIHTTPRequestRunMode = CFSTR("ASIHTTPRequest");  
26 -  
27 NSString* const NetworkRequestErrorDomain = @"ASIHTTPRequestErrorDomain"; 23 NSString* const NetworkRequestErrorDomain = @"ASIHTTPRequestErrorDomain";
28 24
29 static const CFOptionFlags kNetworkEvents = kCFStreamEventOpenCompleted | kCFStreamEventHasBytesAvailable | kCFStreamEventEndEncountered | kCFStreamEventErrorOccurred; 25 static const CFOptionFlags kNetworkEvents = kCFStreamEventOpenCompleted | kCFStreamEventHasBytesAvailable | kCFStreamEventEndEncountered | kCFStreamEventErrorOccurred;
@@ -134,7 +130,6 @@ static BOOL isiPhoneOS2; @@ -134,7 +130,6 @@ static BOOL isiPhoneOS2;
134 @property (assign, nonatomic) int redirectCount; 130 @property (assign, nonatomic) int redirectCount;
135 @property (retain, nonatomic) NSData *compressedPostBody; 131 @property (retain, nonatomic) NSData *compressedPostBody;
136 @property (retain, nonatomic) NSString *compressedPostBodyFilePath; 132 @property (retain, nonatomic) NSString *compressedPostBodyFilePath;
137 -@property (retain) NSConditionLock *authenticationLock;  
138 @property (retain) NSString *authenticationRealm; 133 @property (retain) NSString *authenticationRealm;
139 @property (retain) NSString *proxyAuthenticationRealm; 134 @property (retain) NSString *proxyAuthenticationRealm;
140 @property (retain) NSString *responseStatusMessage; 135 @property (retain) NSString *responseStatusMessage;
@@ -240,7 +235,6 @@ static BOOL isiPhoneOS2; @@ -240,7 +235,6 @@ static BOOL isiPhoneOS2;
240 [proxyAuthenticationScheme release]; 235 [proxyAuthenticationScheme release];
241 [proxyCredentials release]; 236 [proxyCredentials release];
242 [url release]; 237 [url release];
243 - [authenticationLock release];  
244 [lastActivityTime release]; 238 [lastActivityTime release];
245 [responseCookies release]; 239 [responseCookies release];
246 [rawResponseData release]; 240 [rawResponseData release];
@@ -722,8 +716,6 @@ static BOOL isiPhoneOS2; @@ -722,8 +716,6 @@ static BOOL isiPhoneOS2;
722 716
723 [self requestStarted]; 717 [self requestStarted];
724 718
725 - [self setAuthenticationLock:[[[NSConditionLock alloc] initWithCondition:1] autorelease]];  
726 -  
727 [self setComplete:NO]; 719 [self setComplete:NO];
728 [self setTotalBytesRead:0]; 720 [self setTotalBytesRead:0];
729 [self setLastBytesRead:0]; 721 [self setLastBytesRead:0];
@@ -850,12 +842,12 @@ static BOOL isiPhoneOS2; @@ -850,12 +842,12 @@ static BOOL isiPhoneOS2;
850 } 842 }
851 843
852 // Schedule the stream 844 // Schedule the stream
853 - CFReadStreamScheduleWithRunLoop(readStream, CFRunLoopGetCurrent(), ASIHTTPRequestRunMode); 845 + CFReadStreamScheduleWithRunLoop(readStream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
854 846
855 // Start the HTTP connection 847 // Start the HTTP connection
856 if (!CFReadStreamOpen(readStream)) { 848 if (!CFReadStreamOpen(readStream)) {
857 CFReadStreamSetClient(readStream, 0, NULL, NULL); 849 CFReadStreamSetClient(readStream, 0, NULL, NULL);
858 - CFReadStreamUnscheduleFromRunLoop(readStream, CFRunLoopGetCurrent(), ASIHTTPRequestRunMode); 850 + CFReadStreamUnscheduleFromRunLoop(readStream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
859 CFRelease(readStream); 851 CFRelease(readStream);
860 readStream = NULL; 852 readStream = NULL;
861 [[self cancelledLock] unlock]; 853 [[self cancelledLock] unlock];
@@ -884,12 +876,12 @@ static BOOL isiPhoneOS2; @@ -884,12 +876,12 @@ static BOOL isiPhoneOS2;
884 876
885 - (void)loadAsynchronous 877 - (void)loadAsynchronous
886 { 878 {
887 - [NSTimer scheduledTimerWithTimeInterval:0.25 target:self selector:@selector(updateStatus:) userInfo:nil repeats:NO]; 879 + [NSTimer scheduledTimerWithTimeInterval:0.25 target:self selector:@selector(updateStatus:) userInfo:nil repeats:YES];
888 880
889 // If we're running asynchronously on the main thread, the runloop will already be running 881 // If we're running asynchronously on the main thread, the runloop will already be running
890 if (![NSThread isMainThread]) { 882 if (![NSThread isMainThread]) {
891 // Will stop automatically when the request is done 883 // Will stop automatically when the request is done
892 - CFRunLoopRun(); 884 + CFRunLoopRun();
893 } 885 }
894 } 886 }
895 887
@@ -899,7 +891,7 @@ static BOOL isiPhoneOS2; @@ -899,7 +891,7 @@ static BOOL isiPhoneOS2;
899 { 891 {
900 while (!complete) { 892 while (!complete) {
901 [self checkRequestStatus]; 893 [self checkRequestStatus];
902 - CFRunLoopRunInMode(ASIHTTPRequestRunMode, 0.25, NO); 894 + CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.25, NO);
903 } 895 }
904 } 896 }
905 897
@@ -908,10 +900,9 @@ static BOOL isiPhoneOS2; @@ -908,10 +900,9 @@ static BOOL isiPhoneOS2;
908 { 900 {
909 [self checkRequestStatus]; 901 [self checkRequestStatus];
910 if ([self complete] || [self error]) { 902 if ([self complete] || [self error]) {
  903 + [timer invalidate];
911 [self willChangeValueForKey:@"isFinished"]; 904 [self willChangeValueForKey:@"isFinished"];
912 [self didChangeValueForKey:@"isFinished"]; 905 [self didChangeValueForKey:@"isFinished"];
913 - } else {  
914 - [self loadAsynchronous];  
915 } 906 }
916 } 907 }
917 908
@@ -962,26 +953,27 @@ static BOOL isiPhoneOS2; @@ -962,26 +953,27 @@ static BOOL isiPhoneOS2;
962 return; 953 return;
963 } 954 }
964 955
  956 + // readStream will be null if we aren't currently running (perhaps we're waiting for a delegate to supply credentials)
965 if (readStream) { 957 if (readStream) {
  958 +
  959 + // Find out if we've sent any more data than last time, and reset the timeout if so
  960 + if (totalBytesSent > lastBytesSent) {
  961 + [self setLastActivityTime:[NSDate date]];
  962 + [self setLastBytesSent:totalBytesSent];
  963 + }
966 964
967 - // Find out if we've sent any more data than last time, and reset the timeout if so 965 + // Find out how much data we've uploaded so far
968 - if (totalBytesSent > lastBytesSent) { 966 + [self setTotalBytesSent:[[(NSNumber *)CFReadStreamCopyProperty(readStream, kCFStreamPropertyHTTPRequestBytesWrittenCount) autorelease] unsignedLongLongValue]];
969 - [self setLastActivityTime:[NSDate date]]; 967 +
970 - [self setLastBytesSent:totalBytesSent]; 968 +
971 - } 969 + [self updateProgressIndicators];
972 - 970 +
973 - // Find out how much data we've uploaded so far 971 + // Measure bandwidth used, and throttle if nescessary
974 - [self setTotalBytesSent:[[(NSNumber *)CFReadStreamCopyProperty(readStream, kCFStreamPropertyHTTPRequestBytesWrittenCount) autorelease] unsignedLongLongValue]]; 972 + [ASIHTTPRequest measureBandwidthUsage];
975 -  
976 -  
977 - [self updateProgressIndicators];  
978 -  
979 - // Measure bandwidth used, and throttle if nescessary  
980 - [ASIHTTPRequest measureBandwidthUsage];  
981 } 973 }
982 974
983 // This thread should wait for 1/4 second for the stream to do something 975 // This thread should wait for 1/4 second for the stream to do something
984 - CFRunLoopRunInMode(ASIHTTPRequestRunMode,0.25,NO); 976 + //CFRunLoopRunInMode(kCFRunLoopDefaultMode,0.25,NO);
985 977
986 978
987 [[self cancelledLock] unlock]; 979 [[self cancelledLock] unlock];
@@ -993,7 +985,7 @@ static BOOL isiPhoneOS2; @@ -993,7 +985,7 @@ static BOOL isiPhoneOS2;
993 { 985 {
994 if (readStream) { 986 if (readStream) {
995 CFReadStreamSetClient(readStream, kCFStreamEventNone, NULL, NULL); 987 CFReadStreamSetClient(readStream, kCFStreamEventNone, NULL, NULL);
996 - CFReadStreamUnscheduleFromRunLoop(readStream, CFRunLoopGetCurrent(), ASIHTTPRequestRunMode); 988 + CFReadStreamUnscheduleFromRunLoop(readStream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
997 CFReadStreamClose(readStream); 989 CFReadStreamClose(readStream);
998 CFRelease(readStream); 990 CFRelease(readStream);
999 readStream = NULL; 991 readStream = NULL;
@@ -1750,8 +1742,6 @@ static BOOL isiPhoneOS2; @@ -1750,8 +1742,6 @@ static BOOL isiPhoneOS2;
1750 - (void)cancelAuthentication 1742 - (void)cancelAuthentication
1751 { 1743 {
1752 [self failWithError:ASIAuthenticationError]; 1744 [self failWithError:ASIAuthenticationError];
1753 - [[self authenticationLock] lockWhenCondition:1];  
1754 - [[self authenticationLock] unlockWithCondition:2];  
1755 } 1745 }
1756 1746
1757 - (BOOL)showProxyAuthenticationDialog 1747 - (BOOL)showProxyAuthenticationDialog
@@ -1761,11 +1751,6 @@ static BOOL isiPhoneOS2; @@ -1761,11 +1751,6 @@ static BOOL isiPhoneOS2;
1761 // Cannot show the dialog when we are running on the main thread, as the locks will cause the app to hang 1751 // Cannot show the dialog when we are running on the main thread, as the locks will cause the app to hang
1762 if ([self shouldPresentProxyAuthenticationDialog] && ![NSThread isMainThread]) { 1752 if ([self shouldPresentProxyAuthenticationDialog] && ![NSThread isMainThread]) {
1763 [ASIAuthenticationDialog performSelectorOnMainThread:@selector(presentProxyAuthenticationDialogForRequest:) withObject:self waitUntilDone:[NSThread isMainThread]]; 1753 [ASIAuthenticationDialog performSelectorOnMainThread:@selector(presentProxyAuthenticationDialogForRequest:) withObject:self waitUntilDone:[NSThread isMainThread]];
1764 - [[self authenticationLock] lockWhenCondition:2];  
1765 - [[self authenticationLock] unlockWithCondition:1];  
1766 - if ([self error]) {  
1767 - return NO;  
1768 - }  
1769 return YES; 1754 return YES;
1770 } 1755 }
1771 return NO; 1756 return NO;
@@ -1791,13 +1776,6 @@ static BOOL isiPhoneOS2; @@ -1791,13 +1776,6 @@ static BOOL isiPhoneOS2;
1791 1776
1792 if ([authenticationDelegate respondsToSelector:@selector(proxyAuthenticationNeededForRequest:)]) { 1777 if ([authenticationDelegate respondsToSelector:@selector(proxyAuthenticationNeededForRequest:)]) {
1793 [authenticationDelegate performSelectorOnMainThread:@selector(proxyAuthenticationNeededForRequest:) withObject:self waitUntilDone:[NSThread isMainThread]]; 1778 [authenticationDelegate performSelectorOnMainThread:@selector(proxyAuthenticationNeededForRequest:) withObject:self waitUntilDone:[NSThread isMainThread]];
1794 - [[self authenticationLock] lockWhenCondition:2];  
1795 - [[self authenticationLock] unlockWithCondition:1];  
1796 -  
1797 - // Was the request cancelled?  
1798 - if ([self error] || [[self mainRequest] error]) {  
1799 - return NO;  
1800 - }  
1801 return YES; 1779 return YES;
1802 } 1780 }
1803 return NO; 1781 return NO;
@@ -1941,13 +1919,11 @@ static BOOL isiPhoneOS2; @@ -1941,13 +1919,11 @@ static BOOL isiPhoneOS2;
1941 } 1919 }
1942 1920
1943 if ([self askDelegateForProxyCredentials]) { 1921 if ([self askDelegateForProxyCredentials]) {
1944 - [self attemptToApplyProxyCredentialsAndResume];  
1945 [delegateAuthenticationLock unlock]; 1922 [delegateAuthenticationLock unlock];
1946 return; 1923 return;
1947 } 1924 }
1948 1925
1949 if ([self showProxyAuthenticationDialog]) { 1926 if ([self showProxyAuthenticationDialog]) {
1950 - [self attemptToApplyProxyCredentialsAndResume];  
1951 [delegateAuthenticationLock unlock]; 1927 [delegateAuthenticationLock unlock];
1952 return; 1928 return;
1953 } 1929 }
@@ -1967,11 +1943,6 @@ static BOOL isiPhoneOS2; @@ -1967,11 +1943,6 @@ static BOOL isiPhoneOS2;
1967 // Cannot show the dialog when we are running on the main thread, as the locks will cause the app to hang 1943 // Cannot show the dialog when we are running on the main thread, as the locks will cause the app to hang
1968 if ([self shouldPresentAuthenticationDialog]) { 1944 if ([self shouldPresentAuthenticationDialog]) {
1969 [ASIAuthenticationDialog performSelectorOnMainThread:@selector(presentAuthenticationDialogForRequest:) withObject:self waitUntilDone:[NSThread isMainThread]]; 1945 [ASIAuthenticationDialog performSelectorOnMainThread:@selector(presentAuthenticationDialogForRequest:) withObject:self waitUntilDone:[NSThread isMainThread]];
1970 - [[self authenticationLock] lockWhenCondition:2];  
1971 - [[self authenticationLock] unlockWithCondition:1];  
1972 - if ([self error]) {  
1973 - return NO;  
1974 - }  
1975 return YES; 1946 return YES;
1976 } 1947 }
1977 return NO; 1948 return NO;
@@ -1982,11 +1953,6 @@ static BOOL isiPhoneOS2; @@ -1982,11 +1953,6 @@ static BOOL isiPhoneOS2;
1982 1953
1983 - (BOOL)askDelegateForCredentials 1954 - (BOOL)askDelegateForCredentials
1984 { 1955 {
1985 -// // Can't use delegate authentication when running on the main thread  
1986 -// if ([NSThread isMainThread]) {  
1987 -// return NO;  
1988 -// }  
1989 -  
1990 // If we have a delegate, we'll see if it can handle proxyAuthenticationNeededForRequest:. 1956 // If we have a delegate, we'll see if it can handle proxyAuthenticationNeededForRequest:.
1991 // Otherwise, we'll try the queue (if this request is part of one) and it will pass the message on to its own delegate 1957 // Otherwise, we'll try the queue (if this request is part of one) and it will pass the message on to its own delegate
1992 id authenticationDelegate = [self delegate]; 1958 id authenticationDelegate = [self delegate];
@@ -1996,13 +1962,6 @@ static BOOL isiPhoneOS2; @@ -1996,13 +1962,6 @@ static BOOL isiPhoneOS2;
1996 1962
1997 if ([authenticationDelegate respondsToSelector:@selector(authenticationNeededForRequest:)]) { 1963 if ([authenticationDelegate respondsToSelector:@selector(authenticationNeededForRequest:)]) {
1998 [authenticationDelegate performSelectorOnMainThread:@selector(authenticationNeededForRequest:) withObject:self waitUntilDone:[NSThread isMainThread]]; 1964 [authenticationDelegate performSelectorOnMainThread:@selector(authenticationNeededForRequest:) withObject:self waitUntilDone:[NSThread isMainThread]];
1999 - //[[self authenticationLock] lockWhenCondition:2];  
2000 -// [[self authenticationLock] unlockWithCondition:1];  
2001 -//  
2002 -// // Was the request cancelled?  
2003 -// if ([self error] || [[self mainRequest] error]) {  
2004 -// return NO;  
2005 - //}  
2006 return YES; 1965 return YES;
2007 } 1966 }
2008 return NO; 1967 return NO;
@@ -2077,12 +2036,10 @@ static BOOL isiPhoneOS2; @@ -2077,12 +2036,10 @@ static BOOL isiPhoneOS2;
2077 [self setLastActivityTime:nil]; 2036 [self setLastActivityTime:nil];
2078 2037
2079 if ([self askDelegateForCredentials]) { 2038 if ([self askDelegateForCredentials]) {
2080 - [self attemptToApplyCredentialsAndResume];  
2081 [delegateAuthenticationLock unlock]; 2039 [delegateAuthenticationLock unlock];
2082 return; 2040 return;
2083 } 2041 }
2084 if ([self showAuthenticationDialog]) { 2042 if ([self showAuthenticationDialog]) {
2085 - [self attemptToApplyCredentialsAndResume];  
2086 [delegateAuthenticationLock unlock]; 2043 [delegateAuthenticationLock unlock];
2087 return; 2044 return;
2088 } 2045 }
@@ -2150,7 +2107,6 @@ static BOOL isiPhoneOS2; @@ -2150,7 +2107,6 @@ static BOOL isiPhoneOS2;
2150 } 2107 }
2151 2108
2152 if ([self showAuthenticationDialog]) { 2109 if ([self showAuthenticationDialog]) {
2153 - [self attemptToApplyCredentialsAndResume];  
2154 [delegateAuthenticationLock unlock]; 2110 [delegateAuthenticationLock unlock];
2155 return; 2111 return;
2156 } 2112 }
@@ -2304,7 +2260,7 @@ static BOOL isiPhoneOS2; @@ -2304,7 +2260,7 @@ static BOOL isiPhoneOS2;
2304 2260
2305 if (readStream) { 2261 if (readStream) {
2306 CFReadStreamSetClient(readStream, kCFStreamEventNone, NULL, NULL); 2262 CFReadStreamSetClient(readStream, kCFStreamEventNone, NULL, NULL);
2307 - CFReadStreamUnscheduleFromRunLoop(readStream, CFRunLoopGetCurrent(), ASIHTTPRequestRunMode); 2263 + CFReadStreamUnscheduleFromRunLoop(readStream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
2308 CFReadStreamClose(readStream); 2264 CFReadStreamClose(readStream);
2309 CFRelease(readStream); 2265 CFRelease(readStream);
2310 readStream = NULL; 2266 readStream = NULL;
@@ -3268,7 +3224,6 @@ static BOOL isiPhoneOS2; @@ -3268,7 +3224,6 @@ static BOOL isiPhoneOS2;
3268 @synthesize needsRedirect; 3224 @synthesize needsRedirect;
3269 @synthesize redirectCount; 3225 @synthesize redirectCount;
3270 @synthesize shouldCompressRequestBody; 3226 @synthesize shouldCompressRequestBody;
3271 -@synthesize authenticationLock;  
3272 @synthesize needsProxyAuthentication; 3227 @synthesize needsProxyAuthentication;
3273 @synthesize proxyCredentials; 3228 @synthesize proxyCredentials;
3274 @synthesize proxyHost; 3229 @synthesize proxyHost;