Ben Copsey

Added shouldUseRFC2616RedirectBehaviour property

Move build cookie headers into its own method
... ... @@ -359,6 +359,10 @@ extern unsigned long const ASIWWANBandwidthThrottleAmount;
// This timer checks up on the request every 0.25 seconds, and updates progress
NSTimer *statusTimer;
// When set to YES, 301 and 302 automatic redirects will use the original method and and body, according to the HTTP 1.1 standard
// Default is NO (to follow the behaviour of most browsers)
BOOL shouldUseRFC2616RedirectBehaviour;
}
#pragma mark init / dealloc
... ... @@ -374,12 +378,16 @@ extern unsigned long const ASIWWANBandwidthThrottleAmount;
// Add a custom header to the request
- (void)addRequestHeader:(NSString *)header value:(NSString *)value;
// Called during buildRequestHeaders and after a redirect to create a cookie header from request cookies and the global store
- (void)applyCookieHeader;
// Populate the request headers dictionary. Called before a request is started, or by a HEAD request that needs to borrow them
- (void)buildRequestHeaders;
// Used to apply authorization header to a request before it is sent (when shouldPresentCredentialsBeforeChallenge is YES)
- (void)applyAuthorizationHeader;
// Create the post body
- (void)buildPostBody;
... ... @@ -693,4 +701,5 @@ extern unsigned long const ASIWWANBandwidthThrottleAmount;
@property (assign) int numberOfTimesToRetryOnTimeout;
@property (assign, readonly) int retryCount;
@property (assign) BOOL shouldAttemptPersistentConnection;
@property (assign) BOOL shouldUseRFC2616RedirectBehaviour;
@end
... ...
... ... @@ -21,7 +21,7 @@
#import "ASIInputStream.h"
// Automatically set on build
NSString *ASIHTTPRequestVersion = @"v1.5-4 2010-01-19";
NSString *ASIHTTPRequestVersion = @"v1.5-5 2010-01-19";
NSString* const NetworkRequestErrorDomain = @"ASIHTTPRequestErrorDomain";
... ... @@ -672,22 +672,10 @@ static BOOL isiPhoneOS2;
}
}
- (void)buildRequestHeaders
- (void)applyCookieHeader
{
if ([self haveBuiltRequestHeaders]) {
return;
}
[self setHaveBuiltRequestHeaders:YES];
if ([self mainRequest]) {
for (NSString *header in [[self mainRequest] requestHeaders]) {
[self addRequestHeader:header value:[[[self mainRequest] requestHeaders] valueForKey:header]];
}
return;
}
// Add cookies from the persistant (mac os global) store
if ([self useCookiePersistance] ) {
if ([self useCookiePersistance]) {
NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:[self url]];
if (cookies) {
[[self requestCookies] addObjectsFromArray:cookies];
... ... @@ -714,8 +702,25 @@ static BOOL isiPhoneOS2;
if (cookieHeader) {
[self addRequestHeader:@"Cookie" value:cookieHeader];
}
}
}
- (void)buildRequestHeaders
{
if ([self haveBuiltRequestHeaders]) {
return;
}
[self setHaveBuiltRequestHeaders:YES];
if ([self mainRequest]) {
for (NSString *header in [[self mainRequest] requestHeaders]) {
[self addRequestHeader:header value:[[[self mainRequest] requestHeaders] valueForKey:header]];
}
return;
}
[self applyCookieHeader];
// Build and set the user agent string if the request does not already have a custom user agent specified
if (![[self requestHeaders] objectForKey:@"User-Agent"]) {
NSString *userAgentString = [ASIHTTPRequest defaultUserAgentString];
... ... @@ -1697,18 +1702,26 @@ static BOOL isiPhoneOS2;
if ([self shouldRedirect] && [responseHeaders valueForKey:@"Location"]) {
if ([self responseStatusCode] > 300 && [self responseStatusCode] < 304) {
// We redirect 301, 302 and 303 response codes as GET requests
// By default, we redirect 301 and 302 response codes as GET requests
// According to RFC 2616 this is wrong, but this is what most browsers do, so it's probably what you're expecting to happen
// See also:
// http://allseeing-i.lighthouseapp.com/projects/27881/tickets/27-302-redirection-issue
if (![self shouldUseRFC2616RedirectBehaviour] || [self responseStatusCode] == 303) {
[self setRequestMethod:@"GET"];
[self setPostBody:nil];
[self setPostLength:0];
[self setRequestHeaders:nil];
[self setHaveBuiltRequestHeaders:NO];
} else {
[self setRequestMethod:@"GET"];
[self setPostBody:nil];
[self setPostLength:0];
[self setRequestHeaders:nil];
// Force rebuild the cookie header incase we got some new cookies from this request
// All other request headers will remain as they are for 301 / 302 redirects
[self applyCookieHeader];
}
// Force the redirected request to rebuild the request headers (if not a 303, it will re-use old ones, and add any new ones)
[self setHaveBuiltRequestHeaders:NO];
[self setURL:[[NSURL URLWithString:[responseHeaders valueForKey:@"Location"] relativeToURL:[self url]] absoluteURL]];
[self setNeedsRedirect:YES];
... ... @@ -3658,4 +3671,5 @@ static BOOL isiPhoneOS2;
@synthesize readStream;
@synthesize readStreamIsScheduled;
@synthesize statusTimer;
@synthesize shouldUseRFC2616RedirectBehaviour;
@end
\ No newline at end of file
... ...
... ... @@ -322,9 +322,9 @@
ASIHTTPRequest *request;
ASIFormDataRequest *request2;
BOOL success;
int i;
unsigned int i;
for (i=301; i<305; i++) {
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://allseeing-i.com/ASIHTTPRequest/tests/redirect/%hi",i]];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://asi/ASIHTTPRequest/tests/redirect/%hi",i]];
request = [ASIHTTPRequest requestWithURL:url];
[request setShouldRedirect:NO];
[request startSynchronous];
... ... @@ -335,7 +335,7 @@
GHAssertTrue(success,[NSString stringWithFormat:@"Got the wrong content when not redirecting after a %hi",i]);
request2 = [ASIFormDataRequest requestWithURL:url];
[request2 setPostValue:@"foo" forKey:@"eep"];
[request2 setPostValue:@"Giant Monkey" forKey:@"lookbehindyou"];
[request2 startSynchronous];
NSString *method = @"GET";
... ... @@ -347,9 +347,37 @@
GHAssertTrue(success,[NSString stringWithFormat:@"Got the wrong content when redirecting after a %hi",i]);
success = ([request2 responseStatusCode] == 200);
GHAssertTrue(success,[NSString stringWithFormat:@"Got the wrong status code (expected %hi)",i]);
GHAssertTrue(success,@"Got the wrong status code (expected 200)");
}
// Test RFC 2616 behaviour
for (i=301; i<303; i++) {
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://asi/ASIHTTPRequest/tests/redirect/%hi",i]];
request2 = [ASIFormDataRequest requestWithURL:url];
[request2 setPostValue:@"Giant Monkey" forKey:@"lookbehindyou"];
[request2 setShouldUseRFC2616RedirectBehaviour:YES];
[request2 startSynchronous];
success = ([request2 responseStatusCode] == 200);
GHAssertTrue(success,@"Got the wrong status code (expected 200)");
if (i == 303) {
success = ([request2 postLength] == 0 && ![request2 postBody] && [[request2 requestMethod] isEqualToString:@"GET"]);
GHAssertTrue(success,@"Failed to reset request to GET on 303 redirect");
success = [[request2 responseString] isEqualToString:[NSString stringWithFormat:@"Redirected as GET after a %hi status code",i]];
GHAssertTrue(success,@"Failed to dump the post body on 303 redirect");
} else {
success = ([request2 postLength] > 0 || ![request2 postBody] || ![[request2 requestMethod] isEqualToString:@"POST"]);
GHAssertTrue(success,@"Failed to use the same request method and body for a redirect when using rfc2616 behaviour");
success = ([[request2 responseString] isEqualToString:[NSString stringWithFormat:@"Redirected as POST after a %hi status code\r\nWatch out for the Giant Monkey!",i]]);
GHAssertTrue(success,@"Failed to send the correct post body on redirect");
}
}
}
// Using a persistent connection for HTTP 305-307 would cause crashes on the redirect, not really sure why
... ...