Ben Copsey

Added timeout support

... ... @@ -122,7 +122,10 @@
//Called on the delegate when the request fails
SEL didFailSelector;
//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
NSDate *lastActivityTime;
NSTimeInterval timeOutSeconds;
}
#pragma mark init / dealloc
... ... @@ -254,5 +257,6 @@
@property (retain) NSDictionary *requestCredentials;
@property (assign) int responseStatusCode;
@property (retain) NSMutableData *receivedData;
@property (retain) NSDate *lastActivityTime;
@property (assign) NSTimeInterval timeOutSeconds;
@end
... ...
... ... @@ -51,6 +51,7 @@ static void ReadStreamClientCallBack(CFReadStreamRef readStream, CFStreamEventTy
//credentials = NULL;
request = NULL;
responseHeaders = nil;
[self setTimeOutSeconds:30];
[self setUseKeychainPersistance:NO];
[self setUseSessionPersistance:YES];
[self setUseCookiePersistance:YES];
... ... @@ -83,6 +84,7 @@ static void ReadStreamClientCallBack(CFReadStreamRef readStream, CFStreamEventTy
[authenticationRealm release];
[url release];
[authenticationLock release];
[lastActivityTime release];
[super dealloc];
}
... ... @@ -304,11 +306,23 @@ static void ReadStreamClientCallBack(CFReadStreamRef readStream, CFStreamEventTy
[self performSelectorOnMainThread:@selector(resetUploadProgress:) withObject:[NSNumber numberWithDouble:postLength] waitUntilDone:YES];
}
//Record when the request started, so we can timeout if nothing happens
[self setLastActivityTime:[[NSDate new] autorelease]];
// Wait for the request to finish
NSDate* endDate = [NSDate distantFuture];
while (!complete) {
//See if we need to timeout
if (lastActivityTime && timeOutSeconds > 0) {
if ([[[NSDate new] autorelease] timeIntervalSinceDate:lastActivityTime] > timeOutSeconds) {
[self failWithProblem:@"Request timed out"];
[self cancelLoad];
complete = YES;
break;
}
}
// See if our NSOperationQueue told us to cancel
if ([self isCancelled]) {
[self failWithProblem:@"The request was cancelled"];
... ... @@ -366,6 +380,8 @@ static void ReadStreamClientCallBack(CFReadStreamRef readStream, CFStreamEventTy
- (void)updateUploadProgress
{
[self setLastActivityTime:[[NSDate new] autorelease]];
double byteCount = [[(NSNumber *)CFReadStreamCopyProperty (readStream, kCFStreamPropertyHTTPRequestBytesWrittenCount) autorelease] doubleValue];
if (uploadProgressDelegate) {
[uploadProgressDelegate incrementBy:byteCount-lastBytesSent];
... ... @@ -385,6 +401,8 @@ static void ReadStreamClientCallBack(CFReadStreamRef readStream, CFStreamEventTy
- (void)updateDownloadProgress
{
[self setLastActivityTime:[[NSDate new] autorelease]];
//We won't update downlaod progress until we've examined the headers, since we might need to authenticate
if (downloadProgressDelegate && responseHeaders) {
[downloadProgressDelegate incrementBy:totalBytesRead-lastBytesRead];
... ... @@ -586,6 +604,7 @@ static void ReadStreamClientCallBack(CFReadStreamRef readStream, CFStreamEventTy
// check for bad credentials, so we can give the delegate a chance to replace them
if (err.domain == kCFStreamErrorDomainHTTP && (err.error == kCFStreamErrorHTTPAuthenticationBadUserName || err.error == kCFStreamErrorHTTPAuthenticationBadPassword)) {
ignoreError = YES;
[self setLastActivityTime:nil];
if ([delegate respondsToSelector:@selector(authorizationNeededForRequest:)]) {
[delegate performSelectorOnMainThread:@selector(authorizationNeededForRequest:) withObject:self waitUntilDone:YES];
[authenticationLock lockWhenCondition:2];
... ... @@ -682,14 +701,14 @@ static void ReadStreamClientCallBack(CFReadStreamRef readStream, CFStreamEventTy
- (void)handleBytesAvailable
{
if (!responseHeaders) {
if ([self readResponseHeadersReturningAuthenticationFailure]) {
[self attemptToApplyCredentialsAndResume];
return;
}
}
UInt8 buffer[2048];
CFIndex bytesRead = CFReadStreamRead(readStream, buffer, sizeof(buffer));
... ... @@ -863,4 +882,6 @@ static void ReadStreamClientCallBack(CFReadStreamRef readStream, CFStreamEventTy
@synthesize requestCredentials;
@synthesize responseStatusCode;
@synthesize receivedData;
@synthesize lastActivityTime;
@synthesize timeOutSeconds;
@end
... ...
... ... @@ -13,6 +13,7 @@
}
- (void)testBasicDownload;
- (void)testTimeOut;
- (void)testOperationQueue;
- (void)testCookies;
@end
... ...
... ... @@ -58,6 +58,20 @@ More tests needed for:
STAssertNotNil(error,@"Failed to generate an error for a bad host - this test may fail when your DNS server redirects you to another page when it can't find a domain name (eg OpenDNS)");
}
- (void)testTimeOut
{
//Grab data
NSURL *url = [[[NSURL alloc] initWithString:@"http://allseeing-i.com"] autorelease];
ASIHTTPRequest *request = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease];
[request setTimeOutSeconds:0.0001]; //It's pretty unlikely we will be able to grab the data this quickly, so the request should timeout
[request start];
NSError *error = [request error];
STAssertNotNil(error,@"Request didn't timeout");
BOOL success = [[[error userInfo] valueForKey:@"Description"] isEqualToString:@"Request timed out"];
STAssertTrue(success,@"Timeout didn't generate the correct error");
}
- (void)testOperationQueue
{
NSOperationQueue *queue = [[[NSOperationQueue alloc] init] autorelease];
... ...
... ... @@ -40,4 +40,5 @@
- (IBAction)fetchTopSecretInformation:(id)sender;
- (IBAction)postWithProgress:(id)sender;
@end
... ...
This diff is collapsed. Click to expand it.
This diff could not be displayed because it is too large.