Remove unnecessary code and resources
[pithos-ios] / Classes / ASINetworkQueue.m
1 //
2 //  ASINetworkQueue.m
3 //  Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
4 //
5 //  Created by Ben Copsey on 07/11/2008.
6 //  Copyright 2008-2009 All-Seeing Interactive. All rights reserved.
7 //
8
9 #import "ASINetworkQueue.h"
10 #import "ASIHTTPRequest.h"
11
12 // Private stuff
13 @interface ASINetworkQueue ()
14         - (void)resetProgressDelegate:(id *)progressDelegate;
15         @property (assign) int requestsCount;
16 @end
17
18 @implementation ASINetworkQueue
19
20 - (id)init
21 {
22         self = [super init];
23         [self setShouldCancelAllRequestsOnFailure:YES];
24         [self setMaxConcurrentOperationCount:4];
25         [self setSuspended:YES];
26         
27         return self;
28 }
29
30 + (id)queue
31 {
32         return [[[self alloc] init] autorelease];
33 }
34
35 - (void)dealloc
36 {
37         //We need to clear the queue on any requests that haven't got around to cleaning up yet, as otherwise they'll try to let us know if something goes wrong, and we'll be long gone by then
38         for (ASIHTTPRequest *request in [self operations]) {
39                 [request setQueue:nil];
40         }
41         [userInfo release];
42         [super dealloc];
43 }
44
45 - (void)setSuspended:(BOOL)suspend
46 {
47         [super setSuspended:suspend];
48 }
49
50 - (void)reset
51 {
52         [self cancelAllOperations];
53         [self setDelegate:nil];
54         [self setDownloadProgressDelegate:nil];
55         [self setUploadProgressDelegate:nil];
56         [self setRequestDidStartSelector:NULL];
57         [self setRequestDidReceiveResponseHeadersSelector:NULL];
58         [self setRequestDidFailSelector:NULL];
59         [self setRequestDidFinishSelector:NULL];
60         [self setQueueDidFinishSelector:NULL];
61         [self setSuspended:YES];
62 }
63
64
65 - (void)go
66 {
67         [self setSuspended:NO];
68 }
69
70 - (void)cancelAllOperations
71 {
72         [self setBytesUploadedSoFar:0];
73         [self setTotalBytesToUpload:0];
74         [self setBytesDownloadedSoFar:0];
75         [self setTotalBytesToDownload:0];
76         [super cancelAllOperations];
77 }
78
79 - (void)setUploadProgressDelegate:(id)newDelegate
80 {
81         uploadProgressDelegate = newDelegate;
82         [self resetProgressDelegate:&uploadProgressDelegate];
83
84 }
85
86 - (void)setDownloadProgressDelegate:(id)newDelegate
87 {
88         downloadProgressDelegate = newDelegate;
89         [self resetProgressDelegate:&downloadProgressDelegate];
90 }
91
92 - (void)resetProgressDelegate:(id *)progressDelegate
93 {
94 #if !TARGET_OS_IPHONE
95         // If the uploadProgressDelegate is an NSProgressIndicator, we set its MaxValue to 1.0 so we can treat it similarly to UIProgressViews
96         SEL selector = @selector(setMaxValue:);
97         if ([*progressDelegate respondsToSelector:selector]) {
98                 double max = 1.0;
99                 [ASIHTTPRequest performSelector:selector onTarget:progressDelegate withObject:nil amount:&max callerToRetain:nil];
100         }
101         selector = @selector(setDoubleValue:);
102         if ([*progressDelegate respondsToSelector:selector]) {
103                 double value = 0.0;
104                 [ASIHTTPRequest performSelector:selector onTarget:progressDelegate withObject:nil amount:&value callerToRetain:nil];
105         }
106 #else
107         SEL selector = @selector(setProgress:);
108         if ([*progressDelegate respondsToSelector:selector]) {
109                 float value = 0.0f;
110                 [ASIHTTPRequest performSelector:selector onTarget:progressDelegate withObject:nil amount:&value callerToRetain:nil];
111         }
112 #endif
113 }
114
115 - (void)addHEADOperation:(NSOperation *)operation
116 {
117         if ([operation isKindOfClass:[ASIHTTPRequest class]]) {
118                 
119                 ASIHTTPRequest *request = (ASIHTTPRequest *)operation;
120                 [request setRequestMethod:@"HEAD"];
121                 [request setQueuePriority:10];
122                 [request setShowAccurateProgress:YES];
123                 [request setQueue:self];
124                 
125                 // Important - we are calling NSOperation's add method - we don't want to add this as a normal request!
126                 [super addOperation:request];
127         }
128 }
129
130 // Only add ASIHTTPRequests to this queue!!
131 - (void)addOperation:(NSOperation *)operation
132 {
133         if (![operation isKindOfClass:[ASIHTTPRequest class]]) {
134                 [NSException raise:@"AttemptToAddInvalidRequest" format:@"Attempted to add an object that was not an ASIHTTPRequest to an ASINetworkQueue"];
135         }
136                 
137         [self setRequestsCount:[self requestsCount]+1];
138         
139         ASIHTTPRequest *request = (ASIHTTPRequest *)operation;
140         
141         if ([self showAccurateProgress]) {
142                 
143                 // Force the request to build its body (this may change requestMethod)
144                 [request buildPostBody];
145                 
146                 // If this is a GET request and we want accurate progress, perform a HEAD request first to get the content-length
147                 // We'll only do this before the queue is started
148                 // 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
149                 // Instead, they'll update the total progress if and when they receive a content-length header
150                 if ([[request requestMethod] isEqualToString:@"GET"]) {
151                         if ([self isSuspended]) {
152                                 ASIHTTPRequest *HEADRequest = [request HEADRequest];
153                                 [self addHEADOperation:HEADRequest];
154                                 [request addDependency:HEADRequest];
155                                 if ([request shouldResetDownloadProgress]) {
156                                         [self resetProgressDelegate:&downloadProgressDelegate];
157                                         [request setShouldResetDownloadProgress:NO];
158                                 }
159                         }
160                 }
161                 [request buildPostBody];
162                 [self request:nil incrementUploadSizeBy:[request postLength]];
163
164
165         } else {
166                 [self request:nil incrementDownloadSizeBy:1];
167                 [self request:nil incrementUploadSizeBy:1];
168         }
169         // Tell the request not to increment the upload size when it starts, as we've already added its length
170         if ([request shouldResetUploadProgress]) {
171                 [self resetProgressDelegate:&uploadProgressDelegate];
172                 [request setShouldResetUploadProgress:NO];
173         }
174         
175         [request setShowAccurateProgress:[self showAccurateProgress]];
176         
177         [request setQueue:self];
178         [super addOperation:request];
179
180 }
181
182 - (void)requestStarted:(ASIHTTPRequest *)request
183 {
184         if ([self requestDidStartSelector]) {
185                 [[self delegate] performSelector:[self requestDidStartSelector] withObject:request];
186         }
187 }
188
189 - (void)request:(ASIHTTPRequest *)request didReceiveResponseHeaders:(NSDictionary *)responseHeaders
190 {
191         if ([self requestDidReceiveResponseHeadersSelector]) {
192                 [[self delegate] performSelector:[self requestDidReceiveResponseHeadersSelector] withObject:request withObject:responseHeaders];
193         }
194 }
195
196 - (void)request:(ASIHTTPRequest *)request willRedirectToURL:(NSURL *)newURL
197 {
198         if ([self requestWillRedirectSelector]) {
199                 [[self delegate] performSelector:[self requestWillRedirectSelector] withObject:request withObject:newURL];
200         }
201 }
202
203 - (void)requestFinished:(ASIHTTPRequest *)request
204 {
205         [self setRequestsCount:[self requestsCount]-1];
206         if ([self requestDidFinishSelector]) {
207                 [[self delegate] performSelector:[self requestDidFinishSelector] withObject:request];
208         }
209         if ([self requestsCount] == 0) {
210                 if ([self queueDidFinishSelector]) {
211                         [[self delegate] performSelector:[self queueDidFinishSelector] withObject:self];
212                 }
213         }
214 }
215
216 - (void)requestFailed:(ASIHTTPRequest *)request
217 {
218         [self setRequestsCount:[self requestsCount]-1];
219         if ([self requestDidFailSelector]) {
220                 [[self delegate] performSelector:[self requestDidFailSelector] withObject:request];
221         }
222         if ([self requestsCount] == 0) {
223                 if ([self queueDidFinishSelector]) {
224                         [[self delegate] performSelector:[self queueDidFinishSelector] withObject:self];
225                 }
226         }
227         if ([self shouldCancelAllRequestsOnFailure] && [self requestsCount] > 0) {
228                 [self cancelAllOperations];
229         }
230         
231 }
232
233
234 - (void)request:(ASIHTTPRequest *)request didReceiveBytes:(long long)bytes
235 {
236         [self setBytesDownloadedSoFar:[self bytesDownloadedSoFar]+bytes];
237         if ([self downloadProgressDelegate]) {
238                 [ASIHTTPRequest updateProgressIndicator:&downloadProgressDelegate withProgress:[self bytesDownloadedSoFar] ofTotal:[self totalBytesToDownload]];
239         }
240 }
241
242 - (void)request:(ASIHTTPRequest *)request didSendBytes:(long long)bytes
243 {
244         [self setBytesUploadedSoFar:[self bytesUploadedSoFar]+bytes];
245         if ([self uploadProgressDelegate]) {
246                 [ASIHTTPRequest updateProgressIndicator:&uploadProgressDelegate withProgress:[self bytesUploadedSoFar] ofTotal:[self totalBytesToUpload]];
247         }
248 }
249
250 - (void)request:(ASIHTTPRequest *)request incrementDownloadSizeBy:(long long)newLength
251 {
252         [self setTotalBytesToDownload:[self totalBytesToDownload]+newLength];
253 }
254
255 - (void)request:(ASIHTTPRequest *)request incrementUploadSizeBy:(long long)newLength
256 {
257         [self setTotalBytesToUpload:[self totalBytesToUpload]+newLength];
258 }
259
260
261 // Since this queue takes over as the delegate for all requests it contains, it should forward authorisation requests to its own delegate
262 - (void)authenticationNeededForRequest:(ASIHTTPRequest *)request
263 {
264         if ([[self delegate] respondsToSelector:@selector(authenticationNeededForRequest:)]) {
265                 [[self delegate] performSelector:@selector(authenticationNeededForRequest:) withObject:request];
266         }
267 }
268
269 - (void)proxyAuthenticationNeededForRequest:(ASIHTTPRequest *)request
270 {
271         if ([[self delegate] respondsToSelector:@selector(proxyAuthenticationNeededForRequest:)]) {
272                 [[self delegate] performSelector:@selector(proxyAuthenticationNeededForRequest:) withObject:request];
273         }
274 }
275
276
277 - (BOOL)respondsToSelector:(SEL)selector
278 {
279         // We handle certain methods differently because whether our delegate implements them or not can affect how the request should behave
280
281         // If the delegate implements this, the request will stop to wait for credentials
282         if (selector == @selector(authenticationNeededForRequest:)) {
283                 if ([[self delegate] respondsToSelector:@selector(authenticationNeededForRequest:)]) {
284                         return YES;
285                 }
286                 return NO;
287
288         // If the delegate implements this, the request will to wait for credentials
289         } else if (selector == @selector(proxyAuthenticationNeededForRequest:)) {
290                 if ([[self delegate] respondsToSelector:@selector(proxyAuthenticationNeededForRequest:)]) {
291                         return YES;
292                 }
293                 return NO;
294
295         // If the delegate implements requestWillRedirectSelector, the request will stop to allow the delegate to change the url
296         } else if (selector == @selector(request:willRedirectToURL:)) {
297                 if ([self requestWillRedirectSelector] && [[self delegate] respondsToSelector:[self requestWillRedirectSelector]]) {
298                         return YES;
299                 }
300                 return NO;
301         }
302         return [super respondsToSelector:selector];
303 }
304
305 #pragma mark NSCopying
306
307 - (id)copyWithZone:(NSZone *)zone
308 {
309         ASINetworkQueue *newQueue = [[[self class] alloc] init];
310         [newQueue setDelegate:[self delegate]];
311         [newQueue setRequestDidStartSelector:[self requestDidStartSelector]];
312         [newQueue setRequestWillRedirectSelector:[self requestWillRedirectSelector]];
313         [newQueue setRequestDidReceiveResponseHeadersSelector:[self requestDidReceiveResponseHeadersSelector]];
314         [newQueue setRequestDidFinishSelector:[self requestDidFinishSelector]];
315         [newQueue setRequestDidFailSelector:[self requestDidFailSelector]];
316         [newQueue setQueueDidFinishSelector:[self queueDidFinishSelector]];
317         [newQueue setUploadProgressDelegate:[self uploadProgressDelegate]];
318         [newQueue setDownloadProgressDelegate:[self downloadProgressDelegate]];
319         [newQueue setShouldCancelAllRequestsOnFailure:[self shouldCancelAllRequestsOnFailure]];
320         [newQueue setShowAccurateProgress:[self showAccurateProgress]];
321         [newQueue setUserInfo:[[[self userInfo] copyWithZone:zone] autorelease]];
322         return newQueue;
323 }
324
325
326 @synthesize requestsCount;
327 @synthesize bytesUploadedSoFar;
328 @synthesize totalBytesToUpload;
329 @synthesize bytesDownloadedSoFar;
330 @synthesize totalBytesToDownload;
331 @synthesize shouldCancelAllRequestsOnFailure;
332 @synthesize uploadProgressDelegate;
333 @synthesize downloadProgressDelegate;
334 @synthesize requestDidStartSelector;
335 @synthesize requestDidReceiveResponseHeadersSelector;
336 @synthesize requestWillRedirectSelector;
337 @synthesize requestDidFinishSelector;
338 @synthesize requestDidFailSelector;
339 @synthesize queueDidFinishSelector;
340 @synthesize delegate;
341 @synthesize showAccurateProgress;
342 @synthesize userInfo;
343 @end