Ben Copsey

More tweaks to progress tracking

Run synchronous requests in custom runloop mode again
... ... @@ -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;
... ...
This diff is collapsed. Click to expand it.
... ... @@ -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
... ...
... ... @@ -71,24 +71,12 @@
[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,36 +160,34 @@
// 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]) {
// 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];
if ([request shouldResetProgressIndicators]) {
[request addDependency:HEADRequest];
if ([request shouldResetDownloadProgress]) {
[self resetProgressDelegate:[request downloadProgressDelegate]];
[request setShouldResetDownloadProgress:NO];
}
}
}
//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]];
[self request:nil incrementUploadSizeBy:[request postLength]];
if ([request shouldResetProgressIndicators]) {
} 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 setShouldResetProgressIndicators:NO];
}
}
[request setShowAccurateProgress:[self showAccurateProgress]];
[request setQueue:self];
[super addOperation:request];
[self updateNetworkActivityIndicator];
... ...
... ... @@ -21,17 +21,18 @@
- (void)setMaxValue:(double)newMax;
#endif
// Called when the request recieves some data - bytes is the length of that data
// bytes may be less than zero if a request needs to remove its progress so far
// Called when the request receives some data - bytes is the length of that data
- (void)request:(ASIHTTPRequest *)request didReceiveBytes:(long long)bytes;
// Called when the request sends some data.
// Called when the request sends some data
// The first 32KB (128KB on older platforms) of data sent is not included in this amount because of limitations with the CFNetwork API
// bytes may be less than zero if a request needs to remove upload progress (probably because the request needs to run again)
- (void)request:(ASIHTTPRequest *)request didSendBytes:(long long)bytes;
// Called when a request needs to change the length of the content to download
- (void)request:(ASIHTTPRequest *)request incrementDownloadSizeBy:(long long)newLength;
// Called when a request needs to change the length of the content to upload
// newLength may be less than zero when a request needs to remove the size of the internal buffer from progress tracking
- (void)request:(ASIHTTPRequest *)request incrementUploadSizeBy:(long long)newLength;
@end
... ...
... ... @@ -182,7 +182,10 @@ IMPORTANT
BOOL success = (progress == 1.0);
GHAssertTrue(success,@"Failed to increment progress properly");
[networkQueue cancelAllOperations];
[networkQueue reset];
[networkQueue setDownloadProgressDelegate:self];
[networkQueue setDelegate:self];
[networkQueue setQueueDidFinishSelector:@selector(queueFinished:)];
// This test will request gzipped content, but the content-length header we get on the HEAD request will be wrong, ASIHTTPRequest should fall back to simple progress
// This is to workaround an issue Apache has with HEAD requests for dynamically generated content when accepting gzip - it returns the content-length of a gzipped empty body
... ... @@ -210,14 +213,13 @@ IMPORTANT
[self setAddMoreRequestsQueue:[ASINetworkQueue queue]];
[[self addMoreRequestsQueue] setDownloadProgressDelegate:self];
[[self addMoreRequestsQueue] setDelegate:self];
[[self addMoreRequestsQueue] setShowAccurateProgress:NO];
[[self addMoreRequestsQueue] setShowAccurateProgress:YES];
[[self addMoreRequestsQueue]setQueueDidFinishSelector:@selector(addMoreRequestsQueueFinished:)];
requestsFinishedCount = 0;
complete = NO;
progress = 0;
[[self addMoreRequestsQueue] setShowAccurateProgress:YES];
int i;
for (i=0; i<5; i++) {
... ... @@ -311,13 +313,18 @@ IMPORTANT
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.25]];
}
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
BOOL success = (progress > 0.95);
BOOL success = (progress == 1.0f);
GHAssertTrue(success,@"Failed to increment progress properly");
//Now test again with accurate progress
complete = NO;
progress = 0;
[networkQueue cancelAllOperations];
[networkQueue reset];
[networkQueue setUploadProgressDelegate:self];
[networkQueue setDelegate:self];
[networkQueue setShowAccurateProgress:NO];
[networkQueue setRequestDidFailSelector:@selector(uploadFailed:)];
[networkQueue setQueueDidFinishSelector:@selector(queueFinished:)];
[networkQueue setShowAccurateProgress:YES];
for (i=0; i<3; i++) {
... ... @@ -335,7 +342,7 @@ IMPORTANT
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.25]];
}
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
success = (progress > 0.95);
success = (progress == 1.0f);
GHAssertTrue(success,@"Failed to increment progress properly");
}
... ... @@ -709,7 +716,7 @@ IMPORTANT
success = (amountDownloaded == 1036935);
GHAssertTrue(success,@"Failed to complete the download");
success = (progress > 0.95);
success = (progress == 1.0f);
GHAssertTrue(success,@"Failed to increment progress properly");
... ... @@ -1112,6 +1119,10 @@ IMPORTANT
- (void)testQueueFinishedCalledOnFailure
{
[self performSelectorOnMainThread:@selector(runTestQueueFinishedCalledOnFailureTest) withObject:nil waitUntilDone:YES];
}
- (void)runTestQueueFinishedCalledOnFailureTest
{
complete = NO;
ASINetworkQueue *networkQueue = [[ASINetworkQueue queue] retain];
[networkQueue setDelegate:self];
... ... @@ -1136,7 +1147,9 @@ IMPORTANT
queueFinishedCallCount = 0;
complete = NO;
[networkQueue reset];
[networkQueue release];
networkQueue = [[ASINetworkQueue queue] retain];
[networkQueue setDelegate:self];
[networkQueue setQueueDidFinishSelector:@selector(queueFailureFinishCallOnce:)];
[networkQueue setMaxConcurrentOperationCount:1];
... ... @@ -1150,7 +1163,7 @@ IMPORTANT
dateStarted = [NSDate date];
while (!complete) {
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.5]];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.0f]];
if ([dateStarted timeIntervalSinceNow] < -10) {
break;
}
... ...