Ben Copsey

Big changes to progress tracking:

Added ability to use non-accurate progress for speed
Request HEAD for GET requests when in accurate mode
Calculate postLength outside of main
Bug fixes
@@ -36,6 +36,7 @@ @@ -36,6 +36,7 @@
36 postData = [[NSMutableDictionary alloc] init]; 36 postData = [[NSMutableDictionary alloc] init];
37 } 37 }
38 [postData setValue:value forKey:key]; 38 [postData setValue:value forKey:key];
  39 + [self setRequestMethod:@"POST"];
39 } 40 }
40 41
41 - (void)setFile:(NSString *)filePath forKey:(NSString *)key 42 - (void)setFile:(NSString *)filePath forKey:(NSString *)key
@@ -44,30 +45,20 @@ @@ -44,30 +45,20 @@
44 fileData = [[NSMutableDictionary alloc] init]; 45 fileData = [[NSMutableDictionary alloc] init];
45 } 46 }
46 [fileData setValue:filePath forKey:key]; 47 [fileData setValue:filePath forKey:key];
  48 + [self setRequestMethod:@"POST"];
47 } 49 }
48 50
49 - 51 +- (void)buildPostBody
50 -#pragma mark request logic  
51 -  
52 -// Create the request  
53 -- (void)main  
54 { 52 {
55 -  
56 - // If the user didn't specify post data, we will let ASIHTTPRequest use the value of body  
57 - if ([postData count] == 0 && [fileData count] == 0) {  
58 - [super main];  
59 - return;  
60 - }  
61 -  
62 NSMutableData *body = [[[NSMutableData alloc] init] autorelease]; 53 NSMutableData *body = [[[NSMutableData alloc] init] autorelease];
63 54
64 // Set your own boundary string only if really obsessive. We don't bother to check if post data contains the boundary, since it's pretty unlikely that it does. 55 // Set your own boundary string only if really obsessive. We don't bother to check if post data contains the boundary, since it's pretty unlikely that it does.
65 NSString *stringBoundary = @"0xKhTmLbOuNdArY"; 56 NSString *stringBoundary = @"0xKhTmLbOuNdArY";
66 57
67 - if ([fileData count] > 0) { 58 + //if ([fileData count] > 0) {
68 // We need to use multipart/form-data when using file upload 59 // We need to use multipart/form-data when using file upload
69 [self addRequestHeader:@"Content-Type" value:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",stringBoundary]]; 60 [self addRequestHeader:@"Content-Type" value:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",stringBoundary]];
70 - } 61 + //}
71 62
72 63
73 64
@@ -95,7 +86,9 @@ @@ -95,7 +86,9 @@
95 NSString *filePath = [fileData objectForKey:key]; 86 NSString *filePath = [fileData objectForKey:key];
96 [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n",key,[filePath lastPathComponent]] dataUsingEncoding:NSUTF8StringEncoding]]; 87 [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n",key,[filePath lastPathComponent]] dataUsingEncoding:NSUTF8StringEncoding]];
97 [body appendData:contentTypeHeader]; 88 [body appendData:contentTypeHeader];
98 - [body appendData:[NSData dataWithContentsOfMappedFile:filePath]]; 89 + //[body appendData: [NSData dataWithContentsOfFile:filePath options:NSUncachedRead error:NULL]];
  90 + //[body appendData:[NSData dataWithContentsOfMappedFile:filePath]];
  91 + [body appendData:[NSData dataWithContentsOfFile:filePath]];
99 i++; 92 i++;
100 // Only add the boundary if this is not the last item in the post body 93 // Only add the boundary if this is not the last item in the post body
101 if (i != [fileData count]) { 94 if (i != [fileData count]) {
@@ -107,11 +100,11 @@ @@ -107,11 +100,11 @@
107 100
108 [self setPostBody:body]; 101 [self setPostBody:body];
109 102
110 - //Now we've created our post data, construct the request  
111 - [super main];  
112 103
  104 + [super buildPostBody];
113 } 105 }
114 106
115 107
116 108
  109 +
117 @end 110 @end
@@ -12,6 +12,7 @@ @@ -12,6 +12,7 @@
12 @implementation ASIFormDataRequestTests 12 @implementation ASIFormDataRequestTests
13 13
14 14
  15 +
15 - (void)testPostWithFileUpload 16 - (void)testPostWithFileUpload
16 { 17 {
17 18
@@ -21,14 +22,12 @@ @@ -21,14 +22,12 @@
21 NSString *path = [[[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"bigfile"]; 22 NSString *path = [[[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"bigfile"];
22 [data writeToFile:path atomically:NO]; 23 [data writeToFile:path atomically:NO];
23 24
24 - ASIFormDataRequest *request = [[[ASIFormDataRequest alloc] initWithURL:[NSURL URLWithString:@"http://allseeing-i.com/asi-http-request/tests/post"]] autorelease]; 25 + ASIFormDataRequest *request = [[[ASIFormDataRequest alloc] initWithURL:[NSURL URLWithString:@"http://asi/asi-http-request/tests/post"]] autorelease];
25 - [request setDelegate:self];  
26 -  
27 [request setPostValue:@"foo" forKey:@"post_var"]; 26 [request setPostValue:@"foo" forKey:@"post_var"];
28 [request setFile:path forKey:@"file"]; 27 [request setFile:path forKey:@"file"];
29 - [request setUploadProgressDelegate:self];  
30 [request start]; 28 [request start];
31 29
  30 +
32 BOOL success = ([[request dataString] isEqualToString:[NSString stringWithFormat:@"post_var: %@\r\nfile_name: %@\r\nfile_size: %hu",@"foo",@"bigfile",size]]); 31 BOOL success = ([[request dataString] isEqualToString:[NSString stringWithFormat:@"post_var: %@\r\nfile_name: %@\r\nfile_size: %hu",@"foo",@"bigfile",size]]);
33 STAssertTrue(success,@"Failed to upload the correct data"); 32 STAssertTrue(success,@"Failed to upload the correct data");
34 } 33 }
@@ -121,9 +121,27 @@ @@ -121,9 +121,27 @@
121 //Used for recording when something last happened during the request, we will compare this value with the current date to time out requests when appropriate 121 //Used for recording when something last happened during the request, we will compare this value with the current date to time out requests when appropriate
122 NSDate *lastActivityTime; 122 NSDate *lastActivityTime;
123 123
  124 + // Number of seconds to wait before timing out - default is 10
124 NSTimeInterval timeOutSeconds; 125 NSTimeInterval timeOutSeconds;
125 126
  127 + // Autorelease pool for the main loop, since it's highly likely that this operation will run in a thread
126 NSAutoreleasePool *pool; 128 NSAutoreleasePool *pool;
  129 +
  130 + // Will be YES when a HEAD request will handle the content-length before this request starts
  131 + BOOL useCachedContentLength;
  132 +
  133 + // Used by HEAD requests when showAccurateProgress is YES to preset the content-length for this request
  134 + ASIHTTPRequest *mainRequest;
  135 +
  136 + // When NO, this request will only update the progress indicator when it completes
  137 + // When YES, this request will update the progress indicator according to how much data it has recieved so far
  138 + // The default for requests is YES
  139 + // Also see the comments in ASINetworkQueue.h
  140 + BOOL showAccurateProgress;
  141 +
  142 + BOOL updatedProgress;
  143 +
  144 + BOOL haveBuiltPostBody;
127 } 145 }
128 146
129 #pragma mark init / dealloc 147 #pragma mark init / dealloc
@@ -136,6 +154,7 @@ @@ -136,6 +154,7 @@
136 //Add a custom header to the request 154 //Add a custom header to the request
137 - (void)addRequestHeader:(NSString *)header value:(NSString *)value; 155 - (void)addRequestHeader:(NSString *)header value:(NSString *)value;
138 156
  157 +- (void)buildPostBody;
139 158
140 #pragma mark get information about this request 159 #pragma mark get information about this request
141 160
@@ -262,4 +281,8 @@ @@ -262,4 +281,8 @@
262 @property (retain) NSString *requestMethod; 281 @property (retain) NSString *requestMethod;
263 @property (retain,setter=setPostBody:) NSData *postBody; 282 @property (retain,setter=setPostBody:) NSData *postBody;
264 @property (assign) unsigned int contentLength; 283 @property (assign) unsigned int contentLength;
  284 +@property (assign) unsigned int postLength;
  285 +@property (assign) BOOL useCachedContentLength;
  286 +@property (retain) ASIHTTPRequest *mainRequest;
  287 +@property (assign) BOOL showAccurateProgress;
265 @end 288 @end
@@ -51,12 +51,17 @@ static NSLock *progressLock; @@ -51,12 +51,17 @@ static NSLock *progressLock;
51 self = [super init]; 51 self = [super init];
52 [self setRequestMethod:@"GET"]; 52 [self setRequestMethod:@"GET"];
53 lastBytesSent = 0; 53 lastBytesSent = 0;
  54 + showAccurateProgress = YES;
  55 + useCachedContentLength = NO;
  56 + updatedProgress = NO;
  57 + mainRequest = nil;
54 username = nil; 58 username = nil;
55 password = nil; 59 password = nil;
56 requestHeaders = nil; 60 requestHeaders = nil;
57 authenticationRealm = nil; 61 authenticationRealm = nil;
58 outputStream = nil; 62 outputStream = nil;
59 requestAuthentication = NULL; 63 requestAuthentication = NULL;
  64 + haveBuiltPostBody = NO;
60 //credentials = NULL; 65 //credentials = NULL;
61 request = NULL; 66 request = NULL;
62 responseHeaders = nil; 67 responseHeaders = nil;
@@ -81,6 +86,7 @@ static NSLock *progressLock; @@ -81,6 +86,7 @@ static NSLock *progressLock;
81 CFRelease(request); 86 CFRelease(request);
82 } 87 }
83 [self cancelLoad]; 88 [self cancelLoad];
  89 + [mainRequest release];
84 [postBody release]; 90 [postBody release];
85 [requestCredentials release]; 91 [requestCredentials release];
86 [error release]; 92 [error release];
@@ -116,7 +122,18 @@ static NSLock *progressLock; @@ -116,7 +122,18 @@ static NSLock *progressLock;
116 -(void)setPostBody:(NSData *)body 122 -(void)setPostBody:(NSData *)body
117 { 123 {
118 postBody = [body retain]; 124 postBody = [body retain];
  125 + postLength = [postBody length];
  126 + if (postBody && postLength > 0 && ![requestMethod isEqualToString:@"POST"] && ![requestMethod isEqualToString:@"PUT"]) {
119 [self setRequestMethod:@"POST"]; 127 [self setRequestMethod:@"POST"];
  128 + }
  129 +}
  130 +
  131 +// Subclasses should override this method if they need to create POST content for this request
  132 +// This function will be called either just before a request starts, or when postLength is needed, whichever comes first
  133 +// postLength must be set by the time this function is complete - calling setPostBody: will do this for you
  134 +- (void)buildPostBody
  135 +{
  136 + haveBuiltPostBody = YES;
120 } 137 }
121 138
122 #pragma mark get information about this request 139 #pragma mark get information about this request
@@ -199,6 +216,10 @@ static NSLock *progressLock; @@ -199,6 +216,10 @@ static NSLock *progressLock;
199 } 216 }
200 217
201 218
  219 + if (!haveBuiltPostBody) {
  220 + [self buildPostBody];
  221 + }
  222 +
202 // Add custom headers 223 // Add custom headers
203 NSString *header; 224 NSString *header;
204 for (header in requestHeaders) { 225 for (header in requestHeaders) {
@@ -206,10 +227,12 @@ static NSLock *progressLock; @@ -206,10 +227,12 @@ static NSLock *progressLock;
206 } 227 }
207 228
208 229
  230 +
  231 +
  232 +
209 // If this is a post request and we have data to send, add it to the request 233 // If this is a post request and we have data to send, add it to the request
210 if ([self postBody]) { 234 if ([self postBody]) {
211 CFHTTPMessageSetBody(request, (CFDataRef)postBody); 235 CFHTTPMessageSetBody(request, (CFDataRef)postBody);
212 - postLength = [postBody length];  
213 } 236 }
214 237
215 [self loadRequest]; 238 [self loadRequest];
@@ -235,7 +258,9 @@ static NSLock *progressLock; @@ -235,7 +258,9 @@ static NSLock *progressLock;
235 } 258 }
236 259
237 lastBytesSent = 0; 260 lastBytesSent = 0;
  261 + if (!useCachedContentLength) {
238 contentLength = 0; 262 contentLength = 0;
  263 + }
239 [self setResponseHeaders:nil]; 264 [self setResponseHeaders:nil];
240 [self setReceivedData:[[[NSMutableData alloc] init] autorelease]]; 265 [self setReceivedData:[[[NSMutableData alloc] init] autorelease]];
241 266
@@ -268,7 +293,6 @@ static NSLock *progressLock; @@ -268,7 +293,6 @@ static NSLock *progressLock;
268 return; 293 return;
269 } 294 }
270 295
271 -  
272 if (uploadProgressDelegate) { 296 if (uploadProgressDelegate) {
273 [self performSelectorOnMainThread:@selector(resetUploadProgress:) withObject:[NSNumber numberWithDouble:postLength] waitUntilDone:YES]; 297 [self performSelectorOnMainThread:@selector(resetUploadProgress:) withObject:[NSNumber numberWithDouble:postLength] waitUntilDone:YES];
274 } 298 }
@@ -340,9 +364,14 @@ static NSLock *progressLock; @@ -340,9 +364,14 @@ static NSLock *progressLock;
340 364
341 - (void)updateProgressIndicators 365 - (void)updateProgressIndicators
342 { 366 {
  367 + //Only update progress if this isn't a HEAD request used to preset the content-length
  368 + if (!mainRequest) {
343 369
  370 + if (showAccurateProgress || (complete && !updatedProgress)) {
344 [self updateUploadProgress]; 371 [self updateUploadProgress];
345 [self updateDownloadProgress]; 372 [self updateDownloadProgress];
  373 + }
  374 + }
346 375
347 } 376 }
348 377
@@ -421,7 +450,13 @@ static NSLock *progressLock; @@ -421,7 +450,13 @@ static NSLock *progressLock;
421 450
422 //We're using a progress queue or compatible controller to handle progress 451 //We're using a progress queue or compatible controller to handle progress
423 if ([uploadProgressDelegate respondsToSelector:@selector(incrementUploadProgressBy:)]) { 452 if ([uploadProgressDelegate respondsToSelector:@selector(incrementUploadProgressBy:)]) {
424 - int value = byteCount-lastBytesSent; 453 + int value = 0;
  454 + if (showAccurateProgress) {
  455 + value = byteCount-lastBytesSent;
  456 + } else {
  457 + value = 1;
  458 + updatedProgress = YES;
  459 + }
425 SEL selector = @selector(incrementUploadProgressBy:); 460 SEL selector = @selector(incrementUploadProgressBy:);
426 NSMethodSignature *signature = nil; 461 NSMethodSignature *signature = nil;
427 signature = [[uploadProgressDelegate class] instanceMethodSignatureForSelector:selector]; 462 signature = [[uploadProgressDelegate class] instanceMethodSignatureForSelector:selector];
@@ -485,7 +520,14 @@ static NSLock *progressLock; @@ -485,7 +520,14 @@ static NSLock *progressLock;
485 520
486 NSAutoreleasePool *thePool = [[NSAutoreleasePool alloc] init]; 521 NSAutoreleasePool *thePool = [[NSAutoreleasePool alloc] init];
487 522
488 - int value = totalBytesRead-lastBytesRead; 523 + int value = 0;
  524 + if (showAccurateProgress) {
  525 + value = totalBytesRead-lastBytesRead;
  526 + } else {
  527 + value = 1;
  528 + updatedProgress = YES;
  529 + }
  530 +
489 SEL selector = @selector(incrementDownloadProgressBy:); 531 SEL selector = @selector(incrementDownloadProgressBy:);
490 NSMethodSignature *signature = [[downloadProgressDelegate class] instanceMethodSignatureForSelector:selector]; 532 NSMethodSignature *signature = [[downloadProgressDelegate class] instanceMethodSignatureForSelector:selector];
491 NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; 533 NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
@@ -614,14 +656,20 @@ static NSLock *progressLock; @@ -614,14 +656,20 @@ static NSLock *progressLock;
614 //We won't reset the download progress delegate if we got an authentication challenge 656 //We won't reset the download progress delegate if we got an authentication challenge
615 if (!isAuthenticationChallenge) { 657 if (!isAuthenticationChallenge) {
616 658
  659 + //Only check the content length if we haven't already got one (may have been set by an ASINetworkQueue using a previous HEAD request)
  660 + if (!useCachedContentLength) {
617 //See if we got a Content-length header 661 //See if we got a Content-length header
618 NSString *cLength = [responseHeaders valueForKey:@"Content-Length"]; 662 NSString *cLength = [responseHeaders valueForKey:@"Content-Length"];
619 if (cLength) { 663 if (cLength) {
620 contentLength = CFStringGetDoubleValue((CFStringRef)cLength); 664 contentLength = CFStringGetDoubleValue((CFStringRef)cLength);
621 - if (downloadProgressDelegate) { 665 + if (mainRequest) {
  666 + [mainRequest setContentLength:contentLength];
  667 + }
  668 + if (downloadProgressDelegate && showAccurateProgress) {
622 [self performSelectorOnMainThread:@selector(resetDownloadProgress:) withObject:[NSNumber numberWithDouble:contentLength] waitUntilDone:YES]; 669 [self performSelectorOnMainThread:@selector(resetDownloadProgress:) withObject:[NSNumber numberWithDouble:contentLength] waitUntilDone:YES];
623 } 670 }
624 } 671 }
  672 + }
625 673
626 //Handle cookies 674 //Handle cookies
627 NSArray *cookies = [NSHTTPCookie cookiesWithResponseHeaderFields:responseHeaders forURL:url]; 675 NSArray *cookies = [NSHTTPCookie cookiesWithResponseHeaderFields:responseHeaders forURL:url];
@@ -836,7 +884,6 @@ static NSLock *progressLock; @@ -836,7 +884,6 @@ static NSLock *progressLock;
836 884
837 - (void)handleNetworkEvent:(CFStreamEventType)type 885 - (void)handleNetworkEvent:(CFStreamEventType)type
838 { 886 {
839 -  
840 // Dispatch the stream events. 887 // Dispatch the stream events.
841 switch (type) { 888 switch (type) {
842 case kCFStreamEventHasBytesAvailable: 889 case kCFStreamEventHasBytesAvailable:
@@ -898,9 +945,18 @@ static NSLock *progressLock; @@ -898,9 +945,18 @@ static NSLock *progressLock;
898 945
899 - (void)handleStreamComplete 946 - (void)handleStreamComplete
900 { 947 {
  948 +
  949 + //Try to read the headers (if this is a HEAD request handleBytesAvailable available may not be called)
  950 + if (!responseHeaders) {
  951 + if ([self readResponseHeadersReturningAuthenticationFailure]) {
  952 + [self attemptToApplyCredentialsAndResume];
  953 + return;
  954 + }
  955 + }
  956 +
  957 +
901 complete = YES; 958 complete = YES;
902 - [self updateUploadProgress]; 959 + [self updateProgressIndicators];
903 - [self updateDownloadProgress];  
904 if (readStream) { 960 if (readStream) {
905 CFReadStreamClose(readStream); 961 CFReadStreamClose(readStream);
906 CFReadStreamSetClient(readStream, kCFStreamEventNone, NULL, NULL); 962 CFReadStreamSetClient(readStream, kCFStreamEventNone, NULL, NULL);
@@ -1017,9 +1073,6 @@ static NSLock *progressLock; @@ -1017,9 +1073,6 @@ static NSLock *progressLock;
1017 } 1073 }
1018 1074
1019 1075
1020 -  
1021 -  
1022 -  
1023 @synthesize username; 1076 @synthesize username;
1024 @synthesize password; 1077 @synthesize password;
1025 @synthesize domain; 1078 @synthesize domain;
@@ -1047,4 +1100,8 @@ static NSLock *progressLock; @@ -1047,4 +1100,8 @@ static NSLock *progressLock;
1047 @synthesize requestMethod; 1100 @synthesize requestMethod;
1048 @synthesize postBody; 1101 @synthesize postBody;
1049 @synthesize contentLength; 1102 @synthesize contentLength;
  1103 +@synthesize postLength;
  1104 +@synthesize useCachedContentLength;
  1105 +@synthesize mainRequest;
  1106 +@synthesize showAccurateProgress;
1050 @end 1107 @end
@@ -117,7 +117,7 @@ @@ -117,7 +117,7 @@
117 - (void)testUploadProgress 117 - (void)testUploadProgress
118 { 118 {
119 progress = 0; 119 progress = 0;
120 - ASIHTTPRequest *request = [[[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:@"http://allseeing-i.com/ignore"]] autorelease]; 120 + ASIHTTPRequest *request = [[[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:@"http://asi/ignore"]] autorelease];
121 [request setPostBody:[NSMutableData dataWithLength:1024*32]]; 121 [request setPostBody:[NSMutableData dataWithLength:1024*32]];
122 [request setUploadProgressDelegate:self]; 122 [request setUploadProgressDelegate:self];
123 [request start]; 123 [request start];
@@ -357,4 +357,5 @@ @@ -357,4 +357,5 @@
357 } 357 }
358 358
359 359
  360 +
360 @end 361 @end
@@ -26,27 +26,39 @@ @@ -26,27 +26,39 @@
26 id uploadProgressDelegate; 26 id uploadProgressDelegate;
27 27
28 // Total amount uploaded so far for all requests in this queue 28 // Total amount uploaded so far for all requests in this queue
29 - int uploadProgressBytes; 29 + unsigned int uploadProgressBytes;
30 30
31 // Total amount to be uploaded for all requests in this queue - requests add to this figure as they work out how much data they have to transmit 31 // Total amount to be uploaded for all requests in this queue - requests add to this figure as they work out how much data they have to transmit
32 - int uploadProgressTotalBytes; 32 + unsigned int uploadProgressTotalBytes;
33 33
34 // Download progress indicator, probably an NSProgressIndicator or UIProgressView 34 // Download progress indicator, probably an NSProgressIndicator or UIProgressView
35 id downloadProgressDelegate; 35 id downloadProgressDelegate;
36 36
37 // Total amount downloaded so far for all requests in this queue 37 // Total amount downloaded so far for all requests in this queue
38 - int downloadProgressBytes; 38 + unsigned int downloadProgressBytes;
39 39
40 // Total amount to be downloaded for all requests in this queue - requests add to this figure as they receive Content-Length headers 40 // Total amount to be downloaded for all requests in this queue - requests add to this figure as they receive Content-Length headers
41 - int downloadProgressTotalBytes; 41 + unsigned int downloadProgressTotalBytes;
42 42
43 // When YES, the queue will cancel all requests when a request fails. Default is YES 43 // When YES, the queue will cancel all requests when a request fails. Default is YES
44 BOOL shouldCancelAllRequestsOnFailure; 44 BOOL shouldCancelAllRequestsOnFailure;
45 45
  46 + //Number of real requests (excludes HEAD requests created to manage showAccurateProgress)
46 int requestsCount; 47 int requestsCount;
47 - int requestsCompleteCount; 48 +
  49 + // When NO, this request will only update the progress indicator when it completes
  50 + // When YES, this request will update the progress indicator according to how much data it has recieved so far
  51 + // 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
  52 + // 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
  53 + // Set to YES if the size of a requests in the queue varies greatly for much more accurate results
  54 + // Default for requests in the queue is NO
  55 + BOOL showAccurateProgress;
  56 +
  57 +
48 } 58 }
49 59
  60 +// Used internally to manage HEAD requests when showAccurateProgress is YES, do not use!
  61 +- (void)addHEADOperation:(NSOperation *)operation;
50 62
51 // Called at the start of a request to add on the size of this upload to the total 63 // Called at the start of a request to add on the size of this upload to the total
52 - (void)incrementUploadSizeBy:(int)bytes; 64 - (void)incrementUploadSizeBy:(int)bytes;
@@ -60,6 +72,10 @@ @@ -60,6 +72,10 @@
60 // Called during a request when data is received to increment the progress indicator 72 // Called during a request when data is received to increment the progress indicator
61 - (void)incrementDownloadProgressBy:(int)bytes; 73 - (void)incrementDownloadProgressBy:(int)bytes;
62 74
  75 +// All ASINetworkQueues are paused when created so that total size can be calculated before the queue starts
  76 +// This method will start the queue
  77 +- (void)go;
  78 +
63 @property (assign,setter=setUploadProgressDelegate:) id uploadProgressDelegate; 79 @property (assign,setter=setUploadProgressDelegate:) id uploadProgressDelegate;
64 @property (assign,setter=setDownloadProgressDelegate:) id downloadProgressDelegate; 80 @property (assign,setter=setDownloadProgressDelegate:) id downloadProgressDelegate;
65 81
@@ -68,4 +84,5 @@ @@ -68,4 +84,5 @@
68 @property (assign) SEL queueDidFinishSelector; 84 @property (assign) SEL queueDidFinishSelector;
69 @property (assign) BOOL shouldCancelAllRequestsOnFailure; 85 @property (assign) BOOL shouldCancelAllRequestsOnFailure;
70 @property (assign) id delegate; 86 @property (assign) id delegate;
  87 +@property (assign) BOOL showAccurateProgress;
71 @end 88 @end
@@ -31,17 +31,37 @@ @@ -31,17 +31,37 @@
31 downloadProgressTotalBytes = 0; 31 downloadProgressTotalBytes = 0;
32 32
33 requestsCount = 0; 33 requestsCount = 0;
34 - requestsCompleteCount = 0; 34 +
  35 + showAccurateProgress = NO;
  36 +
  37 + [self setSuspended:YES];
35 38
36 return self; 39 return self;
37 } 40 }
38 41
  42 +- (void)go
  43 +{
  44 + if (!showAccurateProgress) {
  45 + if (downloadProgressDelegate) {
  46 + [self incrementDownloadSizeBy:requestsCount];
  47 + }
  48 + if (uploadProgressDelegate) {
  49 + [self incrementUploadSizeBy:requestsCount];
  50 + }
  51 + }
  52 + [self setSuspended:NO];
  53 +}
  54 +
39 - (void)cancelAllOperations 55 - (void)cancelAllOperations
40 { 56 {
  57 + requestsCount = 0;
41 uploadProgressBytes = 0; 58 uploadProgressBytes = 0;
42 uploadProgressTotalBytes = 0; 59 uploadProgressTotalBytes = 0;
43 downloadProgressBytes = 0; 60 downloadProgressBytes = 0;
44 downloadProgressTotalBytes = 0; 61 downloadProgressTotalBytes = 0;
  62 + [self setUploadProgressDelegate:nil];
  63 + [self setDownloadProgressDelegate:nil];
  64 + [self setDelegate:nil];
45 [super cancelAllOperations]; 65 [super cancelAllOperations];
46 } 66 }
47 67
@@ -58,7 +78,6 @@ @@ -58,7 +78,6 @@
58 [invocation setSelector:selector]; 78 [invocation setSelector:selector];
59 [invocation setArgument:&max atIndex:2]; 79 [invocation setArgument:&max atIndex:2];
60 [invocation invokeWithTarget:uploadProgressDelegate]; 80 [invocation invokeWithTarget:uploadProgressDelegate];
61 -  
62 } 81 }
63 } 82 }
64 83
@@ -79,49 +98,97 @@ @@ -79,49 +98,97 @@
79 } 98 }
80 } 99 }
81 100
  101 +- (void)addHEADOperation:(NSOperation *)operation
  102 +{
  103 + if ([operation isKindOfClass:[ASIHTTPRequest class]]) {
  104 +
  105 + ASIHTTPRequest *request = (ASIHTTPRequest *)operation;
  106 + [request setShowAccurateProgress:YES];
  107 + if (uploadProgressDelegate) {
  108 + [request setUploadProgressDelegate:self];
  109 + } else {
  110 + [request setUploadProgressDelegate:NULL];
  111 + }
  112 + if (downloadProgressDelegate) {
  113 + [request setDownloadProgressDelegate:self];
  114 + } else {
  115 + [request setDownloadProgressDelegate:NULL];
  116 + }
  117 + [request setDelegate:self];
  118 + [super addOperation:request];
  119 + }
  120 +}
  121 +
82 // Only add ASIHTTPRequests to this queue!! 122 // Only add ASIHTTPRequests to this queue!!
83 - (void)addOperation:(NSOperation *)operation 123 - (void)addOperation:(NSOperation *)operation
84 { 124 {
85 if ([operation isKindOfClass:[ASIHTTPRequest class]]) { 125 if ([operation isKindOfClass:[ASIHTTPRequest class]]) {
  126 +
86 requestsCount++; 127 requestsCount++;
  128 +
  129 + ASIHTTPRequest *request = (ASIHTTPRequest *)operation;
  130 +
  131 + if (showAccurateProgress) {
  132 +
  133 + //If this is a GET request and we want accurate progress, perform a HEAD request first to get the content-length
  134 + if ([[request requestMethod] isEqualToString:@"GET"]) {
  135 + ASIHTTPRequest *HEADRequest = [[[ASIHTTPRequest alloc] initWithURL:[request url]] autorelease];
  136 + [HEADRequest setRequestMethod:@"HEAD"];
  137 + [HEADRequest setQueuePriority:10];
  138 + [HEADRequest setMainRequest:request];
  139 + [self addHEADOperation:HEADRequest];
  140 +
  141 + [request setUseCachedContentLength:YES];
  142 + [request addDependency:HEADRequest];
  143 +
  144 + //If we want to track uploading for this request accurately, we need to add the size of the post content to the total
  145 + } else if (uploadProgressDelegate) {
  146 + [request buildPostBody];
  147 + uploadProgressTotalBytes += [request postLength];
  148 + }
  149 + }
  150 + [request setShowAccurateProgress:showAccurateProgress];
  151 +
87 if (uploadProgressDelegate) { 152 if (uploadProgressDelegate) {
88 - [(ASIHTTPRequest *)operation setUploadProgressDelegate:self]; 153 + [request setUploadProgressDelegate:self];
89 } else { 154 } else {
90 - [(ASIHTTPRequest *)operation setUploadProgressDelegate:NULL]; 155 + [request setUploadProgressDelegate:NULL];
91 } 156 }
92 if (downloadProgressDelegate) { 157 if (downloadProgressDelegate) {
93 - [(ASIHTTPRequest *)operation setDownloadProgressDelegate:self]; 158 + [request setDownloadProgressDelegate:self];
94 } else { 159 } else {
95 - [(ASIHTTPRequest *)operation setDownloadProgressDelegate:NULL]; 160 + [request setDownloadProgressDelegate:NULL];
96 } 161 }
97 - [(ASIHTTPRequest *)operation setDelegate:self]; 162 + [request setDelegate:self];
98 - [(ASIHTTPRequest *)operation setDidFailSelector:@selector(requestDidFail:)]; 163 + [request setDidFailSelector:@selector(requestDidFail:)];
99 - [(ASIHTTPRequest *)operation setDidFinishSelector:@selector(requestDidFinish:)]; 164 + [request setDidFinishSelector:@selector(requestDidFinish:)];
100 - [super addOperation:operation]; 165 + [super addOperation:request];
101 } 166 }
102 167
103 } 168 }
104 169
105 - (void)requestDidFail:(ASIHTTPRequest *)request 170 - (void)requestDidFail:(ASIHTTPRequest *)request
106 { 171 {
  172 + requestsCount--;
107 if (requestDidFailSelector) { 173 if (requestDidFailSelector) {
108 [delegate performSelector:requestDidFailSelector withObject:request]; 174 [delegate performSelector:requestDidFailSelector withObject:request];
109 } 175 }
110 if (shouldCancelAllRequestsOnFailure) { 176 if (shouldCancelAllRequestsOnFailure) {
111 [self cancelAllOperations]; 177 [self cancelAllOperations];
112 } 178 }
113 - requestsCompleteCount++;  
114 } 179 }
115 180
116 - (void)requestDidFinish:(ASIHTTPRequest *)request 181 - (void)requestDidFinish:(ASIHTTPRequest *)request
117 { 182 {
118 - requestsCompleteCount++; 183 + requestsCount--;
119 if (requestDidFinishSelector) { 184 if (requestDidFinishSelector) {
120 [delegate performSelector:requestDidFinishSelector withObject:request]; 185 [delegate performSelector:requestDidFinishSelector withObject:request];
121 } 186 }
122 - if (queueDidFinishSelector && requestsCompleteCount == requestsCount) { 187 + if (requestsCount == 0) {
  188 + if (queueDidFinishSelector) {
123 [delegate performSelector:queueDidFinishSelector withObject:self]; 189 [delegate performSelector:queueDidFinishSelector withObject:self];
124 } 190 }
  191 + }
125 } 192 }
126 193
127 - (void)incrementUploadSizeBy:(int)bytes 194 - (void)incrementUploadSizeBy:(int)bytes
@@ -159,7 +226,7 @@ @@ -159,7 +226,7 @@
159 return; 226 return;
160 } 227 }
161 downloadProgressBytes += bytes; 228 downloadProgressBytes += bytes;
162 - 229 + //NSLog(@"%hu/%hu",downloadProgressBytes,downloadProgressTotalBytes);
163 double progress = (downloadProgressBytes*1.0)/(downloadProgressTotalBytes*1.0); 230 double progress = (downloadProgressBytes*1.0)/(downloadProgressTotalBytes*1.0);
164 [ASIHTTPRequest setProgress:progress forProgressIndicator:downloadProgressDelegate]; 231 [ASIHTTPRequest setProgress:progress forProgressIndicator:downloadProgressDelegate];
165 } 232 }
@@ -173,6 +240,7 @@ @@ -173,6 +240,7 @@
173 } 240 }
174 241
175 242
  243 +
176 @synthesize uploadProgressDelegate; 244 @synthesize uploadProgressDelegate;
177 @synthesize downloadProgressDelegate; 245 @synthesize downloadProgressDelegate;
178 @synthesize requestDidFinishSelector; 246 @synthesize requestDidFinishSelector;
@@ -180,4 +248,6 @@ @@ -180,4 +248,6 @@
180 @synthesize queueDidFinishSelector; 248 @synthesize queueDidFinishSelector;
181 @synthesize shouldCancelAllRequestsOnFailure; 249 @synthesize shouldCancelAllRequestsOnFailure;
182 @synthesize delegate; 250 @synthesize delegate;
  251 +@synthesize showAccurateProgress;
  252 +
183 @end 253 @end
@@ -21,21 +21,23 @@ @@ -21,21 +21,23 @@
21 networkQueue = [[ASINetworkQueue alloc] init]; 21 networkQueue = [[ASINetworkQueue alloc] init];
22 [networkQueue setDownloadProgressDelegate:self]; 22 [networkQueue setDownloadProgressDelegate:self];
23 [networkQueue setDelegate:self]; 23 [networkQueue setDelegate:self];
24 - [networkQueue setRequestDidFinishSelector:@selector(queueFinished:)]; 24 + [networkQueue setShowAccurateProgress:NO];
  25 + [networkQueue setQueueDidFinishSelector:@selector(queueFinished:)];
25 26
26 NSURL *url; 27 NSURL *url;
27 - url = [[[NSURL alloc] initWithString:@"http://allseeing-i.com/asi-http-request/tests/first"] autorelease]; 28 + url = [[[NSURL alloc] initWithString:@"http://allseeing-i.com/i/logo.png"] autorelease];
28 ASIHTTPRequest *request1 = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease]; 29 ASIHTTPRequest *request1 = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease];
29 [networkQueue addOperation:request1]; 30 [networkQueue addOperation:request1];
30 31
31 - url = [[[NSURL alloc] initWithString:@"http://allseeing-i.com/asi-http-request/tests/second"] autorelease]; 32 + url = [[[NSURL alloc] initWithString:@"http://allseeing-i.com/i/trailsnetwork.png"] autorelease];
32 ASIHTTPRequest *request2 = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease]; 33 ASIHTTPRequest *request2 = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease];
33 [networkQueue addOperation:request2]; 34 [networkQueue addOperation:request2];
34 35
35 - url = [[[NSURL alloc] initWithString:@"http://allseeing-i.com/asi-http-request/tests/third"] autorelease]; 36 + url = [[[NSURL alloc] initWithString:@"http://allseeing-i.com/sharedspace20.png"] autorelease];
36 ASIHTTPRequest *request3 = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease]; 37 ASIHTTPRequest *request3 = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease];
37 [networkQueue addOperation:request3]; 38 [networkQueue addOperation:request3];
38 39
  40 + [networkQueue go];
39 41
40 NSDate* endDate = [NSDate distantFuture]; 42 NSDate* endDate = [NSDate distantFuture];
41 while (!complete) { 43 while (!complete) {
@@ -45,9 +47,39 @@ @@ -45,9 +47,39 @@
45 BOOL success = (progress == 1.0); 47 BOOL success = (progress == 1.0);
46 STAssertTrue(success,@"Failed to increment progress properly"); 48 STAssertTrue(success,@"Failed to increment progress properly");
47 49
  50 + //Now test again with accurate progress
  51 +
  52 + [networkQueue cancelAllOperations];
  53 + [networkQueue setShowAccurateProgress:YES];
  54 +
  55 + url = [[[NSURL alloc] initWithString:@"http://allseeing-i.com/i/logo.png"] autorelease];
  56 + request1 = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease];
  57 + [networkQueue addOperation:request1];
  58 +
  59 + url = [[[NSURL alloc] initWithString:@"http://allseeing-i.com/i/trailsnetwork.png"] autorelease];
  60 + request2 = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease];
  61 + [networkQueue addOperation:request2];
  62 +
  63 + url = [[[NSURL alloc] initWithString:@"http://allseeing-i.com/sharedspace20.png"] autorelease];
  64 + request3 = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease];
  65 + [networkQueue addOperation:request3];
  66 +
  67 + [networkQueue go];
  68 +
  69 + endDate = [NSDate distantFuture];
  70 + while (!complete) {
  71 + [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:endDate];
  72 + }
  73 +
  74 + success = (progress == 1.0);
  75 + STAssertTrue(success,@"Failed to increment progress properly");
  76 +
  77 +
48 [networkQueue release]; 78 [networkQueue release];
49 79
50 80
  81 +
  82 +
51 } 83 }
52 84
53 - (void)setProgress:(float)newProgress 85 - (void)setProgress:(float)newProgress
@@ -87,6 +119,7 @@ @@ -87,6 +119,7 @@
87 ASIHTTPRequest *request5 = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease]; 119 ASIHTTPRequest *request5 = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease];
88 [networkQueue addOperation:request5]; 120 [networkQueue addOperation:request5];
89 121
  122 + [networkQueue go];
90 123
91 NSDate* endDate = [NSDate distantFuture]; 124 NSDate* endDate = [NSDate distantFuture];
92 while (!complete) { 125 while (!complete) {
@@ -155,6 +188,8 @@ @@ -155,6 +188,8 @@
155 requestThatShouldFail = [[ASIHTTPRequest alloc] initWithURL:url]; 188 requestThatShouldFail = [[ASIHTTPRequest alloc] initWithURL:url];
156 [networkQueue addOperation:requestThatShouldFail]; 189 [networkQueue addOperation:requestThatShouldFail];
157 190
  191 + [networkQueue go];
  192 +
158 NSDate* endDate = [NSDate distantFuture]; 193 NSDate* endDate = [NSDate distantFuture];
159 while (!complete) { 194 while (!complete) {
160 [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:endDate]; 195 [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:endDate];
@@ -16,6 +16,8 @@ @@ -16,6 +16,8 @@
16 IBOutlet NSWindow *window; 16 IBOutlet NSWindow *window;
17 IBOutlet NSWindow *loginWindow; 17 IBOutlet NSWindow *loginWindow;
18 18
  19 + IBOutlet NSButton *showAccurateProgress;
  20 +
19 IBOutlet NSTextField *host; 21 IBOutlet NSTextField *host;
20 IBOutlet NSTextField *realm; 22 IBOutlet NSTextField *realm;
21 IBOutlet NSTextField *username; 23 IBOutlet NSTextField *username;
@@ -43,6 +43,7 @@ @@ -43,6 +43,7 @@
43 - (IBAction)URLFetchWithProgress:(id)sender 43 - (IBAction)URLFetchWithProgress:(id)sender
44 { 44 {
45 [networkQueue cancelAllOperations]; 45 [networkQueue cancelAllOperations];
  46 + [networkQueue setShowAccurateProgress:YES];
46 [networkQueue setDownloadProgressDelegate:progressIndicator]; 47 [networkQueue setDownloadProgressDelegate:progressIndicator];
47 [networkQueue setDelegate:self]; 48 [networkQueue setDelegate:self];
48 [networkQueue setRequestDidFinishSelector:@selector(URLFetchWithProgressComplete:)]; 49 [networkQueue setRequestDidFinishSelector:@selector(URLFetchWithProgressComplete:)];
@@ -50,6 +51,7 @@ @@ -50,6 +51,7 @@
50 ASIHTTPRequest *request = [[[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:@"http://trails-network.net/Downloads/MemexTrails_1.0b1.zip"]] autorelease]; 51 ASIHTTPRequest *request = [[[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:@"http://trails-network.net/Downloads/MemexTrails_1.0b1.zip"]] autorelease];
51 [request setDownloadDestinationPath:[[[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"MemexTrails_1.0b1.zip"]]; 52 [request setDownloadDestinationPath:[[[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"MemexTrails_1.0b1.zip"]];
52 [networkQueue addOperation:request]; 53 [networkQueue addOperation:request];
  54 + [networkQueue go];
53 } 55 }
54 56
55 - (void)URLFetchWithProgressComplete:(ASIHTTPRequest *)request 57 - (void)URLFetchWithProgressComplete:(ASIHTTPRequest *)request
@@ -71,6 +73,7 @@ @@ -71,6 +73,7 @@
71 [networkQueue setDownloadProgressDelegate:progressIndicator]; 73 [networkQueue setDownloadProgressDelegate:progressIndicator];
72 [networkQueue setRequestDidFinishSelector:@selector(imageFetchComplete:)]; 74 [networkQueue setRequestDidFinishSelector:@selector(imageFetchComplete:)];
73 [networkQueue setDelegate:self]; 75 [networkQueue setDelegate:self];
  76 + [networkQueue setShowAccurateProgress:([showAccurateProgress state] == NSOnState)];
74 77
75 ASIHTTPRequest *request; 78 ASIHTTPRequest *request;
76 79
@@ -85,6 +88,9 @@ @@ -85,6 +88,9 @@
85 request = [[[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:@"http://allseeing-i.com/i/sharedspace20.png"]] autorelease]; 88 request = [[[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:@"http://allseeing-i.com/i/sharedspace20.png"]] autorelease];
86 [request setDownloadDestinationPath:[[[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"3.png"]]; 89 [request setDownloadDestinationPath:[[[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"3.png"]];
87 [networkQueue addOperation:request]; 90 [networkQueue addOperation:request];
  91 +
  92 +
  93 + [networkQueue go];
88 } 94 }
89 95
90 96
@@ -118,7 +124,7 @@ @@ -118,7 +124,7 @@
118 request = [[[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:@"http://allseeing-i.com/top_secret/"]] autorelease]; 124 request = [[[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:@"http://allseeing-i.com/top_secret/"]] autorelease];
119 [request setUseKeychainPersistance:[keychainCheckbox state]]; 125 [request setUseKeychainPersistance:[keychainCheckbox state]];
120 [networkQueue addOperation:request]; 126 [networkQueue addOperation:request];
121 - 127 + [networkQueue go];
122 128
123 } 129 }
124 130
@@ -166,19 +172,19 @@ @@ -166,19 +172,19 @@
166 [data writeToFile:path atomically:NO]; 172 [data writeToFile:path atomically:NO];
167 173
168 [networkQueue cancelAllOperations]; 174 [networkQueue cancelAllOperations];
169 - [progressIndicator setDoubleValue:0]; 175 + [networkQueue setShowAccurateProgress:YES];
170 - ASIFormDataRequest *request = [[[ASIFormDataRequest alloc] initWithURL:[NSURL URLWithString:@"http://allseeing-i.com/ignore"]] autorelease]; 176 + [networkQueue setUploadProgressDelegate:progressIndicator];
171 - [request setDelegate:self]; 177 + [networkQueue setDelegate:self];
172 178
  179 + ASIFormDataRequest *request = [[[ASIFormDataRequest alloc] initWithURL:[NSURL URLWithString:@"http://allseeing-i.com/ignore"]] autorelease];
173 [request setPostValue:@"test" forKey:@"value1"]; 180 [request setPostValue:@"test" forKey:@"value1"];
174 [request setPostValue:@"test" forKey:@"value2"]; 181 [request setPostValue:@"test" forKey:@"value2"];
175 [request setPostValue:@"test" forKey:@"value3"]; 182 [request setPostValue:@"test" forKey:@"value3"];
176 -  
177 [request setFile:path forKey:@"file"]; 183 [request setFile:path forKey:@"file"];
178 184
179 - [networkQueue setUploadProgressDelegate:progressIndicator];  
180 - [networkQueue addOperation:request];  
181 185
  186 + [networkQueue addOperation:request];
  187 + [networkQueue go];
182 } 188 }
183 189
184 190
@@ -8,6 +8,7 @@ @@ -8,6 +8,7 @@
8 <string key="IBDocument.HIToolboxVersion">352.00</string> 8 <string key="IBDocument.HIToolboxVersion">352.00</string>
9 <object class="NSMutableArray" key="IBDocument.EditedObjectIDs"> 9 <object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
10 <bool key="EncodedWithXMLCoder">YES</bool> 10 <bool key="EncodedWithXMLCoder">YES</bool>
  11 + <integer value="440"/>
11 </object> 12 </object>
12 <object class="NSArray" key="IBDocument.PluginDependencies"> 13 <object class="NSArray" key="IBDocument.PluginDependencies">
13 <bool key="EncodedWithXMLCoder">YES</bool> 14 <bool key="EncodedWithXMLCoder">YES</bool>
@@ -771,7 +772,6 @@ @@ -771,7 +772,6 @@
771 <object class="NSPSMatrix" key="NSDrawMatrix"/> 772 <object class="NSPSMatrix" key="NSDrawMatrix"/>
772 <string key="NSFrame">{{11, 16}, {151, 20}}</string> 773 <string key="NSFrame">{{11, 16}, {151, 20}}</string>
773 <reference key="NSSuperview" ref="439893737"/> 774 <reference key="NSSuperview" ref="439893737"/>
774 - <reference key="NSWindow"/>  
775 <int key="NSpiFlags">16392</int> 775 <int key="NSpiFlags">16392</int>
776 <double key="NSMaxValue">1.000000e+00</double> 776 <double key="NSMaxValue">1.000000e+00</double>
777 </object> 777 </object>
@@ -780,7 +780,6 @@ @@ -780,7 +780,6 @@
780 <int key="NSvFlags">12</int> 780 <int key="NSvFlags">12</int>
781 <string key="NSFrame">{{6, 34}, {461, 289}}</string> 781 <string key="NSFrame">{{6, 34}, {461, 289}}</string>
782 <reference key="NSSuperview" ref="439893737"/> 782 <reference key="NSSuperview" ref="439893737"/>
783 - <reference key="NSWindow"/>  
784 <object class="NSMutableArray" key="NSTabViewItems"> 783 <object class="NSMutableArray" key="NSTabViewItems">
785 <bool key="EncodedWithXMLCoder">YES</bool> 784 <bool key="EncodedWithXMLCoder">YES</bool>
786 <object class="NSTabViewItem" id="601615678"> 785 <object class="NSTabViewItem" id="601615678">
@@ -1077,7 +1076,6 @@ cmVhZC4</string> @@ -1077,7 +1076,6 @@ cmVhZC4</string>
1077 </object> 1076 </object>
1078 <string key="NSFrame">{{14, 163}, {139, 72}}</string> 1077 <string key="NSFrame">{{14, 163}, {139, 72}}</string>
1079 <reference key="NSSuperview" ref="624078948"/> 1078 <reference key="NSSuperview" ref="624078948"/>
1080 - <reference key="NSWindow"/>  
1081 <bool key="NSEnabled">YES</bool> 1079 <bool key="NSEnabled">YES</bool>
1082 <object class="NSImageCell" key="NSCell" id="650701610"> 1080 <object class="NSImageCell" key="NSCell" id="650701610">
1083 <int key="NSCellFlags">130560</int> 1081 <int key="NSCellFlags">130560</int>
@@ -1106,7 +1104,6 @@ cmVhZC4</string> @@ -1106,7 +1104,6 @@ cmVhZC4</string>
1106 </object> 1104 </object>
1107 <string key="NSFrame">{{14, 84}, {139, 72}}</string> 1105 <string key="NSFrame">{{14, 84}, {139, 72}}</string>
1108 <reference key="NSSuperview" ref="624078948"/> 1106 <reference key="NSSuperview" ref="624078948"/>
1109 - <reference key="NSWindow"/>  
1110 <bool key="NSEnabled">YES</bool> 1107 <bool key="NSEnabled">YES</bool>
1111 <object class="NSImageCell" key="NSCell" id="737332382"> 1108 <object class="NSImageCell" key="NSCell" id="737332382">
1112 <int key="NSCellFlags">130560</int> 1109 <int key="NSCellFlags">130560</int>
@@ -1135,7 +1132,6 @@ cmVhZC4</string> @@ -1135,7 +1132,6 @@ cmVhZC4</string>
1135 </object> 1132 </object>
1136 <string key="NSFrame">{{14, 4}, {139, 72}}</string> 1133 <string key="NSFrame">{{14, 4}, {139, 72}}</string>
1137 <reference key="NSSuperview" ref="624078948"/> 1134 <reference key="NSSuperview" ref="624078948"/>
1138 - <reference key="NSWindow"/>  
1139 <bool key="NSEnabled">YES</bool> 1135 <bool key="NSEnabled">YES</bool>
1140 <object class="NSImageCell" key="NSCell" id="543138502"> 1136 <object class="NSImageCell" key="NSCell" id="543138502">
1141 <int key="NSCellFlags">130560</int> 1137 <int key="NSCellFlags">130560</int>
@@ -1152,7 +1148,6 @@ cmVhZC4</string> @@ -1152,7 +1148,6 @@ cmVhZC4</string>
1152 <int key="NSvFlags">268</int> 1148 <int key="NSvFlags">268</int>
1153 <string key="NSFrame">{{156, 138}, {62, 32}}</string> 1149 <string key="NSFrame">{{156, 138}, {62, 32}}</string>
1154 <reference key="NSSuperview" ref="624078948"/> 1150 <reference key="NSSuperview" ref="624078948"/>
1155 - <reference key="NSWindow"/>  
1156 <bool key="NSEnabled">YES</bool> 1151 <bool key="NSEnabled">YES</bool>
1157 <object class="NSButtonCell" key="NSCell" id="11946473"> 1152 <object class="NSButtonCell" key="NSCell" id="11946473">
1158 <int key="NSCellFlags">67239424</int> 1153 <int key="NSCellFlags">67239424</int>
@@ -1173,7 +1168,6 @@ cmVhZC4</string> @@ -1173,7 +1168,6 @@ cmVhZC4</string>
1173 <int key="NSvFlags">268</int> 1168 <int key="NSvFlags">268</int>
1174 <string key="NSFrame">{{159, 181}, {268, 51}}</string> 1169 <string key="NSFrame">{{159, 181}, {268, 51}}</string>
1175 <reference key="NSSuperview" ref="624078948"/> 1170 <reference key="NSSuperview" ref="624078948"/>
1176 - <reference key="NSWindow"/>  
1177 <bool key="NSEnabled">YES</bool> 1171 <bool key="NSEnabled">YES</bool>
1178 <object class="NSTextFieldCell" key="NSCell" id="118640000"> 1172 <object class="NSTextFieldCell" key="NSCell" id="118640000">
1179 <int key="NSCellFlags">67239424</int> 1173 <int key="NSCellFlags">67239424</int>
@@ -1185,10 +1179,36 @@ cmVhZC4</string> @@ -1185,10 +1179,36 @@ cmVhZC4</string>
1185 <reference key="NSTextColor" ref="981560827"/> 1179 <reference key="NSTextColor" ref="981560827"/>
1186 </object> 1180 </object>
1187 </object> 1181 </object>
  1182 + <object class="NSButton" id="986741348">
  1183 + <reference key="NSNextResponder" ref="624078948"/>
  1184 + <int key="NSvFlags">268</int>
  1185 + <string key="NSFrame">{{160, 110}, {172, 18}}</string>
  1186 + <reference key="NSSuperview" ref="624078948"/>
  1187 + <bool key="NSEnabled">YES</bool>
  1188 + <object class="NSButtonCell" key="NSCell" id="588048761">
  1189 + <int key="NSCellFlags">67239424</int>
  1190 + <int key="NSCellFlags2">0</int>
  1191 + <string key="NSContents">Show accurate progress</string>
  1192 + <reference key="NSSupport" ref="584670792"/>
  1193 + <reference key="NSControlView" ref="986741348"/>
  1194 + <int key="NSButtonFlags">1211912703</int>
  1195 + <int key="NSButtonFlags2">130</int>
  1196 + <object class="NSCustomResource" key="NSNormalImage" id="385619933">
  1197 + <string key="NSClassName">NSImage</string>
  1198 + <string key="NSResourceName">NSSwitch</string>
  1199 + </object>
  1200 + <object class="NSButtonImageSource" key="NSAlternateImage" id="938042219">
  1201 + <string key="NSImageName">NSSwitch</string>
  1202 + </object>
  1203 + <string key="NSAlternateContents"/>
  1204 + <string key="NSKeyEquivalent"/>
  1205 + <int key="NSPeriodicDelay">200</int>
  1206 + <int key="NSPeriodicInterval">25</int>
  1207 + </object>
  1208 + </object>
1188 </object> 1209 </object>
1189 <string key="NSFrame">{{10, 33}, {441, 243}}</string> 1210 <string key="NSFrame">{{10, 33}, {441, 243}}</string>
1190 <reference key="NSSuperview" ref="495298985"/> 1211 <reference key="NSSuperview" ref="495298985"/>
1191 - <reference key="NSWindow"/>  
1192 </object> 1212 </object>
1193 <string key="NSLabel">Queue</string> 1213 <string key="NSLabel">Queue</string>
1194 <reference key="NSColor" ref="482475293"/> 1214 <reference key="NSColor" ref="482475293"/>
@@ -1253,13 +1273,8 @@ c3N3b3JkLCBlbnRlciAndG9wc2VjcmV0JyBmb3IgYm90aC4</string> @@ -1253,13 +1273,8 @@ c3N3b3JkLCBlbnRlciAndG9wc2VjcmV0JyBmb3IgYm90aC4</string>
1253 <reference key="NSControlView" ref="448108793"/> 1273 <reference key="NSControlView" ref="448108793"/>
1254 <int key="NSButtonFlags">1211912703</int> 1274 <int key="NSButtonFlags">1211912703</int>
1255 <int key="NSButtonFlags2">2</int> 1275 <int key="NSButtonFlags2">2</int>
1256 - <object class="NSCustomResource" key="NSNormalImage"> 1276 + <reference key="NSNormalImage" ref="385619933"/>
1257 - <string key="NSClassName">NSImage</string> 1277 + <reference key="NSAlternateImage" ref="938042219"/>
1258 - <string key="NSResourceName">NSSwitch</string>  
1259 - </object>  
1260 - <object class="NSButtonImageSource" key="NSAlternateImage">  
1261 - <string key="NSImageName">NSSwitch</string>  
1262 - </object>  
1263 <string key="NSAlternateContents"/> 1278 <string key="NSAlternateContents"/>
1264 <string key="NSKeyEquivalent"/> 1279 <string key="NSKeyEquivalent"/>
1265 <int key="NSPeriodicDelay">200</int> 1280 <int key="NSPeriodicDelay">200</int>
@@ -1369,7 +1384,6 @@ c3N3b3JkLCBlbnRlciAndG9wc2VjcmV0JyBmb3IgYm90aC4</string> @@ -1369,7 +1384,6 @@ c3N3b3JkLCBlbnRlciAndG9wc2VjcmV0JyBmb3IgYm90aC4</string>
1369 </object> 1384 </object>
1370 <string key="NSFrameSize">{480, 337}</string> 1385 <string key="NSFrameSize">{480, 337}</string>
1371 <reference key="NSSuperview"/> 1386 <reference key="NSSuperview"/>
1372 - <reference key="NSWindow"/>  
1373 </object> 1387 </object>
1374 <string key="NSScreenRect">{{0, 0}, {1440, 878}}</string> 1388 <string key="NSScreenRect">{{0, 0}, {1440, 878}}</string>
1375 <string key="NSMaxSize">{3.40282e+38, 3.40282e+38}</string> 1389 <string key="NSMaxSize">{3.40282e+38, 3.40282e+38}</string>
@@ -2062,6 +2076,14 @@ c3N3b3JkLCBlbnRlciAndG9wc2VjcmV0JyBmb3IgYm90aC4</string> @@ -2062,6 +2076,14 @@ c3N3b3JkLCBlbnRlciAndG9wc2VjcmV0JyBmb3IgYm90aC4</string>
2062 </object> 2076 </object>
2063 <int key="connectionID">506</int> 2077 <int key="connectionID">506</int>
2064 </object> 2078 </object>
  2079 + <object class="IBConnectionRecord">
  2080 + <object class="IBOutletConnection" key="connection">
  2081 + <string key="label">showAccurateProgress</string>
  2082 + <reference key="source" ref="1010338297"/>
  2083 + <reference key="destination" ref="986741348"/>
  2084 + </object>
  2085 + <int key="connectionID">515</int>
  2086 + </object>
2065 </object> 2087 </object>
2066 <object class="IBMutableOrderedSet" key="objectRecords"> 2088 <object class="IBMutableOrderedSet" key="objectRecords">
2067 <object class="NSArray" key="orderedObjects"> 2089 <object class="NSArray" key="orderedObjects">
@@ -2911,6 +2933,7 @@ c3N3b3JkLCBlbnRlciAndG9wc2VjcmV0JyBmb3IgYm90aC4</string> @@ -2911,6 +2933,7 @@ c3N3b3JkLCBlbnRlciAndG9wc2VjcmV0JyBmb3IgYm90aC4</string>
2911 <reference ref="448639965"/> 2933 <reference ref="448639965"/>
2912 <reference ref="919017202"/> 2934 <reference ref="919017202"/>
2913 <reference ref="1057121416"/> 2935 <reference ref="1057121416"/>
  2936 + <reference ref="986741348"/>
2914 </object> 2937 </object>
2915 <reference key="parent" ref="725395930"/> 2938 <reference key="parent" ref="725395930"/>
2916 </object> 2939 </object>
@@ -3239,6 +3262,20 @@ c3N3b3JkLCBlbnRlciAndG9wc2VjcmV0JyBmb3IgYm90aC4</string> @@ -3239,6 +3262,20 @@ c3N3b3JkLCBlbnRlciAndG9wc2VjcmV0JyBmb3IgYm90aC4</string>
3239 <reference key="object" ref="850742861"/> 3262 <reference key="object" ref="850742861"/>
3240 <reference key="parent" ref="949500094"/> 3263 <reference key="parent" ref="949500094"/>
3241 </object> 3264 </object>
  3265 + <object class="IBObjectRecord">
  3266 + <int key="objectID">513</int>
  3267 + <reference key="object" ref="986741348"/>
  3268 + <object class="NSMutableArray" key="children">
  3269 + <bool key="EncodedWithXMLCoder">YES</bool>
  3270 + <reference ref="588048761"/>
  3271 + </object>
  3272 + <reference key="parent" ref="624078948"/>
  3273 + </object>
  3274 + <object class="IBObjectRecord">
  3275 + <int key="objectID">514</int>
  3276 + <reference key="object" ref="588048761"/>
  3277 + <reference key="parent" ref="986741348"/>
  3278 + </object>
3242 </object> 3279 </object>
3243 </object> 3280 </object>
3244 <object class="NSMutableDictionary" key="flattenedProperties"> 3281 <object class="NSMutableDictionary" key="flattenedProperties">
@@ -3461,6 +3498,8 @@ c3N3b3JkLCBlbnRlciAndG9wc2VjcmV0JyBmb3IgYm90aC4</string> @@ -3461,6 +3498,8 @@ c3N3b3JkLCBlbnRlciAndG9wc2VjcmV0JyBmb3IgYm90aC4</string>
3461 <string>503.IBPluginDependency</string> 3498 <string>503.IBPluginDependency</string>
3462 <string>504.IBPluginDependency</string> 3499 <string>504.IBPluginDependency</string>
3463 <string>505.IBPluginDependency</string> 3500 <string>505.IBPluginDependency</string>
  3501 + <string>513.IBPluginDependency</string>
  3502 + <string>514.IBPluginDependency</string>
3464 <string>56.IBPluginDependency</string> 3503 <string>56.IBPluginDependency</string>
3465 <string>56.ImportedFromIB2</string> 3504 <string>56.ImportedFromIB2</string>
3466 <string>57.IBPluginDependency</string> 3505 <string>57.IBPluginDependency</string>
@@ -3713,6 +3752,8 @@ c3N3b3JkLCBlbnRlciAndG9wc2VjcmV0JyBmb3IgYm90aC4</string> @@ -3713,6 +3752,8 @@ c3N3b3JkLCBlbnRlciAndG9wc2VjcmV0JyBmb3IgYm90aC4</string>
3713 <string>com.apple.InterfaceBuilder.CocoaPlugin</string> 3752 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
3714 <string>com.apple.InterfaceBuilder.CocoaPlugin</string> 3753 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
3715 <string>com.apple.InterfaceBuilder.CocoaPlugin</string> 3754 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
  3755 + <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
  3756 + <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
3716 <reference ref="9"/> 3757 <reference ref="9"/>
3717 <string>com.apple.InterfaceBuilder.CocoaPlugin</string> 3758 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
3718 <reference ref="9"/> 3759 <reference ref="9"/>
@@ -3766,7 +3807,7 @@ c3N3b3JkLCBlbnRlciAndG9wc2VjcmV0JyBmb3IgYm90aC4</string> @@ -3766,7 +3807,7 @@ c3N3b3JkLCBlbnRlciAndG9wc2VjcmV0JyBmb3IgYm90aC4</string>
3766 </object> 3807 </object>
3767 </object> 3808 </object>
3768 <nil key="sourceID"/> 3809 <nil key="sourceID"/>
3769 - <int key="maxID">506</int> 3810 + <int key="maxID">515</int>
3770 </object> 3811 </object>
3771 <object class="IBClassDescriber" key="IBDocument.Classes"> 3812 <object class="IBClassDescriber" key="IBDocument.Classes">
3772 <object class="NSMutableArray" key="referencedPartialClassDescriptions"> 3813 <object class="NSMutableArray" key="referencedPartialClassDescriptions">
@@ -3810,6 +3851,7 @@ c3N3b3JkLCBlbnRlciAndG9wc2VjcmV0JyBmb3IgYm90aC4</string> @@ -3810,6 +3851,7 @@ c3N3b3JkLCBlbnRlciAndG9wc2VjcmV0JyBmb3IgYm90aC4</string>
3810 <string>password</string> 3851 <string>password</string>
3811 <string>progressIndicator</string> 3852 <string>progressIndicator</string>
3812 <string>realm</string> 3853 <string>realm</string>
  3854 + <string>showAccurateProgress</string>
3813 <string>topSecretInfo</string> 3855 <string>topSecretInfo</string>
3814 <string>username</string> 3856 <string>username</string>
3815 <string>window</string> 3857 <string>window</string>
@@ -3827,6 +3869,7 @@ c3N3b3JkLCBlbnRlciAndG9wc2VjcmV0JyBmb3IgYm90aC4</string> @@ -3827,6 +3869,7 @@ c3N3b3JkLCBlbnRlciAndG9wc2VjcmV0JyBmb3IgYm90aC4</string>
3827 <string>NSTextField</string> 3869 <string>NSTextField</string>
3828 <string>NSProgressIndicator</string> 3870 <string>NSProgressIndicator</string>
3829 <string>NSTextField</string> 3871 <string>NSTextField</string>
  3872 + <string>NSButton</string>
3830 <string>NSTextField</string> 3873 <string>NSTextField</string>
3831 <string>NSTextField</string> 3874 <string>NSTextField</string>
3832 <string>NSWindow</string> 3875 <string>NSWindow</string>
@@ -38,6 +38,8 @@ @@ -38,6 +38,8 @@
38 38
39 request = [[[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:@"http://allseeing-i.com/i/sharedspace20.png"]] autorelease]; 39 request = [[[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:@"http://allseeing-i.com/i/sharedspace20.png"]] autorelease];
40 [networkQueue addOperation:request]; 40 [networkQueue addOperation:request];
  41 +
  42 + [networkQueue go];
41 } 43 }
42 44
43 45