Permalink
Browse files

More tweaks to progress tracking

Run synchronous requests in custom runloop mode again
  • Loading branch information...
1 parent bd94484 commit 3cbd8d6f61546030a426c9af7fd1326bbe8cd4aa @pokeb committed Apr 15, 2010
View
@@ -266,7 +266,8 @@ extern unsigned long const ASIWWANBandwidthThrottleAmount;
NSTimeInterval timeOutSeconds;
// Will be YES when a HEAD request will handle the content-length before this request starts
- BOOL shouldResetProgressIndicators;
+ BOOL shouldResetUploadProgress;
+ BOOL shouldResetDownloadProgress;
// Used by HEAD requests when showAccurateProgress is YES to preset the content-length for this request
ASIHTTPRequest *mainRequest;
@@ -385,6 +386,9 @@ extern unsigned long const ASIWWANBandwidthThrottleAmount;
// An ID that uniquely identifies this request - primarily used for debugging persistent connections
NSNumber *requestID;
+
+ // Will be ASIHTTPRequestRunLoopMode for synchronous requests, NSDefaultRunLoopMode for all other requests
+ NSString *runLoopMode;
}
#pragma mark init / dealloc
@@ -466,10 +470,10 @@ extern unsigned long const ASIWWANBandwidthThrottleAmount;
// Called when authorisation is needed, as we only find out we don't have permission to something when the upload is complete
- (void)removeUploadProgressSoFar;
-// Called when we get a content-length header and shouldResetProgressIndicators is true
+// Called when we get a content-length header and shouldResetDownloadProgress is true
- (void)incrementDownloadSizeBy:(long long)length;
-// Called when a request starts and shouldResetProgressIndicators is true
+// Called when a request starts and shouldResetUploadProgress is true
// Also called (with a negative length) to remove the size of the underlying buffer used for uploading
- (void)incrementUploadSizeBy:(long long)length;
@@ -723,7 +727,8 @@ extern unsigned long const ASIWWANBandwidthThrottleAmount;
@property (retain) NSMutableData *postBody;
@property (assign,readonly) unsigned long long contentLength;
@property (assign) unsigned long long postLength;
-@property (assign) BOOL shouldResetProgressIndicators;
+@property (assign) BOOL shouldResetDownloadProgress;
+@property (assign) BOOL shouldResetUploadProgress;
@property (assign) ASIHTTPRequest *mainRequest;
@property (assign) BOOL showAccurateProgress;
@property (assign,readonly) unsigned long long totalBytesRead;
View
@@ -23,10 +23,12 @@
// Automatically set on build
-NSString *ASIHTTPRequestVersion = @"v1.6.1-15 2010-04-14";
+NSString *ASIHTTPRequestVersion = @"v1.6.1-16 2010-04-15";
NSString* const NetworkRequestErrorDomain = @"ASIHTTPRequestErrorDomain";
+static NSString *ASIHTTPRequestRunLoopMode = @"ASIHTTPRequestRunLoopMode";
+
static const CFOptionFlags kNetworkEvents = kCFStreamEventOpenCompleted | kCFStreamEventHasBytesAvailable | kCFStreamEventEndEncountered | kCFStreamEventErrorOccurred;
// In memory caches of credentials, used on when useSessionPersistence is YES
@@ -187,6 +189,7 @@ + (void)reachabilityChanged:(NSNotification *)note;
@property (retain, nonatomic) NSTimer *statusTimer;
@property (assign, nonatomic) BOOL downloadComplete;
@property (retain) NSNumber *requestID;
+@property (assign, nonatomic) NSString *runLoopMode;
@end
@@ -225,12 +228,14 @@ - (id)initWithURL:(NSURL *)newURL
self = [self init];
[self setRequestMethod:@"GET"];
+ [self setRunLoopMode:NSDefaultRunLoopMode];
[self setShouldAttemptPersistentConnection:YES];
[self setPersistentConnectionTimeoutSeconds:60.0];
[self setShouldPresentCredentialsBeforeChallenge:YES];
[self setShouldRedirect:YES];
[self setShowAccurateProgress:YES];
- [self setShouldResetProgressIndicators:YES];
+ [self setShouldResetDownloadProgress:YES];
+ [self setShouldResetUploadProgress:YES];
[self setAllowCompressedResponse:YES];
[self setDefaultResponseEncoding:NSISOLatin1StringEncoding];
[self setShouldPresentProxyAuthenticationDialog:YES];
@@ -498,6 +503,7 @@ - (void)startSynchronous
#if DEBUG_REQUEST_STATUS || DEBUG_THROTTLING
NSLog(@"Starting synchronous request %@",self);
#endif
+ [self setRunLoopMode:ASIHTTPRequestRunLoopMode];
[self setInProgress:YES];
@try {
if (![self isCancelled] && ![self complete]) {
@@ -516,7 +522,6 @@ - (void)start
{
#if TARGET_OS_IPHONE
[self performSelectorInBackground:@selector(startAsynchronous) withObject:nil];
-
#else
SInt32 versionMajor;
@@ -1015,7 +1020,7 @@ - (void)startRequest
// 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
// http://lists.apple.com/archives/Macnetworkprog/2006/Mar/msg00119.html
if (oldStream) {
- CFReadStreamClose((CFReadStreamRef)oldStream);
+ [oldStream close];
[oldStream release];
oldStream = nil;
}
@@ -1031,14 +1036,16 @@ - (void)startRequest
[[self cancelledLock] unlock];
- if (![self mainRequest] && [self shouldResetProgressIndicators]) {
- if ([self showAccurateProgress]) {
- [self incrementUploadSizeBy:[self postLength]];
- } else {
- [self incrementUploadSizeBy:1];
+ if (![self mainRequest]) {
+ if ([self shouldResetUploadProgress]) {
+ if ([self showAccurateProgress]) {
+ [self incrementUploadSizeBy:[self postLength]];
+ } else {
+ [self incrementUploadSizeBy:1];
+ }
+ [ASIHTTPRequest updateProgressIndicator:[self uploadProgressDelegate] withProgress:0 ofTotal:1];
}
- [ASIHTTPRequest updateProgressIndicator:[self uploadProgressDelegate] withProgress:0 ofTotal:1];
- if (![self partialDownloadSize]) {
+ if ([self shouldResetDownloadProgress] && ![self partialDownloadSize]) {
[ASIHTTPRequest updateProgressIndicator:[self downloadProgressDelegate] withProgress:0 ofTotal:1];
}
}
@@ -1048,12 +1055,13 @@ - (void)startRequest
[self setLastActivityTime:[NSDate date]];
- [self setStatusTimer:[NSTimer scheduledTimerWithTimeInterval:0.25 target:self selector:@selector(updateStatus:) userInfo:nil repeats:YES]];
-
+ [self setStatusTimer:[NSTimer timerWithTimeInterval:0.25 target:self selector:@selector(updateStatus:) userInfo:nil repeats:YES]];
+ [[NSRunLoop currentRunLoop] addTimer:[self statusTimer] forMode:[self runLoopMode]];
+
// If we're running asynchronously on the main thread, the runloop will already be running and we can return control
- if (![NSThread isMainThread] || [self isSynchronous]) {
+ if (![NSThread isMainThread] || [self isSynchronous] || ![[self runLoopMode] isEqualToString:NSDefaultRunLoopMode]) {
while (!complete) {
- CFRunLoopRun();
+ [[NSRunLoop currentRunLoop] runMode:[self runLoopMode] beforeDate:[NSDate distantFuture]];
}
}
}
@@ -1322,6 +1330,9 @@ - (void)updateDownloadProgress
value = 1;
[self setUpdatedProgress:YES];
}
+ if (!value) {
+ return;
+ }
[ASIHTTPRequest performSelector:@selector(request:didReceiveBytes:) onTarget:[self queue] withObject:self amount:&value];
[ASIHTTPRequest performSelector:@selector(request:didReceiveBytes:) onTarget:[self downloadProgressDelegate] withObject:self amount:&value];
@@ -1358,6 +1369,10 @@ - (void)updateUploadProgress
[self setUpdatedProgress:YES];
}
+ if (!value) {
+ return;
+ }
+
[ASIHTTPRequest performSelector:@selector(request:didSendBytes:) onTarget:[self queue] withObject:self amount:&value];
[ASIHTTPRequest performSelector:@selector(request:didSendBytes:) onTarget:[self uploadProgressDelegate] withObject:self amount:&value];
[ASIHTTPRequest updateProgressIndicator:[self uploadProgressDelegate] withProgress:[self totalBytesSent]-[self uploadBufferSize] ofTotal:[self postLength]];
@@ -1368,15 +1383,13 @@ - (void)incrementDownloadSizeBy:(long long)length
{
[ASIHTTPRequest performSelector:@selector(request:incrementDownloadSizeBy:) onTarget:[self queue] withObject:self amount:&length];
[ASIHTTPRequest performSelector:@selector(request:incrementDownloadSizeBy:) onTarget:[self uploadProgressDelegate] withObject:self amount:&length];
- [ASIHTTPRequest updateProgressIndicator:[self uploadProgressDelegate] withProgress:0 ofTotal:length];
}
- (void)incrementUploadSizeBy:(long long)length
{
[ASIHTTPRequest performSelector:@selector(request:incrementUploadSizeBy:) onTarget:[self queue] withObject:self amount:&length];
[ASIHTTPRequest performSelector:@selector(request:incrementUploadSizeBy:) onTarget:[self uploadProgressDelegate] withObject:self amount:&length];
- [ASIHTTPRequest updateProgressIndicator:[self uploadProgressDelegate] withProgress:0 ofTotal:length];
}
@@ -1625,18 +1638,18 @@ - (void)readResponseHeaders
SInt32 length = CFStringGetIntValue((CFStringRef)cLength);
// Workaround for Apache HEAD requests for dynamically generated content returning the wrong Content-Length when using gzip
- if ([self mainRequest] && [self allowCompressedResponse] && length == 20 && [self showAccurateProgress] && [self shouldResetProgressIndicators]) {
+ if ([self mainRequest] && [self allowCompressedResponse] && length == 20 && [self showAccurateProgress] && [self shouldResetDownloadProgress]) {
[[self mainRequest] setShowAccurateProgress:NO];
[[self mainRequest] incrementDownloadSizeBy:1];
} else {
[theRequest setContentLength:length];
- if ([self showAccurateProgress] && [self shouldResetProgressIndicators]) {
+ if ([self showAccurateProgress] && [self shouldResetDownloadProgress]) {
[theRequest incrementDownloadSizeBy:[theRequest contentLength]+[theRequest partialDownloadSize]];
}
}
- } else if ([self showAccurateProgress] && [self shouldResetProgressIndicators]) {
+ } else if ([self showAccurateProgress] && [self shouldResetDownloadProgress]) {
[theRequest setShowAccurateProgress:NO];
[theRequest incrementDownloadSizeBy:1];
}
@@ -2434,7 +2447,7 @@ - (void)handleBytesAvailable
UInt8 buffer[bufferSize];
- CFIndex bytesRead = CFReadStreamRead((CFReadStreamRef)[self readStream], buffer, sizeof(buffer));
+ NSInteger bytesRead = [[self readStream] read:buffer maxLength:sizeof(buffer)];
// Less than zero is an error
if (bytesRead < 0) {
@@ -2663,12 +2676,10 @@ - (void)destroyReadStream
[connectionsLock lock];
if (![self connectionCanBeReused]) {
- CFReadStreamUnscheduleFromRunLoop((CFReadStreamRef)[self readStream], CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
- CFReadStreamClose((CFReadStreamRef)[self readStream]);
+ [[self readStream] removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:[self runLoopMode]];
+ [[self readStream] close];
[self setReadStreamIsScheduled:NO];
-
}
-
[self setReadStream:nil];
[connectionsLock unlock];
}
@@ -2679,15 +2690,15 @@ - (void)scheduleReadStream
if ([self readStream] && ![self readStreamIsScheduled]) {
// Reset the timeout
[self setLastActivityTime:[NSDate date]];
- CFReadStreamScheduleWithRunLoop((CFReadStreamRef)[self readStream], CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
+ [[self readStream] scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:[self runLoopMode]];
[self setReadStreamIsScheduled:YES];
}
}
- (void)unscheduleReadStream
{
if ([self readStream] && [self readStreamIsScheduled]) {
- CFReadStreamUnscheduleFromRunLoop((CFReadStreamRef)[self readStream], CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
+ [[self readStream] removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:[self runLoopMode]];
[self setReadStreamIsScheduled:NO];
}
}
@@ -2709,7 +2720,7 @@ + (void)expirePersistentConnections
#endif
NSInputStream *stream = [existingConnection objectForKey:@"stream"];
if (stream) {
- CFReadStreamClose((CFReadStreamRef)stream);
+ [stream close];
}
[persistentConnectionsPool removeObject:existingConnection];
i--;
@@ -2755,7 +2766,8 @@ - (id)copyWithZone:(NSZone *)zone
[newRequest setDidFinishSelector:[self didFinishSelector]];
[newRequest setDidFailSelector:[self didFailSelector]];
[newRequest setTimeOutSeconds:[self timeOutSeconds]];
- [newRequest setShouldResetProgressIndicators:[self shouldResetProgressIndicators]];
+ [newRequest setShouldResetDownloadProgress:[self shouldResetDownloadProgress]];
+ [newRequest setShouldResetUploadProgress:[self shouldResetUploadProgress]];
[newRequest setShowAccurateProgress:[self showAccurateProgress]];
[newRequest setDefaultResponseEncoding:[self defaultResponseEncoding]];
[newRequest setAllowResumeForFileDownloads:[self allowResumeForFileDownloads]];
@@ -3585,7 +3597,6 @@ + (void)registerForNetworkReachabilityNotifications
+ (void)unsubscribeFromNetworkReachabilityNotifications
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"kNetworkReachabilityChangedNotification" object:nil];
-
}
+ (BOOL)isNetworkReachableViaWWAN
@@ -3691,7 +3702,8 @@ + (NSString*)base64forData:(NSData*)theData {
@synthesize contentLength;
@synthesize partialDownloadSize;
@synthesize postLength;
-@synthesize shouldResetProgressIndicators;
+@synthesize shouldResetDownloadProgress;
+@synthesize shouldResetUploadProgress;
@synthesize mainRequest;
@synthesize totalBytesRead;
@synthesize totalBytesSent;
@@ -3748,4 +3760,5 @@ + (NSString*)base64forData:(NSData*)theData {
@synthesize shouldUseRFC2616RedirectBehaviour;
@synthesize downloadComplete;
@synthesize requestID;
+@synthesize runLoopMode;
@end
@@ -55,7 +55,7 @@
int requestsCount;
// When NO, this request will only update the progress indicator when it completes
- // When YES, this request will update the progress indicator according to how much data it has recieved so far
+ // When YES, this request will update the progress indicator according to how much data it has received so far
// When YES, the queue will first perform HEAD requests for all GET requests in the queue, so it can calculate the total download size before it starts
// NO means better performance, because it skips this step for GET requests, and it won't waste time updating the progress indicator until a request completes
// Set to YES if the size of a requests in the queue varies greatly for much more accurate results
View
@@ -71,24 +71,12 @@ - (void)reset
[self setRequestDidFailSelector:NULL];
[self setRequestDidFinishSelector:NULL];
[self setQueueDidFinishSelector:NULL];
- [self setTotalBytesToUpload:0];
- [self setBytesUploadedSoFar:0];
- [self setTotalBytesToDownload:0];
- [self setBytesDownloadedSoFar:0];
[self setSuspended:YES];
}
- (void)go
{
- if (![self showAccurateProgress]) {
- if ([self downloadProgressDelegate]) {
- [self setTotalBytesToDownload:[self requestsCount]];
- }
- if ([self uploadProgressDelegate]) {
- [self setTotalBytesToUpload:[self requestsCount]];
- }
- }
[self setSuspended:NO];
}
@@ -172,35 +160,33 @@ - (void)addOperation:(NSOperation *)operation
// If this is a GET request and we want accurate progress, perform a HEAD request first to get the content-length
// We'll only do this before the queue is started
// If requests are added after the queue is started they will probably move the overall progress backwards anyway, so there's no value performing the HEAD requests first
- // Instead, they'll update the total progress if and when they recieve a content-length header
- if ([[request requestMethod] isEqualToString:@"GET"] && [self isSuspended]) {
- ASIHTTPRequest *HEADRequest = [request HEADRequest];
- [self addHEADOperation:HEADRequest];
-
- if ([request shouldResetProgressIndicators]) {
- [self resetProgressDelegate:[request downloadProgressDelegate]];
- }
-
- //Tell the request not to reset the progress indicator when it gets a content-length, as we will get the length from the HEAD request
- [request setShouldResetProgressIndicators:NO];
-
- [request addDependency:HEADRequest];
-
- // If we want to track uploading for this request accurately, we need to add the size of the post content to the total
- } else if (uploadProgressDelegate) {
- [request buildPostBody];
- [self setTotalBytesToUpload:[self totalBytesToUpload]+[request postLength]];
-
-
- if ([request shouldResetProgressIndicators]) {
- [self resetProgressDelegate:[request uploadProgressDelegate]];
+ // Instead, they'll update the total progress if and when they receive a content-length header
+ if ([[request requestMethod] isEqualToString:@"GET"]) {
+ if ([self isSuspended]) {
+ ASIHTTPRequest *HEADRequest = [request HEADRequest];
+ [self addHEADOperation:HEADRequest];
+ [request addDependency:HEADRequest];
+ if ([request shouldResetDownloadProgress]) {
+ [self resetProgressDelegate:[request downloadProgressDelegate]];
+ [request setShouldResetDownloadProgress:NO];
+ }
}
-
- [request setShouldResetProgressIndicators:NO];
}
+ [request buildPostBody];
+ [self request:nil incrementUploadSizeBy:[request postLength]];
+
+
+ } else {
+ [self request:nil incrementDownloadSizeBy:1];
+ [self request:nil incrementUploadSizeBy:1];
}
+ // Tell the request not to increment the upload size when it starts, as we've already added its length
+ if ([request shouldResetUploadProgress]) {
+ [self resetProgressDelegate:[request uploadProgressDelegate]];
+ [request setShouldResetUploadProgress:NO];
+ }
+
[request setShowAccurateProgress:[self showAccurateProgress]];
-
[request setQueue:self];
[super addOperation:request];
Oops, something went wrong.

0 comments on commit 3cbd8d6

Please sign in to comment.