Skip to content

Commit

Permalink
Merge branch 'master' into 1.0RC2
Browse files Browse the repository at this point in the history
Conflicts:
	AFNetworking/AFHTTPClient.m
	AFNetworking/AFHTTPRequestOperation.m
	AFNetworking/AFJSONRequestOperation.m
	AFNetworking/AFNetworkActivityIndicatorManager.m
	AFNetworking/AFURLConnectionOperation.h
  • Loading branch information
mattt committed Sep 14, 2012
2 parents c8d9f79 + b8dff45 commit ff37bb5
Show file tree
Hide file tree
Showing 20 changed files with 626 additions and 448 deletions.
10 changes: 5 additions & 5 deletions AFNetworking.podspec
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
Pod::Spec.new do |s|
s.name = 'AFNetworking'
s.version = '0.10.0'
s.version = '0.10.1'
s.license = 'MIT'
s.summary = 'A delightful iOS and OS X networking framework'
s.summary = 'A delightful iOS and OS X networking framework.'
s.homepage = 'https://github.com/AFNetworking/AFNetworking'
s.authors = {'Mattt Thompson' => '[email protected]', 'Scott Raymond' => 'sco@gowalla.com'}
s.source = { :git => 'https://github.com/AFNetworking/AFNetworking.git', :tag => '0.10.0' }
s.authors = {'Mattt Thompson' => '[email protected]', 'Scott Raymond' => 'sco@scottraymond.net'}
s.source = { :git => 'https://github.com/AFNetworking/AFNetworking.git', :tag => '0.10.1' }
s.source_files = 'AFNetworking'
s.clean_paths = ['iOS Example', 'Mac Example', 'AFNetworking.xcworkspace']
s.framework = 'SystemConfiguration'
s.prefix_header_contents = "#import <SystemConfiguration/SystemConfiguration.h>"
end
270 changes: 162 additions & 108 deletions AFNetworking/AFHTTPClient.h

Large diffs are not rendered by default.

262 changes: 148 additions & 114 deletions AFNetworking/AFHTTPClient.m

Large diffs are not rendered by default.

57 changes: 18 additions & 39 deletions AFNetworking/AFHTTPRequestOperation.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,6 @@
#import <Foundation/Foundation.h>
#import "AFURLConnectionOperation.h"

/**
Returns a set of MIME types detected in an HTTP `Accept` or `Content-Type` header.
*/
extern NSSet * AFContentTypesFromHTTPHeader(NSString *string);

extern NSString * AFCreateIncompleteDownloadDirectoryPath(void);

/**
`AFHTTPRequestOperation` is a subclass of `AFURLConnectionOperation` for requests using the HTTP or HTTPS protocols. It encapsulates the concept of acceptable status codes and content types, which determine the success or failure of a request.
*/
Expand All @@ -44,30 +37,6 @@ extern NSString * AFCreateIncompleteDownloadDirectoryPath(void);
*/
@property (readonly, nonatomic, strong) 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 (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
///----------------------------------------------------------
Expand All @@ -85,16 +54,16 @@ extern NSString * AFCreateIncompleteDownloadDirectoryPath(void);
/**
The callback dispatch queue on success. If `NULL` (default), the main queue is used.
*/
@property (nonatomic) dispatch_queue_t successCallbackQueue;
@property (nonatomic, assign) dispatch_queue_t successCallbackQueue;

/**
The callback dispatch queue on failure. If `NULL` (default), the main queue is used.
*/
@property (nonatomic) dispatch_queue_t failureCallbackQueue;
@property (nonatomic, assign) dispatch_queue_t failureCallbackQueue;

///-------------------------------------------------------------
/// @name Managing Accceptable HTTP Status Codes & Content Types
///-------------------------------------------------------------
///------------------------------------------------------------
/// @name Managing Acceptable HTTP Status Codes & Content Types
///------------------------------------------------------------

/**
Returns an `NSIndexSet` object containing the ranges of acceptable HTTP status codes. When non-`nil`, the operation will set the `error` property to an error in `AFErrorDomain`. See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
Expand All @@ -104,7 +73,7 @@ extern NSString * AFCreateIncompleteDownloadDirectoryPath(void);
+ (NSIndexSet *)acceptableStatusCodes;

/**
Adds status codes to the set of acceptable HTTP status codes returned by `+acceptableStatusCodes` in subsequent calls by this class and its descendents.
Adds status codes to the set of acceptable HTTP status codes returned by `+acceptableStatusCodes` in subsequent calls by this class and its descendants.
@param statusCodes The status codes to be added to the set of acceptable HTTP status codes
*/
Expand All @@ -118,7 +87,7 @@ extern NSString * AFCreateIncompleteDownloadDirectoryPath(void);
+ (NSSet *)acceptableContentTypes;

/**
Adds content types to the set of acceptable MIME types returned by `+acceptableContentTypes` in subsequent calls by this class and its descendents.
Adds content types to the set of acceptable MIME types returned by `+acceptableContentTypes` in subsequent calls by this class and its descendants.
@param contentTypes The content types to be added to the set of acceptable MIME types
*/
Expand All @@ -144,11 +113,21 @@ extern NSString * AFCreateIncompleteDownloadDirectoryPath(void);
Sets the `completionBlock` property with a block that executes either the specified success or failure block, depending on the state of the request on completion. If `error` returns a value, which can be caused by an unacceptable status code or content type, then `failure` is executed. Otherwise, `success` is executed.
@param success The block to be executed on the completion of a successful request. This block has no return value and takes two arguments: the receiver operation and the object constructed from the response data of the request.
@param failure The block to be executed on the completion of an unsuccessful request. This block has no return value and takes two arguments: the receiver operation and the error that occured during the request.
@param failure The block to be executed on the completion of an unsuccessful request. This block has no return value and takes two arguments: the receiver operation and the error that occurred during the request.
@discussion This method should be overridden in subclasses in order to specify the response object passed into the success block.
*/
- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure;

@end

///----------------
/// @name Functions
///----------------

/**
Returns a set of MIME types detected in an HTTP `Accept` or `Content-Type` header.
*/
extern NSSet * AFContentTypesFromHTTPHeader(NSString *string);

113 changes: 56 additions & 57 deletions AFNetworking/AFHTTPRequestOperation.m
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@
#define AF_CAST_TO_BLOCK __bridge void *
#endif

NSString * const kAFNetworkingIncompleteDownloadDirectoryName = @"Incomplete";

NSSet * AFContentTypesFromHTTPHeader(NSString *string) {
static NSCharacterSet *_skippedCharacterSet = nil;
static dispatch_once_t onceToken;
Expand Down Expand Up @@ -83,11 +81,11 @@ static void AFSwizzleClassMethodWithClassAndSelectorUsingBlock(Class klass, SEL
}

if (range.length == 1) {
[string appendFormat:@"%u", range.location];
[string appendFormat:@"%lu", (long)range.location];
} else {
NSUInteger firstIndex = range.location;
NSUInteger lastIndex = firstIndex + range.length - 1;
[string appendFormat:@"%u-%u", firstIndex, lastIndex];
[string appendFormat:@"%lu-%lu", (long)firstIndex, (long)lastIndex];
}

range.location = nextIndex;
Expand All @@ -97,23 +95,6 @@ static void AFSwizzleClassMethodWithClassAndSelectorUsingBlock(Class klass, SEL
return string;
}

NSString * AFCreateIncompleteDownloadDirectoryPath(void) {
static NSString *incompleteDownloadPath;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSString *tempDirectory = NSTemporaryDirectory();
incompleteDownloadPath = [tempDirectory stringByAppendingPathComponent:kAFNetworkingIncompleteDownloadDirectoryName];

NSError *error = nil;
NSFileManager *fileMan = [[NSFileManager alloc] init];
if(![fileMan createDirectoryAtPath:incompleteDownloadPath withIntermediateDirectories:YES attributes:nil error:&error]) {
NSLog(@"Failed to create incomplete downloads directory at %@", incompleteDownloadPath);
}
});

return incompleteDownloadPath;
}

#pragma mark -

@interface AFHTTPRequestOperation ()
Expand All @@ -126,7 +107,6 @@ @interface AFHTTPRequestOperation ()

@implementation AFHTTPRequestOperation
@synthesize HTTPError = _HTTPError;
@synthesize responseFilePath = _responseFilePath;
@synthesize successCallbackQueue = _successCallbackQueue;
@synthesize failureCallbackQueue = _failureCallbackQueue;
@synthesize totalContentLength = _totalContentLength;
Expand All @@ -148,18 +128,24 @@ - (void)dealloc {

- (NSError *)error {
if (self.response && !self.HTTPError) {
if (![self hasAcceptableStatusCode]) {
if (![self hasAcceptableStatusCode] || ![self hasAcceptableContentType]) {
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
[userInfo setValue:[NSString stringWithFormat:NSLocalizedString(@"Expected status code in (%@), got %d", nil), AFStringFromIndexSet([[self class] acceptableStatusCodes]), [self.response statusCode]] forKey:NSLocalizedDescriptionKey];
[userInfo setValue:self.responseString forKey:NSLocalizedRecoverySuggestionErrorKey];
[userInfo setValue:[self.request URL] forKey:NSURLErrorFailingURLErrorKey];
[userInfo setValue:self.request forKey:AFNetworkingOperationFailingURLRequestErrorKey];
[userInfo setValue:self.response forKey:AFNetworkingOperationFailingURLResponseErrorKey];

self.HTTPError = [[NSError alloc] initWithDomain:AFNetworkingErrorDomain code:NSURLErrorBadServerResponse userInfo:userInfo];
} else if ([self.responseData length] > 0 && ![self hasAcceptableContentType]) { // Don't invalidate content type if there is no content
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
[userInfo setValue:[NSString stringWithFormat:NSLocalizedString(@"Expected content type %@, got %@", nil), [[self class] acceptableContentTypes], [self.response MIMEType]] forKey:NSLocalizedDescriptionKey];
[userInfo setValue:[self.request URL] forKey:NSURLErrorFailingURLErrorKey];

self.HTTPError = [[NSError alloc] initWithDomain:AFNetworkingErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:userInfo];
if (![self hasAcceptableStatusCode]) {
NSUInteger statusCode = ([self.response isKindOfClass:[NSHTTPURLResponse class]]) ? (NSUInteger)[self.response statusCode] : 200;
[userInfo setValue:[NSString stringWithFormat:NSLocalizedString(@"Expected status code in (%@), got %d", nil), AFStringFromIndexSet([[self class] acceptableStatusCodes]), statusCode] forKey:NSLocalizedDescriptionKey];
self.HTTPError = [[NSError alloc] initWithDomain:AFNetworkingErrorDomain code:NSURLErrorBadServerResponse userInfo:userInfo];
} else if (![self hasAcceptableContentType]) {
// Don't invalidate content type if there is no content
if ([self.responseData length] > 0) {
[userInfo setValue:[NSString stringWithFormat:NSLocalizedString(@"Expected content type %@, got %@", nil), [[self class] acceptableContentTypes], [self.response MIMEType]] forKey:NSLocalizedDescriptionKey];
self.HTTPError = [[NSError alloc] initWithDomain:AFNetworkingErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:userInfo];
}
}
}
}

Expand Down Expand Up @@ -189,11 +175,28 @@ - (void)pause {
}

- (BOOL)hasAcceptableStatusCode {
return ![[self class] acceptableStatusCodes] || [[[self class] acceptableStatusCodes] containsIndex:[self.response statusCode]];
if (!self.response) {
return NO;
}

NSUInteger statusCode = ([self.response isKindOfClass:[NSHTTPURLResponse class]]) ? (NSUInteger)[self.response statusCode] : 200;
return ![[self class] acceptableStatusCodes] || [[[self class] acceptableStatusCodes] containsIndex:statusCode];
}

- (BOOL)hasAcceptableContentType {
return ![[self class] acceptableContentTypes] || [[[self class] acceptableContentTypes] containsObject:[self.response MIMEType]];
if (!self.response) {
return NO;
}

// According to RFC 2616:
// Any HTTP/1.1 message containing an entity-body SHOULD include a Content-Type header field defining the media type of that body. If and only if the media type is not given by a Content-Type field, the recipient MAY attempt to guess the media type via inspection of its content and/or the name extension(s) of the URI used to identify the resource. If the media type remains unknown, the recipient SHOULD treat it as type "application/octet-stream".
// See http://www.w3.org/Protocols/rfc2616/rfc2616-sec7.html
NSString *contentType = [self.response MIMEType];
if (!contentType) {
contentType = @"application/octet-stream";
}

return ![[self class] acceptableContentTypes] || [[[self class] acceptableContentTypes] containsObject:contentType];
}

- (void)setSuccessCallbackQueue:(dispatch_queue_t)successCallbackQueue {
Expand Down Expand Up @@ -252,18 +255,6 @@ - (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operatio
#pragma clang diagnostic pop
}

- (void)setResponseFilePath:(NSString *)responseFilePath {
if ([self isReady] && responseFilePath != _responseFilePath) {
_responseFilePath = responseFilePath;

if (responseFilePath) {
self.outputStream = [NSOutputStream outputStreamToFileAtPath:responseFilePath append:NO];
}else {
self.outputStream = [NSOutputStream outputStreamToMemory];
}
}
}

#pragma mark - AFHTTPRequestOperation

+ (NSIndexSet *)acceptableStatusCodes {
Expand Down Expand Up @@ -305,30 +296,38 @@ - (void)connection:(NSURLConnection *)connection
{
self.response = (NSHTTPURLResponse *)response;

// 206 = Partial Content.
// Set Content-Range header if status code of response is 206 (Partial Content)
// See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.7
long long totalContentLength = self.response.expectedContentLength;
long long fileOffset = 0;
if ([self.response statusCode] != 206) {
NSUInteger statusCode = ([self.response isKindOfClass:[NSHTTPURLResponse class]]) ? (NSUInteger)[self.response statusCode] : 200;
if (statusCode == 206) {
NSString *contentRange = [self.response.allHeaderFields valueForKey:@"Content-Range"];
if ([contentRange hasPrefix:@"bytes"]) {
NSArray *byteRanges = [contentRange componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@" -/"]];
if ([byteRanges count] == 4) {
fileOffset = [[byteRanges objectAtIndex:1] longLongValue];
totalContentLength = [[byteRanges objectAtIndex:2] longLongValue] ?: -1; // if this is "*", it's converted to 0, but -1 is default.
}
}
} else {
if ([self.outputStream propertyForKey:NSStreamFileCurrentOffsetKey]) {
[self.outputStream setProperty:[NSNumber numberWithInteger:0] forKey:NSStreamFileCurrentOffsetKey];
} else {
if ([[self.outputStream propertyForKey:NSStreamDataWrittenToMemoryStreamKey] length] > 0) {
self.outputStream = [NSOutputStream outputStreamToMemory];

NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
for (NSString *runLoopMode in self.runLoopModes) {
[self.outputStream scheduleInRunLoop:runLoop forMode:runLoopMode];
}
}
}
}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];
}

Expand Down
6 changes: 1 addition & 5 deletions AFNetworking/AFImageRequestOperation.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,11 @@

#if __IPHONE_OS_VERSION_MIN_REQUIRED
/**
The scale factor used when interpreting the image data to construct `responseImage`. Specifying a scale factor of 1.0 results in an image whose size matches the pixel-based dimensions of the image. Applying a different scale factor changes the size of the image as reported by the size property. This is set to the value of `[[UIScreen mainScreen] scale]` by default, which automatically scales images for retina displays, for instance.
The scale factor used when interpreting the image data to construct `responseImage`. Specifying a scale factor of 1.0 results in an image whose size matches the pixel-based dimensions of the image. Applying a different scale factor changes the size of the image as reported by the size property. This is set to the value of scale of the main screen by default, which automatically scales images for retina displays, for instance.
*/
@property (nonatomic, assign) CGFloat imageScale;
#endif

/**
An image constructed from the response data. If an error occurs during the request, `nil` will be returned, and the `error` property will be set to the error.
*/

/**
Creates and returns an `AFImageRequestOperation` object and sets the specified success callback.
Expand Down
5 changes: 4 additions & 1 deletion AFNetworking/AFImageRequestOperation.m
Original file line number Diff line number Diff line change
Expand Up @@ -157,9 +157,12 @@ - (UIImage *)responseImage {
}

- (void)setImageScale:(CGFloat)imageScale {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wfloat-equal"
if (imageScale == _imageScale) {
return;
}
#pragma clang diagnostic pop

_imageScale = imageScale;

Expand All @@ -178,7 +181,7 @@ - (NSImage *)responseImage {
}
#endif

#pragma mark - AFHTTPClientOperation
#pragma mark - AFHTTPRequestOperation

+ (NSSet *)acceptableContentTypes {
return [NSSet setWithObjects:@"image/tiff", @"image/jpeg", @"image/gif", @"image/png", @"image/ico", @"image/x-icon", @"image/bmp", @"image/x-bmp", @"image/x-xbitmap", @"image/x-win-bitmap", nil];
Expand Down
2 changes: 1 addition & 1 deletion AFNetworking/AFJSONRequestOperation.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
@param urlRequest The request object to be loaded asynchronously during execution of the operation
@param success A block object to be executed when the operation finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the JSON object created from the response data of request.
@param failure A block object to be executed when the operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the resonse data as JSON. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the error describing the network or parsing error that occurred.
@param failure A block object to be executed when the operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data as JSON. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the error describing the network or parsing error that occurred.
@return A new JSON request operation
*/
Expand Down
Loading

0 comments on commit ff37bb5

Please sign in to comment.