Ben Copsey

Added automatic redirection for 30x headers (on by default)

@@ -215,6 +215,9 @@ extern NSString* const NetworkRequestErrorDomain; @@ -215,6 +215,9 @@ extern NSString* const NetworkRequestErrorDomain;
215 // Use HTTP 1.0 rather than 1.1 (defaults to false) 215 // Use HTTP 1.0 rather than 1.1 (defaults to false)
216 BOOL useHTTPVersionOne; 216 BOOL useHTTPVersionOne;
217 217
  218 + // When YES, requests will automatically redirect when they get a HTTP 30x header (defaults to YES)
  219 + BOOL shouldRedirect;
  220 +
218 } 221 }
219 222
220 #pragma mark init / dealloc 223 #pragma mark init / dealloc
@@ -397,5 +400,5 @@ extern NSString* const NetworkRequestErrorDomain; @@ -397,5 +400,5 @@ extern NSString* const NetworkRequestErrorDomain;
397 @property (assign) BOOL didCreateTemporaryPostDataFile; 400 @property (assign) BOOL didCreateTemporaryPostDataFile;
398 @property (assign) BOOL useHTTPVersionOne; 401 @property (assign) BOOL useHTTPVersionOne;
399 @property (assign, readonly) unsigned long long partialDownloadSize; 402 @property (assign, readonly) unsigned long long partialDownloadSize;
400 - 403 +@property (assign) BOOL shouldRedirect;
401 @end 404 @end
@@ -88,6 +88,7 @@ static NSError *ASIUnableToCreateRequestError; @@ -88,6 +88,7 @@ static NSError *ASIUnableToCreateRequestError;
88 self = [super init]; 88 self = [super init];
89 [self setRequestMethod:@"GET"]; 89 [self setRequestMethod:@"GET"];
90 90
  91 + [self setShouldRedirect:YES];
91 [self setShowAccurateProgress:YES]; 92 [self setShowAccurateProgress:YES];
92 [self setShouldResetProgressIndicators:YES]; 93 [self setShouldResetProgressIndicators:YES];
93 [self setAllowCompressedResponse:YES]; 94 [self setAllowCompressedResponse:YES];
@@ -305,12 +306,13 @@ static NSError *ASIUnableToCreateRequestError; @@ -305,12 +306,13 @@ static NSError *ASIUnableToCreateRequestError;
305 } 306 }
306 307
307 // Create a new HTTP request. 308 // Create a new HTTP request.
308 - request = CFHTTPMessageCreateRequest(kCFAllocatorDefault, (CFStringRef)requestMethod, (CFURLRef)url, self.useHTTPVersionOne ? kCFHTTPVersion1_0 : kCFHTTPVersion1_1); 309 + request = CFHTTPMessageCreateRequest(kCFAllocatorDefault, (CFStringRef)requestMethod, (CFURLRef)url, [self useHTTPVersionOne] ? kCFHTTPVersion1_0 : kCFHTTPVersion1_1);
309 if (!request) { 310 if (!request) {
310 [self failWithError:ASIUnableToCreateRequestError]; 311 [self failWithError:ASIUnableToCreateRequestError];
311 return; 312 return;
312 } 313 }
313 314
  315 +
314 // If we've already talked to this server and have valid credentials, let's apply them to the request 316 // If we've already talked to this server and have valid credentials, let's apply them to the request
315 if (useSessionPersistance && sessionCredentials && sessionAuthentication) { 317 if (useSessionPersistance && sessionCredentials && sessionAuthentication) {
316 if (!CFHTTPMessageApplyCredentialDictionary(request, sessionAuthentication, (CFMutableDictionaryRef)sessionCredentials, NULL)) { 318 if (!CFHTTPMessageApplyCredentialDictionary(request, sessionAuthentication, (CFMutableDictionaryRef)sessionCredentials, NULL)) {
@@ -429,6 +431,9 @@ static NSError *ASIUnableToCreateRequestError; @@ -429,6 +431,9 @@ static NSError *ASIUnableToCreateRequestError;
429 return; 431 return;
430 } 432 }
431 433
  434 + // Tell CFNetwork to automatically redirect for 30x status codes
  435 + CFReadStreamSetProperty(readStream, kCFStreamPropertyHTTPShouldAutoredirect, [self shouldRedirect] ? kCFBooleanTrue : kCFBooleanFalse);
  436 +
432 // Set the client 437 // Set the client
433 CFStreamClientContext ctxt = {0, self, NULL, NULL, NULL}; 438 CFStreamClientContext ctxt = {0, self, NULL, NULL, NULL};
434 if (!CFReadStreamSetClient(readStream, kNetworkEvents, ReadStreamClientCallBack, &ctxt)) { 439 if (!CFReadStreamSetClient(readStream, kNetworkEvents, ReadStreamClientCallBack, &ctxt)) {
@@ -1634,4 +1639,5 @@ static NSError *ASIUnableToCreateRequestError; @@ -1634,4 +1639,5 @@ static NSError *ASIUnableToCreateRequestError;
1634 @synthesize fileDownloadOutputStream; 1639 @synthesize fileDownloadOutputStream;
1635 @synthesize authenticationRetryCount; 1640 @synthesize authenticationRetryCount;
1636 @synthesize updatedProgress; 1641 @synthesize updatedProgress;
  1642 +@synthesize shouldRedirect;
1637 @end 1643 @end
@@ -126,10 +126,39 @@ @@ -126,10 +126,39 @@
126 GHAssertTrue(success,@"Wrong HTTP version used"); 126 GHAssertTrue(success,@"Wrong HTTP version used");
127 } 127 }
128 128
  129 +- (void)testAutomaticRedirection
  130 +{
  131 + ASIHTTPRequest *request;
  132 + BOOL success;
  133 + int i;
  134 + for (i=301; i<308; i++) {
  135 + NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://allseeing-i.com/ASIHTTPRequest/tests/redirect/%hi",i]];
  136 + request = [ASIHTTPRequest requestWithURL:url];
  137 + [request setShouldRedirect:NO];
  138 + [request start];
  139 + NSLog([request responseString]);
  140 + if (i == 304) { // 304s will not contain a body, as per rfc2616. Will test 304 handling in a future test when we have etag support
  141 + continue;
  142 + }
  143 + success = [[request responseString] isEqualToString:[NSString stringWithFormat:@"Non-redirected content with %hi status code",i]];
  144 + GHAssertTrue(success,[NSString stringWithFormat:@"Got the wrong content when not redirecting after a %hi",i]);
  145 +
  146 + request = [ASIHTTPRequest requestWithURL:url];
  147 + [request start];
  148 + NSLog([request responseString]);
  149 + success = [[request responseString] isEqualToString:[NSString stringWithFormat:@"Redirected content after a %hi status code",i]];
  150 + GHAssertTrue(success,[NSString stringWithFormat:@"Got the wrong content when redirecting after a %hi",i]);
  151 +
  152 + success = ([request responseStatusCode] == 200);
  153 + GHAssertTrue(success,[NSString stringWithFormat:@"Got the wrong status code (expected %hi)",i]);
  154 +
  155 + }
  156 +}
  157 +
129 - (void)testUploadContentLength 158 - (void)testUploadContentLength
130 { 159 {
131 //This url will return the contents of the Content-Length request header 160 //This url will return the contents of the Content-Length request header
132 - NSURL *url = [[[NSURL alloc] initWithString:@"http://allseeing-i.com/ASIHTTPRequest/tests/content-length"] autorelease]; 161 + NSURL *url = [NSURL URLWithString:@"http://allseeing-i.com/ASIHTTPRequest/tests/content-length"];
133 ASIHTTPRequest *request = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease]; 162 ASIHTTPRequest *request = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease];
134 [request setPostBody:[NSMutableData dataWithLength:1024*32]]; 163 [request setPostBody:[NSMutableData dataWithLength:1024*32]];
135 [request start]; 164 [request start];