Ben Copsey

Cleanup:

* Move certain properties that the user really shouldn't access to private
* Rename outputStream to fileDownloadOutputStream
* Use getters in more places
... ... @@ -37,7 +37,7 @@ typedef enum _ASINetworkErrorType {
// The delegate, you need to manage setting and talking to your delegate in your subclasses
id delegate;
// A queue delegate that should *ALSO* be notified of delegate message
// A queue delegate that should *ALSO* be notified of delegate message (used by ASINetworkQueue)
id queue;
// HTTP method to use (GET / POST / PUT / DELETE). Defaults to GET
... ... @@ -95,7 +95,7 @@ typedef enum _ASINetworkErrorType {
NSString *temporaryFileDownloadPath;
// Used for writing data to a file when downloadDestinationPath is set
NSOutputStream *outputStream;
NSOutputStream *fileDownloadOutputStream;
// When the request fails or completes successfully, complete will be true
BOOL complete;
... ... @@ -104,9 +104,6 @@ typedef enum _ASINetworkErrorType {
// If error code is = ASIConnectionFailureErrorType (1, Connection failure occurred) - inspect [[error userInfo] objectForKey:NSUnderlyingErrorKey] for more information
NSError *error;
// If an authentication error occurs, we give the delegate a chance to handle it, ignoreError will be set to true
BOOL ignoreError;
// Username and password used for authentication
NSString *username;
NSString *password;
... ... @@ -366,37 +363,33 @@ typedef enum _ASINetworkErrorType {
@property (retain,readonly) NSString *authenticationRealm;
@property (retain) NSError *error;
@property (assign,readonly) BOOL complete;
@property (retain) NSDictionary *responseHeaders;
@property (retain,readonly) NSDictionary *responseHeaders;
@property (retain) NSMutableDictionary *requestHeaders;
@property (retain) NSMutableArray *requestCookies;
@property (retain) NSArray *responseCookies;
@property (retain,readonly) NSArray *responseCookies;
@property (assign) BOOL useCookiePersistance;
@property (retain) NSDictionary *requestCredentials;
@property (assign) int responseStatusCode;
@property (retain) NSMutableData *rawResponseData;
@property (retain) NSDate *lastActivityTime;
@property (assign,readonly) int responseStatusCode;
@property (retain,readonly) NSMutableData *rawResponseData;
@property (assign) NSTimeInterval timeOutSeconds;
@property (retain) NSString *requestMethod;
@property (retain) NSMutableData *postBody;
@property (assign) unsigned long long contentLength;
@property (assign) unsigned long long partialDownloadSize;
@property (assign,readonly) unsigned long long contentLength;
@property (assign) unsigned long long postLength;
@property (assign) BOOL shouldResetProgressIndicators;
@property (retain) ASIHTTPRequest *mainRequest;
@property (assign) BOOL showAccurateProgress;
@property (assign,readonly) unsigned long long totalBytesRead;
@property (assign,readonly) unsigned long long totalBytesSent;
@property (assign) unsigned long long uploadBufferSize;
@property (assign) NSStringEncoding defaultResponseEncoding;
@property (assign) NSStringEncoding responseEncoding;
@property (assign,readonly) NSStringEncoding responseEncoding;
@property (assign) BOOL allowCompressedResponse;
@property (assign) BOOL allowResumeForFileDownloads;
@property (retain) NSDictionary *userInfo;
@property (retain) NSString *postBodyFilePath;
@property (retain) NSOutputStream *postBodyWriteStream;
@property (retain) NSInputStream *postBodyReadStream;
@property (assign) BOOL shouldStreamPostDataFromDisk;
@property (assign) BOOL didCreateTemporaryPostDataFile;
@property (assign) BOOL useHTTPVersionOne;
@property (assign, readonly) unsigned long long partialDownloadSize;
@end
... ...
... ... @@ -38,6 +38,32 @@ static NSError *ASIRequestTimedOutError;
static NSError *ASIAuthenticationError;
static NSError *ASIUnableToCreateRequestError;
// Private stuff
@interface ASIHTTPRequest ()
@property (retain,setter=setURL:) NSURL *url;
@property (assign) BOOL complete;
@property (retain) NSDictionary *responseHeaders;
@property (retain) NSArray *responseCookies;
@property (assign) int responseStatusCode;
@property (retain) NSMutableData *rawResponseData;
@property (retain, nonatomic) NSDate *lastActivityTime;
@property (assign) unsigned long long contentLength;
@property (assign) unsigned long long partialDownloadSize;
@property (assign, nonatomic) unsigned long long uploadBufferSize;
@property (assign) NSStringEncoding responseEncoding;
@property (retain, nonatomic) NSOutputStream *postBodyWriteStream;
@property (retain, nonatomic) NSInputStream *postBodyReadStream;
@property (assign) unsigned long long totalBytesRead;
@property (assign) unsigned long long totalBytesSent;
@property (assign, nonatomic) unsigned long long lastBytesRead;
@property (assign, nonatomic) unsigned long long lastBytesSent;
@property (retain) NSLock *cancelledLock;
@property (assign, nonatomic) BOOL haveBuiltPostBody;
@property (retain, nonatomic) NSOutputStream *fileDownloadOutputStream;
@property (assign, nonatomic) int authenticationRetryCount;
@property (assign, nonatomic) BOOL updatedProgress;
@end
@implementation ASIHTTPRequest
... ... @@ -73,8 +99,8 @@ static NSError *ASIUnableToCreateRequestError;
[self setRequestCookies:[[[NSMutableArray alloc] init] autorelease]];
[self setDidFinishSelector:@selector(requestFinished:)];
[self setDidFailSelector:@selector(requestFailed:)];
url = [newURL retain];
cancelledLock = [[NSLock alloc] init];
[self setURL:newURL];
[self setCancelledLock:[[[NSLock alloc] init] autorelease]];
return self;
}
... ... @@ -96,7 +122,7 @@ static NSError *ASIUnableToCreateRequestError;
[requestCookies release];
[downloadDestinationPath release];
[temporaryFileDownloadPath release];
[outputStream release];
[fileDownloadOutputStream release];
[username release];
[password release];
[domain release];
... ... @@ -147,14 +173,14 @@ static NSError *ASIUnableToCreateRequestError;
[self setPostLength:[postBody length]];
}
if (postLength > 0)
if ([self postLength] > 0)
{
if (![requestMethod isEqualToString:@"POST"] && ![requestMethod isEqualToString:@"PUT"]) {
[self setRequestMethod:@"POST"];
}
[self addRequestHeader:@"Content-Length" value:[NSString stringWithFormat:@"%llu",postLength]];
}
haveBuiltPostBody = YES;
[self setHaveBuiltPostBody:YES];
}
// Sets up storage for the post body
... ... @@ -212,7 +238,7 @@ static NSError *ASIUnableToCreateRequestError;
- (BOOL)isFinished
{
return complete;
return [self complete];
}
... ... @@ -221,7 +247,7 @@ static NSError *ASIUnableToCreateRequestError;
[self failWithError:ASIRequestCancelledError];
[super cancel];
[self cancelLoad];
complete = YES;
[self setComplete:YES];
}
... ... @@ -262,14 +288,14 @@ static NSError *ASIUnableToCreateRequestError;
[pool release];
pool = [[NSAutoreleasePool alloc] init];
complete = NO;
[self setComplete:NO];
if (!url) {
if (![self url]) {
[self failWithError:ASIUnableToCreateRequestError];
return;
}
if (!haveBuiltPostBody) {
if (![self haveBuiltPostBody]) {
[self buildPostBody];
}
... ... @@ -366,18 +392,18 @@ static NSError *ASIUnableToCreateRequestError;
[authenticationLock release];
authenticationLock = [[NSConditionLock alloc] initWithCondition:1];
complete = NO;
totalBytesRead = 0;
lastBytesRead = 0;
[self setComplete:NO];
[self setTotalBytesRead:0];
[self setLastBytesRead:0];
// If we're retrying a request after an authentication failure, let's remove any progress we made
if (lastBytesSent > 0) {
if ([self lastBytesSent] > 0) {
[self removeUploadProgressSoFar];
}
lastBytesSent = 0;
if (shouldResetProgressIndicators) {
contentLength = 0;
[self setLastBytesSent:0];
if ([self shouldResetProgressIndicators]) {
[self setContentLength:0];
[self resetDownloadProgress:0];
}
[self setResponseHeaders:nil];
... ... @@ -459,7 +485,7 @@ static NSError *ASIUnableToCreateRequestError;
if (contentLength <= uploadBufferSize || (uploadBufferSize > 0 && totalBytesSent > uploadBufferSize)) {
[self failWithError:ASIRequestTimedOutError];
[self cancelLoad];
complete = YES;
[self setComplete:YES];
break;
}
}
... ... @@ -472,11 +498,11 @@ static NSError *ASIUnableToCreateRequestError;
// Find out if we've sent any more data than last time, and reset the timeout if so
if (totalBytesSent > lastBytesSent) {
[self setLastActivityTime:[NSDate date]];
lastBytesSent = totalBytesSent;
[self setLastBytesSent:totalBytesSent];
}
// Find out how much data we've uploaded so far
totalBytesSent = [[(NSNumber *)CFReadStreamCopyProperty(readStream, kCFStreamPropertyHTTPRequestBytesWrittenCount) autorelease] unsignedLongLongValue];
[self setTotalBytesSent:[[(NSNumber *)CFReadStreamCopyProperty(readStream, kCFStreamPropertyHTTPRequestBytesWrittenCount) autorelease] unsignedLongLongValue]];
[self updateProgressIndicators];
... ... @@ -505,7 +531,7 @@ static NSError *ASIUnableToCreateRequestError;
// If we were downloading to a file
} else if (temporaryFileDownloadPath) {
[outputStream close];
[fileDownloadOutputStream close];
// If we haven't said we might want to resume, let's remove the temporary file too
if (![self allowResumeForFileDownloads]) {
... ... @@ -556,7 +582,7 @@ static NSError *ASIUnableToCreateRequestError;
//Only update progress if this isn't a HEAD request used to preset the content-length
if (!mainRequest) {
if (showAccurateProgress || (complete && !updatedProgress)) {
if ([self showAccurateProgress] || ([self complete] && ![self updatedProgress])) {
[self updateUploadProgress];
[self updateDownloadProgress];
}
... ... @@ -657,7 +683,7 @@ static NSError *ASIUnableToCreateRequestError;
}
} else {
value = 1;
updatedProgress = YES;
[self setUpdatedProgress:YES];
}
NSMethodSignature *signature = nil;
... ... @@ -721,11 +747,11 @@ static NSError *ASIUnableToCreateRequestError;
NSAutoreleasePool *thePool = [[NSAutoreleasePool alloc] init];
unsigned long long value = 0;
if (showAccurateProgress) {
value = bytesReadSoFar-lastBytesRead;
if ([self showAccurateProgress]) {
value = bytesReadSoFar-[self lastBytesRead];
} else {
value = 1;
updatedProgress = YES;
[self setUpdatedProgress:YES];
}
... ... @@ -743,7 +769,7 @@ static NSError *ASIUnableToCreateRequestError;
[ASIHTTPRequest setProgress:(double)(1.0*bytesReadSoFar/(contentLength+partialDownloadSize)) forProgressIndicator:downloadProgressDelegate];
}
lastBytesRead = bytesReadSoFar;
[self setLastBytesRead:bytesReadSoFar];
}
}
... ... @@ -830,7 +856,7 @@ static NSError *ASIUnableToCreateRequestError;
// If you do this, don't forget to call [super failWithError:] to let the queue / delegate know we're done
- (void)failWithError:(NSError *)theError
{
complete = YES;
[self setComplete:YES];
if ([self isCancelled]) {
return;
... ... @@ -888,12 +914,12 @@ static NSError *ASIUnableToCreateRequestError;
// See if we got a Content-length header
NSString *cLength = [responseHeaders valueForKey:@"Content-Length"];
if (cLength) {
contentLength = CFStringGetIntValue((CFStringRef)cLength);
if (mainRequest) {
[mainRequest setContentLength:contentLength];
[self setContentLength:CFStringGetIntValue((CFStringRef)cLength)];
if ([self mainRequest]) {
[[self mainRequest] setContentLength:contentLength];
}
if (showAccurateProgress && shouldResetProgressIndicators) {
[self resetDownloadProgress:contentLength+partialDownloadSize];
if ([self showAccurateProgress] && [self shouldResetProgressIndicators]) {
[self resetDownloadProgress:[self contentLength]+[self partialDownloadSize]];
}
}
... ... @@ -969,7 +995,7 @@ static NSError *ASIUnableToCreateRequestError;
- (BOOL)applyCredentials:(NSMutableDictionary *)newCredentials
{
authenticationRetryCount++;
[self setAuthenticationRetryCount:[self authenticationRetryCount]+1];
if (newCredentials && requestAuthentication && request) {
// Apply whatever credentials we've built up to the old request
... ... @@ -1088,14 +1114,13 @@ static NSError *ASIUnableToCreateRequestError;
[self setRequestCredentials:nil];
ignoreError = YES;
[self setLastActivityTime:nil];
// If we have a delegate, we'll see if it can handle authorizationNeededForRequest.
// Otherwise, we'll try the queue (if this request is part of one) and it will pass the message on to its own delegate
id authorizationDelegate = delegate;
if (!delegate) {
authorizationDelegate = queue;
id authorizationDelegate = [self delegate];
if (!authorizationDelegate) {
authorizationDelegate = [self queue];
}
if ([authorizationDelegate respondsToSelector:@selector(authorizationNeededForRequest:)]) {
... ... @@ -1144,13 +1169,11 @@ static NSError *ASIUnableToCreateRequestError;
}
// We've got no credentials, let's ask the delegate to sort this out
ignoreError = YES;
// If we have a delegate, we'll see if it can handle authorizationNeededForRequest.
// Otherwise, we'll try the queue (if this request is part of one) and it will pass the message on to its own delegate
id authorizationDelegate = delegate;
if (!delegate) {
authorizationDelegate = queue;
id authorizationDelegate = [self delegate];
if (!authorizationDelegate) {
authorizationDelegate = [self queue];
}
if ([authorizationDelegate respondsToSelector:@selector(authorizationNeededForRequest:)]) {
... ... @@ -1196,7 +1219,7 @@ static NSError *ASIUnableToCreateRequestError;
- (void)handleBytesAvailable
{
if (!responseHeaders) {
if (![self responseHeaders]) {
if ([self readResponseHeadersReturningAuthenticationFailure]) {
[self attemptToApplyCredentialsAndResume];
return;
... ... @@ -1220,11 +1243,11 @@ static NSError *ASIUnableToCreateRequestError;
// If zero bytes were read, wait for the EOF to come.
} else if (bytesRead) {
totalBytesRead += bytesRead;
[self setTotalBytesRead:[self totalBytesRead]+bytesRead];
// Are we downloading to a file?
if (downloadDestinationPath) {
if (!outputStream) {
if ([self downloadDestinationPath]) {
if (![self fileDownloadOutputStream]) {
BOOL append = NO;
if (![self temporaryFileDownloadPath]) {
[self setTemporaryFileDownloadPath:[NSTemporaryDirectory() stringByAppendingPathComponent:[[NSProcessInfo processInfo] globallyUniqueString]]];
... ... @@ -1232,10 +1255,10 @@ static NSError *ASIUnableToCreateRequestError;
append = YES;
}
outputStream = [[NSOutputStream alloc] initToFileAtPath:temporaryFileDownloadPath append:append];
[outputStream open];
[self setFileDownloadOutputStream:[[[NSOutputStream alloc] initToFileAtPath:temporaryFileDownloadPath append:append] autorelease]];
[fileDownloadOutputStream open];
}
[outputStream write:buffer maxLength:bytesRead];
[fileDownloadOutputStream write:buffer maxLength:bytesRead];
//Otherwise, let's add the data to our in-memory store
} else {
... ... @@ -1247,14 +1270,14 @@ static NSError *ASIUnableToCreateRequestError;
- (void)handleStreamComplete
{
//Try to read the headers (if this is a HEAD request handleBytesAvailable available may not be called)
if (!responseHeaders) {
if (![self responseHeaders]) {
if ([self readResponseHeadersReturningAuthenticationFailure]) {
[self attemptToApplyCredentialsAndResume];
return;
}
}
[progressLock lock];
complete = YES;
[self setComplete:YES];
[self updateProgressIndicators];
if (readStream) {
... ... @@ -1274,7 +1297,7 @@ static NSError *ASIUnableToCreateRequestError;
// Close the output stream as we're done writing to the file
if (temporaryFileDownloadPath) {
[outputStream close];
[fileDownloadOutputStream close];
// Decompress the file (if necessary) directly to the destination path
if ([self isResponseCompressed]) {
... ... @@ -1318,9 +1341,9 @@ static NSError *ASIUnableToCreateRequestError;
NSError *underlyingError = [(NSError *)CFReadStreamCopyError(readStream) autorelease];
[self cancelLoad];
complete = YES;
[self setComplete:YES];
if (!error) { // We may already have handled this error
if (![self error]) { // We may already have handled this error
[self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIConnectionFailureErrorType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"A connection failure occurred",NSLocalizedDescriptionKey,underlyingError,NSUnderlyingErrorKey,nil]]];
}
... ... @@ -1599,4 +1622,11 @@ static NSError *ASIUnableToCreateRequestError;
@synthesize shouldStreamPostDataFromDisk;
@synthesize didCreateTemporaryPostDataFile;
@synthesize useHTTPVersionOne;
@synthesize lastBytesRead;
@synthesize lastBytesSent;
@synthesize cancelledLock;
@synthesize haveBuiltPostBody;
@synthesize fileDownloadOutputStream;
@synthesize authenticationRetryCount;
@synthesize updatedProgress;
@end
... ...