diff --git a/AFNetworking/AFHTTPRequestOperation.h b/AFNetworking/AFHTTPRequestOperation.h index 28c8639..c4e0bd5 100644 --- a/AFNetworking/AFHTTPRequestOperation.h +++ b/AFNetworking/AFHTTPRequestOperation.h @@ -50,9 +50,28 @@ extern NSString * AFCreateIncompleteDownloadDirectoryPath(void); @property (readonly, nonatomic, retain) NSHTTPURLResponse *response; /** - + Set a target file for the response, will stream directly into this destination. + Defaults to nil, which will use a memory stream. Will create a new outputStream on change. + + Note: Changing this while the request is not in ready state will be ignored. */ -@property (readonly, nonatomic, copy) NSString *responseFilePath; +@property (nonatomic, copy) NSString *responseFilePath; + + +/** + Expected total length. This is different than expectedContentLength if the file is resumed. + On regular requests, this is equal to self.response.expectedContentLength unless we resume a request. + + Note: this can also be -1 if the file size is not sent (*) + */ +@property (assign, readonly) long long totalContentLength; + +/** + Indicator for the file offset on partial/resumed downloads. + This is greater than zero if the file download is resumed. + */ +@property (assign, readonly) long long offsetContentLength; + ///---------------------------------------------------------- /// @name Managing And Checking For Acceptable HTTP Responses diff --git a/AFNetworking/AFHTTPRequestOperation.m b/AFNetworking/AFHTTPRequestOperation.m index 49247a8..8d389a0 100644 --- a/AFNetworking/AFHTTPRequestOperation.m +++ b/AFNetworking/AFHTTPRequestOperation.m @@ -114,7 +114,8 @@ NSString * AFCreateIncompleteDownloadDirectoryPath(void) { @property (readwrite, nonatomic, retain) NSURLRequest *request; @property (readwrite, nonatomic, retain) NSHTTPURLResponse *response; @property (readwrite, nonatomic, retain) NSError *HTTPError; -@property (readwrite, nonatomic, copy) NSString *responseFilePath; +@property (assign) long long totalContentLength; +@property (assign) long long offsetContentLength; @end @implementation AFHTTPRequestOperation @@ -122,6 +123,8 @@ NSString * AFCreateIncompleteDownloadDirectoryPath(void) { @synthesize responseFilePath = _responseFilePath; @synthesize successCallbackQueue = _successCallbackQueue; @synthesize failureCallbackQueue = _failureCallbackQueue; +@synthesize totalContentLength = _totalContentLength; +@synthesize offsetContentLength = _offsetContentLength; @dynamic request; @dynamic response; @@ -241,6 +244,19 @@ NSString * AFCreateIncompleteDownloadDirectoryPath(void) { }; } +- (void)setResponseFilePath:(NSString *)responseFilePath { + if ([self isReady] && responseFilePath != _responseFilePath) { + [_responseFilePath release]; + _responseFilePath = [responseFilePath retain]; + + if (responseFilePath) { + self.outputStream = [NSOutputStream outputStreamToFileAtPath:responseFilePath append:NO]; + }else { + self.outputStream = [NSOutputStream outputStreamToMemory]; + } + } +} + #pragma mark - AFHTTPClientOperation + (NSIndexSet *)acceptableStatusCodes { @@ -283,6 +299,8 @@ didReceiveResponse:(NSURLResponse *)response self.response = (NSHTTPURLResponse *)response; // 206 = Partial Content. + long long totalContentLength = self.response.expectedContentLength; + long long fileOffset = 0; if ([self.response statusCode] != 206) { if ([self.outputStream propertyForKey:NSStreamFileCurrentOffsetKey]) { [self.outputStream setProperty:[NSNumber numberWithInteger:0] forKey:NSStreamFileCurrentOffsetKey]; @@ -291,8 +309,19 @@ didReceiveResponse:(NSURLResponse *)response self.outputStream = [NSOutputStream outputStreamToMemory]; } } + }else { + NSString *contentRange = [self.response.allHeaderFields valueForKey:@"Content-Range"]; + if ([contentRange hasPrefix:@"bytes"]) { + NSArray *bytes = [contentRange componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@" -/"]]; + if ([bytes count] == 4) { + fileOffset = [[bytes objectAtIndex:1] longLongValue]; + totalContentLength = [[bytes objectAtIndex:2] longLongValue] ?: -1; // if this is *, it's converted to 0, but -1 is default. + } + } + } - + self.offsetContentLength = MAX(fileOffset, 0); + self.totalContentLength = totalContentLength; [self.outputStream open]; }