Fix bug where HEAD requests created by ASINeworkQueues didn't present the reques…
…t headers from the main request. This meant they wouldn't present authentication information or cookies, as well as custom headers. Errors thrown by the above HEAD requests now set the error on the main request and talk to its delegate when appropriate Thanks to Alex Reynolds for noticing this issue!
Showing
7 changed files
with
130 additions
and
24 deletions
@@ -12,7 +12,6 @@ | @@ -12,7 +12,6 @@ | ||
12 | @implementation ASIFormDataRequestTests | 12 | @implementation ASIFormDataRequestTests |
13 | 13 | ||
14 | 14 | ||
15 | - | ||
16 | - (void)testPostWithFileUpload | 15 | - (void)testPostWithFileUpload |
17 | { | 16 | { |
18 | NSURL *url = [NSURL URLWithString:@"http://allseeing-i.com/ASIHTTPRequest/tests/post"]; | 17 | NSURL *url = [NSURL URLWithString:@"http://allseeing-i.com/ASIHTTPRequest/tests/post"]; |
@@ -280,6 +280,7 @@ typedef enum _ASINetworkErrorType { | @@ -280,6 +280,7 @@ typedef enum _ASINetworkErrorType { | ||
280 | @property (retain) NSError *error; | 280 | @property (retain) NSError *error; |
281 | @property (assign,readonly) BOOL complete; | 281 | @property (assign,readonly) BOOL complete; |
282 | @property (retain) NSDictionary *responseHeaders; | 282 | @property (retain) NSDictionary *responseHeaders; |
283 | +@property (retain) NSMutableDictionary *requestHeaders; | ||
283 | @property (retain) NSMutableArray *requestCookies; | 284 | @property (retain) NSMutableArray *requestCookies; |
284 | @property (retain) NSArray *responseCookies; | 285 | @property (retain) NSArray *responseCookies; |
285 | @property (assign) BOOL useCookiePersistance; | 286 | @property (assign) BOOL useCookiePersistance; |
@@ -62,24 +62,24 @@ static NSError *ASIUnableToCreateRequestError; | @@ -62,24 +62,24 @@ static NSError *ASIUnableToCreateRequestError; | ||
62 | showAccurateProgress = YES; | 62 | showAccurateProgress = YES; |
63 | shouldResetProgressIndicators = YES; | 63 | shouldResetProgressIndicators = YES; |
64 | updatedProgress = NO; | 64 | updatedProgress = NO; |
65 | - mainRequest = nil; | 65 | + [self setMainRequest:nil]; |
66 | - username = nil; | 66 | + [self setPassword:nil]; |
67 | - password = nil; | 67 | + [self setUsername:nil]; |
68 | - requestHeaders = nil; | 68 | + [self setRequestHeaders:nil]; |
69 | authenticationRealm = nil; | 69 | authenticationRealm = nil; |
70 | outputStream = nil; | 70 | outputStream = nil; |
71 | requestAuthentication = NULL; | 71 | requestAuthentication = NULL; |
72 | haveBuiltPostBody = NO; | 72 | haveBuiltPostBody = NO; |
73 | request = NULL; | 73 | request = NULL; |
74 | - responseHeaders = nil; | 74 | + [self setResponseHeaders:nil]; |
75 | [self setTimeOutSeconds:10]; | 75 | [self setTimeOutSeconds:10]; |
76 | [self setUseKeychainPersistance:NO]; | 76 | [self setUseKeychainPersistance:NO]; |
77 | [self setUseSessionPersistance:YES]; | 77 | [self setUseSessionPersistance:YES]; |
78 | [self setUseCookiePersistance:YES]; | 78 | [self setUseCookiePersistance:YES]; |
79 | [self setRequestCookies:[[[NSMutableArray alloc] init] autorelease]]; | 79 | [self setRequestCookies:[[[NSMutableArray alloc] init] autorelease]]; |
80 | - didFinishSelector = @selector(requestFinished:); | 80 | + [self setDidFinishSelector:@selector(requestFinished:)]; |
81 | - didFailSelector = @selector(requestFailed:); | 81 | + [self setDidFailSelector:@selector(requestFailed:)]; |
82 | - delegate = nil; | 82 | + [self setDelegate:nil]; |
83 | url = [newURL retain]; | 83 | url = [newURL retain]; |
84 | cancelledLock = [[NSLock alloc] init]; | 84 | cancelledLock = [[NSLock alloc] init]; |
85 | return self; | 85 | return self; |
@@ -123,7 +123,7 @@ static NSError *ASIUnableToCreateRequestError; | @@ -123,7 +123,7 @@ static NSError *ASIUnableToCreateRequestError; | ||
123 | - (void)addRequestHeader:(NSString *)header value:(NSString *)value | 123 | - (void)addRequestHeader:(NSString *)header value:(NSString *)value |
124 | { | 124 | { |
125 | if (!requestHeaders) { | 125 | if (!requestHeaders) { |
126 | - requestHeaders = [[NSMutableDictionary alloc] init]; | 126 | + [self setRequestHeaders:[NSMutableDictionary dictionaryWithCapacity:1]]; |
127 | } | 127 | } |
128 | [requestHeaders setObject:value forKey:header]; | 128 | [requestHeaders setObject:value forKey:header]; |
129 | } | 129 | } |
@@ -208,10 +208,16 @@ static NSError *ASIUnableToCreateRequestError; | @@ -208,10 +208,16 @@ static NSError *ASIUnableToCreateRequestError; | ||
208 | } | 208 | } |
209 | 209 | ||
210 | // Apply request cookies | 210 | // Apply request cookies |
211 | - if ([requestCookies count] > 0) { | 211 | + NSArray *cookies; |
212 | + if ([self mainRequest]) { | ||
213 | + cookies = [[self mainRequest] requestCookies]; | ||
214 | + } else { | ||
215 | + cookies = [self requestCookies]; | ||
216 | + } | ||
217 | + if ([cookies count] > 0) { | ||
212 | NSHTTPCookie *cookie; | 218 | NSHTTPCookie *cookie; |
213 | NSString *cookieHeader = nil; | 219 | NSString *cookieHeader = nil; |
214 | - for (cookie in requestCookies) { | 220 | + for (cookie in cookies) { |
215 | if (!cookieHeader) { | 221 | if (!cookieHeader) { |
216 | cookieHeader = [NSString stringWithFormat: @"%@=%@",[cookie name],[cookie encodedValue]]; | 222 | cookieHeader = [NSString stringWithFormat: @"%@=%@",[cookie name],[cookie encodedValue]]; |
217 | } else { | 223 | } else { |
@@ -229,8 +235,16 @@ static NSError *ASIUnableToCreateRequestError; | @@ -229,8 +235,16 @@ static NSError *ASIUnableToCreateRequestError; | ||
229 | } | 235 | } |
230 | 236 | ||
231 | // Add custom headers | 237 | // Add custom headers |
238 | + NSDictionary *headers; | ||
239 | + | ||
240 | + //Add headers from the main request if this is a HEAD request generated by an ASINetwork Queue | ||
241 | + if ([self mainRequest]) { | ||
242 | + headers = [mainRequest requestHeaders]; | ||
243 | + } else { | ||
244 | + headers = [self requestHeaders]; | ||
245 | + } | ||
232 | NSString *header; | 246 | NSString *header; |
233 | - for (header in requestHeaders) { | 247 | + for (header in headers) { |
234 | CFHTTPMessageSetHeaderFieldValue(request, (CFStringRef)header, (CFStringRef)[requestHeaders objectForKey:header]); | 248 | CFHTTPMessageSetHeaderFieldValue(request, (CFStringRef)header, (CFStringRef)[requestHeaders objectForKey:header]); |
235 | } | 249 | } |
236 | 250 | ||
@@ -248,6 +262,7 @@ static NSError *ASIUnableToCreateRequestError; | @@ -248,6 +262,7 @@ static NSError *ASIUnableToCreateRequestError; | ||
248 | // Start the request | 262 | // Start the request |
249 | - (void)loadRequest | 263 | - (void)loadRequest |
250 | { | 264 | { |
265 | + | ||
251 | [cancelledLock lock]; | 266 | [cancelledLock lock]; |
252 | 267 | ||
253 | if ([self isCancelled]) { | 268 | if ([self isCancelled]) { |
@@ -643,12 +658,22 @@ static NSError *ASIUnableToCreateRequestError; | @@ -643,12 +658,22 @@ static NSError *ASIUnableToCreateRequestError; | ||
643 | complete = YES; | 658 | complete = YES; |
644 | if (!error) { | 659 | if (!error) { |
645 | 660 | ||
646 | - [self setError:theError]; | 661 | + // If this is a HEAD request created by an ASINetworkQueue, make the main request fail |
662 | + if ([self mainRequest]) { | ||
663 | + ASIHTTPRequest *mRequest = [self mainRequest]; | ||
664 | + [mRequest setError:theError]; | ||
665 | + if ([mRequest didFailSelector] && ![self isCancelled] && [[mRequest delegate] respondsToSelector:[mRequest didFailSelector]]) { | ||
666 | + [[mRequest delegate] performSelectorOnMainThread:[mRequest didFailSelector] withObject:mRequest waitUntilDone:[NSThread isMainThread]]; | ||
667 | + } | ||
647 | 668 | ||
669 | + } else { | ||
670 | + [self setError:theError]; | ||
648 | if (didFailSelector && ![self isCancelled] && [delegate respondsToSelector:didFailSelector]) { | 671 | if (didFailSelector && ![self isCancelled] && [delegate respondsToSelector:didFailSelector]) { |
649 | [delegate performSelectorOnMainThread:didFailSelector withObject:self waitUntilDone:[NSThread isMainThread]]; | 672 | [delegate performSelectorOnMainThread:didFailSelector withObject:self waitUntilDone:[NSThread isMainThread]]; |
650 | } | 673 | } |
651 | } | 674 | } |
675 | + | ||
676 | + } | ||
652 | } | 677 | } |
653 | 678 | ||
654 | 679 | ||
@@ -761,12 +786,24 @@ static NSError *ASIUnableToCreateRequestError; | @@ -761,12 +786,24 @@ static NSError *ASIUnableToCreateRequestError; | ||
761 | NSString *user = [url user]; | 786 | NSString *user = [url user]; |
762 | NSString *pass = [url password]; | 787 | NSString *pass = [url password]; |
763 | 788 | ||
764 | - // If the username and password weren't in the url, let's try to use the ones set in this object | 789 | + // If the username and password weren't in the url |
765 | - if ((!user || !pass) && username && password) { | 790 | + if (!user || !pass) { |
791 | + | ||
792 | + // If this is a HEAD request generated by an ASINetworkQueue, we'll try to use the details from the main request | ||
793 | + if ([self mainRequest] && [[self mainRequest] username] && [[self mainRequest] password]) { | ||
794 | + user = [[self mainRequest] username]; | ||
795 | + pass = [[self mainRequest] password]; | ||
796 | + | ||
797 | + // Let's try to use the ones set in this object | ||
798 | + } else if (username && password) { | ||
766 | user = username; | 799 | user = username; |
767 | pass = password; | 800 | pass = password; |
768 | } | 801 | } |
769 | 802 | ||
803 | + } | ||
804 | + | ||
805 | + | ||
806 | + | ||
770 | // Ok, that didn't work, let's try the keychain | 807 | // Ok, that didn't work, let's try the keychain |
771 | if ((!user || !pass) && useKeychainPersistance) { | 808 | if ((!user || !pass) && useKeychainPersistance) { |
772 | NSURLCredential *authenticationCredentials = [ASIHTTPRequest savedCredentialsForHost:[url host] port:443 protocol:[url scheme] realm:authenticationRealm]; | 809 | NSURLCredential *authenticationCredentials = [ASIHTTPRequest savedCredentialsForHost:[url host] port:443 protocol:[url scheme] realm:authenticationRealm]; |
@@ -833,8 +870,7 @@ static NSError *ASIUnableToCreateRequestError; | @@ -833,8 +870,7 @@ static NSError *ASIUnableToCreateRequestError; | ||
833 | return; | 870 | return; |
834 | } | 871 | } |
835 | } | 872 | } |
836 | - [self setError:ASIAuthenticationError]; | 873 | + [self failWithError:ASIAuthenticationError]; |
837 | - complete = YES; | ||
838 | return; | 874 | return; |
839 | } | 875 | } |
840 | 876 | ||
@@ -874,8 +910,7 @@ static NSError *ASIUnableToCreateRequestError; | @@ -874,8 +910,7 @@ static NSError *ASIUnableToCreateRequestError; | ||
874 | } | 910 | } |
875 | 911 | ||
876 | // The delegate isn't interested, we'll have to give up | 912 | // The delegate isn't interested, we'll have to give up |
877 | - [self setError:ASIAuthenticationError]; | 913 | + [self failWithError:ASIAuthenticationError]; |
878 | - complete = YES; | ||
879 | return; | 914 | return; |
880 | } | 915 | } |
881 | 916 | ||
@@ -982,7 +1017,6 @@ static NSError *ASIUnableToCreateRequestError; | @@ -982,7 +1017,6 @@ static NSError *ASIUnableToCreateRequestError; | ||
982 | 1017 | ||
983 | - (void)handleStreamError | 1018 | - (void)handleStreamError |
984 | { | 1019 | { |
985 | - complete = YES; | ||
986 | NSError *underlyingError = [(NSError *)CFReadStreamCopyError(readStream) autorelease]; | 1020 | NSError *underlyingError = [(NSError *)CFReadStreamCopyError(readStream) autorelease]; |
987 | 1021 | ||
988 | [self cancelLoad]; | 1022 | [self cancelLoad]; |
@@ -1096,6 +1130,7 @@ static NSError *ASIUnableToCreateRequestError; | @@ -1096,6 +1130,7 @@ static NSError *ASIUnableToCreateRequestError; | ||
1096 | @synthesize authenticationRealm; | 1130 | @synthesize authenticationRealm; |
1097 | @synthesize error; | 1131 | @synthesize error; |
1098 | @synthesize complete; | 1132 | @synthesize complete; |
1133 | +@synthesize requestHeaders; | ||
1099 | @synthesize responseHeaders; | 1134 | @synthesize responseHeaders; |
1100 | @synthesize responseCookies; | 1135 | @synthesize responseCookies; |
1101 | @synthesize requestCookies; | 1136 | @synthesize requestCookies; |
@@ -15,7 +15,6 @@ | @@ -15,7 +15,6 @@ | ||
15 | @implementation ASIHTTPRequestTests | 15 | @implementation ASIHTTPRequestTests |
16 | 16 | ||
17 | 17 | ||
18 | - | ||
19 | - (void)testBasicDownload | 18 | - (void)testBasicDownload |
20 | { | 19 | { |
21 | NSURL *url = [[[NSURL alloc] initWithString:@"http://allseeing-i.com"] autorelease]; | 20 | NSURL *url = [[[NSURL alloc] initWithString:@"http://allseeing-i.com"] autorelease]; |
@@ -375,5 +374,4 @@ | @@ -375,5 +374,4 @@ | ||
375 | } | 374 | } |
376 | 375 | ||
377 | 376 | ||
378 | - | ||
379 | @end | 377 | @end |
@@ -254,6 +254,18 @@ | @@ -254,6 +254,18 @@ | ||
254 | } | 254 | } |
255 | 255 | ||
256 | 256 | ||
257 | +- (BOOL)respondsToSelector:(SEL)selector | ||
258 | +{ | ||
259 | + if (selector == @selector(authorizationNeededForRequest:)) { | ||
260 | + if ([delegate respondsToSelector:@selector(authorizationNeededForRequest:)]) { | ||
261 | + return YES; | ||
262 | + } | ||
263 | + return NO; | ||
264 | + } | ||
265 | + return [super respondsToSelector:selector]; | ||
266 | +} | ||
267 | + | ||
268 | + | ||
257 | 269 | ||
258 | @synthesize uploadProgressDelegate; | 270 | @synthesize uploadProgressDelegate; |
259 | @synthesize downloadProgressDelegate; | 271 | @synthesize downloadProgressDelegate; |
@@ -21,6 +21,7 @@ | @@ -21,6 +21,7 @@ | ||
21 | - (void)testFailure; | 21 | - (void)testFailure; |
22 | - (void)testFailureCancelsOtherRequests; | 22 | - (void)testFailureCancelsOtherRequests; |
23 | - (void)testProgress; | 23 | - (void)testProgress; |
24 | +- (void)testProgressWithAuthentication; | ||
24 | 25 | ||
25 | - (void)setProgress:(float)newProgress; | 26 | - (void)setProgress:(float)newProgress; |
26 | @end | 27 | @end |
@@ -12,7 +12,6 @@ | @@ -12,7 +12,6 @@ | ||
12 | 12 | ||
13 | @implementation ASINetworkQueueTests | 13 | @implementation ASINetworkQueueTests |
14 | 14 | ||
15 | - | ||
16 | - (void)testProgress | 15 | - (void)testProgress |
17 | { | 16 | { |
18 | complete = NO; | 17 | complete = NO; |
@@ -78,12 +77,15 @@ | @@ -78,12 +77,15 @@ | ||
78 | 77 | ||
79 | } | 78 | } |
80 | 79 | ||
80 | + | ||
81 | + | ||
81 | - (void)setProgress:(float)newProgress | 82 | - (void)setProgress:(float)newProgress |
82 | { | 83 | { |
83 | progress = newProgress; | 84 | progress = newProgress; |
84 | } | 85 | } |
85 | 86 | ||
86 | 87 | ||
88 | + | ||
87 | - (void)testFailure | 89 | - (void)testFailure |
88 | { | 90 | { |
89 | complete = NO; | 91 | complete = NO; |
@@ -189,6 +191,8 @@ | @@ -189,6 +191,8 @@ | ||
189 | [requestThatShouldFail release]; | 191 | [requestThatShouldFail release]; |
190 | } | 192 | } |
191 | 193 | ||
194 | + | ||
195 | + | ||
192 | - (void)requestFailedCancellingOthers:(ASIHTTPRequest *)request | 196 | - (void)requestFailedCancellingOthers:(ASIHTTPRequest *)request |
193 | { | 197 | { |
194 | complete = YES; | 198 | complete = YES; |
@@ -205,6 +209,62 @@ | @@ -205,6 +209,62 @@ | ||
205 | complete = YES; | 209 | complete = YES; |
206 | } | 210 | } |
207 | 211 | ||
212 | +- (void)testProgressWithAuthentication | ||
213 | +{ | ||
214 | + complete = NO; | ||
215 | + progress = 0; | ||
216 | + | ||
217 | + networkQueue = [[ASINetworkQueue alloc] init]; | ||
218 | + [networkQueue setDownloadProgressDelegate:self]; | ||
219 | + [networkQueue setDelegate:self]; | ||
220 | + [networkQueue setShowAccurateProgress:YES]; | ||
221 | + [networkQueue setQueueDidFinishSelector:@selector(queueFinished:)]; | ||
222 | + [networkQueue setRequestDidFailSelector:@selector(requestFailedCancellingOthers:)]; | ||
223 | + | ||
224 | + NSURL *url; | ||
225 | + url = [[[NSURL alloc] initWithString:@"http://allseeing-i.com/ASIHTTPRequest/tests/basic-authentication"] autorelease]; | ||
226 | + ASIHTTPRequest *request = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease]; | ||
227 | + [networkQueue addOperation:request]; | ||
228 | + | ||
229 | + [networkQueue go]; | ||
230 | + | ||
231 | + NSDate* endDate = [NSDate distantFuture]; | ||
232 | + while (!complete) { | ||
233 | + [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:endDate]; | ||
234 | + } | ||
235 | + | ||
236 | + NSError *error = [request error]; | ||
237 | + STAssertNotNil(error,@"The HEAD request failed, but it didn't tell the main request to fail"); | ||
238 | + [networkQueue release]; | ||
239 | + | ||
240 | + | ||
241 | + networkQueue = [[ASINetworkQueue alloc] init]; | ||
242 | + [networkQueue setDownloadProgressDelegate:self]; | ||
243 | + [networkQueue setDelegate:self]; | ||
244 | + [networkQueue setShowAccurateProgress:YES]; | ||
245 | + [networkQueue setQueueDidFinishSelector:@selector(queueFinished:)]; | ||
246 | + | ||
247 | + request = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease]; | ||
248 | + [request setUsername:@"secret_username"]; | ||
249 | + [request setPassword:@"secret_password"]; | ||
250 | + [networkQueue addOperation:request]; | ||
251 | + | ||
252 | + [networkQueue go]; | ||
253 | + | ||
254 | + while (!complete) { | ||
255 | + [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:endDate]; | ||
256 | + } | ||
257 | + | ||
258 | + error = [request error]; | ||
259 | + STAssertNil(error,@"Failed to use authentication in a queue"); | ||
260 | + [networkQueue release]; | ||
261 | + | ||
262 | + | ||
263 | + | ||
264 | + | ||
265 | + | ||
266 | +} | ||
267 | + | ||
208 | 268 | ||
209 | 269 | ||
210 | @end | 270 | @end |
-
Please register or login to post a comment