From c4b48ed3b050724c2414dc8f763f298bf2e64767 Mon Sep 17 00:00:00 2001 From: UzysJung Date: Thu, 24 Jan 2013 14:13:43 +0900 Subject: [PATCH 01/30] default content-type headerfield added. -'application/x-www-form-urlencoded' if you don't insert this field in condition of POST, it's ok. but in condition of PUT , if you don't insert this field, it doesn't work properly. --- SVHTTPRequest/SVHTTPRequest.m | 1 + 1 file changed, 1 insertion(+) diff --git a/SVHTTPRequest/SVHTTPRequest.m b/SVHTTPRequest/SVHTTPRequest.m index d78b6d0..c65b854 100644 --- a/SVHTTPRequest/SVHTTPRequest.m +++ b/SVHTTPRequest/SVHTTPRequest.m @@ -235,6 +235,7 @@ - (void)addParametersToRequest:(NSDictionary*)paramsDict { if(!hasData) { const char *stringData = [[self parameterStringForDictionary:paramsDict] UTF8String]; NSMutableData *postData = [NSMutableData dataWithBytes:stringData length:strlen(stringData)]; + [self.operationRequest setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; //added by uzys [self.operationRequest setHTTPBody:postData]; } else { From a9e8024aeaa0c3df65b8481f8609032a17a4f8ee Mon Sep 17 00:00:00 2001 From: UzysJung Date: Thu, 24 Jan 2013 15:02:42 +0900 Subject: [PATCH 02/30] added attachment file Content-type in 'multipart/form-data' --- SVHTTPRequest/SVHTTPRequest.m | 94 +++++++++++++++++++++++++++++++++-- 1 file changed, 90 insertions(+), 4 deletions(-) diff --git a/SVHTTPRequest/SVHTTPRequest.m b/SVHTTPRequest/SVHTTPRequest.m index c65b854..a36e39b 100644 --- a/SVHTTPRequest/SVHTTPRequest.m +++ b/SVHTTPRequest/SVHTTPRequest.m @@ -11,6 +11,10 @@ @interface NSData (Base64) - (NSString*)base64EncodingWithLineLength:(unsigned int)lineLength; +- (NSString *)getImageType; +- (BOOL)isJPG; +- (BOOL)isPNG; +- (BOOL)isGIF; @end @interface NSString (OAURLEncodingAdditions) @@ -224,7 +228,7 @@ - (void)addParametersToRequest:(NSDictionary*)paramsDict { [self.operationRequest setHTTPBody:jsonData]; } else { __block BOOL hasData = NO; - + [paramsDict.allValues enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { if([obj isKindOfClass:[NSData class]]) hasData = YES; @@ -244,7 +248,7 @@ - (void)addParametersToRequest:(NSDictionary*)paramsDict { [self.operationRequest setValue:contentType forHTTPHeaderField: @"Content-Type"]; __block NSMutableData *postData = [NSMutableData data]; - + __block int dataIdx = 0; // add string parameters [paramsDict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { if(![obj isKindOfClass:[NSData class]]) { @@ -254,10 +258,23 @@ - (void)addParametersToRequest:(NSDictionary*)paramsDict { [postData appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; } else { [postData appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; - [postData appendData:[[NSString stringWithFormat:@"Content-Disposition: attachment; name=\"%@\"; filename=\"userfile\"\r\n", key] dataUsingEncoding:NSUTF8StringEncoding]]; - [postData appendData:[@"Content-Type: application/octet-stream\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; + + NSString *imageExtension = [obj getImageType]; + + if(imageExtension != nil) + { + [postData appendData:[[NSString stringWithFormat:@"Content-Disposition: attachment; name=\"%@\"; filename=\"userfile%d%x.%@\"\r\n", key,dataIdx,(int)[[NSDate date] timeIntervalSince1970],imageExtension] dataUsingEncoding:NSUTF8StringEncoding]]; + [postData appendData:[[NSString stringWithFormat:@"Content-Type: image/%@\r\n\r\n",imageExtension] dataUsingEncoding:NSUTF8StringEncoding]]; + } + else + { + [postData appendData:[[NSString stringWithFormat:@"Content-Disposition: attachment; name=\"%@\"; filename=\"userfile%d%x\"\r\n", key,dataIdx,(int)[[NSDate date] timeIntervalSince1970]] dataUsingEncoding:NSUTF8StringEncoding]]; + [postData appendData:[@"Content-Type: application/octet-stream\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; + } + [postData appendData:obj]; [postData appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; + dataIdx++; } }]; @@ -622,6 +639,75 @@ - (NSString *)base64EncodingWithLineLength:(unsigned int) lineLength { return result; } +- (BOOL)isJPG +{ + if (self.length > 4) + { + unsigned char buffer[4]; + [self getBytes:&buffer length:4]; + + return buffer[0]==0xff && + buffer[1]==0xd8 && + buffer[2]==0xff && + buffer[3]==0xe0; + } + + return NO; +} + +- (BOOL)isPNG +{ + if (self.length > 4) + { + unsigned char buffer[4]; + [self getBytes:&buffer length:4]; + + return buffer[0]==0x89 && + buffer[1]==0x50 && + buffer[2]==0x4e && + buffer[3]==0x47; + } + + return NO; +} + +- (BOOL)isGIF +{ + if(self.length >3) + { + unsigned char buffer[4]; + [self getBytes:&buffer length:4]; + + return buffer[0]==0x47 && + buffer[1]==0x49 && + buffer[2]==0x46; //Signature ASCII 'G','I','F' + + } + return NO; +} + +- (NSString *)getImageType +{ + NSString *ret; + if([self isJPG]) + { + ret=@"jpg"; + } + else if([self isGIF]) + { + ret=@"gif"; + } + else if([self isPNG]) + { + ret=@"png"; + } + else + { + ret=nil; + } + return ret; +} + @end From 2ff344a1b30c551fd4111e3ccd405113c7f1c391 Mon Sep 17 00:00:00 2001 From: UzysJung Date: Thu, 24 Jan 2013 19:04:09 +0900 Subject: [PATCH 03/30] change indentation style. --- SVHTTPRequest/SVHTTPRequest.m | 41 +++++++++++------------------------ 1 file changed, 13 insertions(+), 28 deletions(-) diff --git a/SVHTTPRequest/SVHTTPRequest.m b/SVHTTPRequest/SVHTTPRequest.m index a36e39b..0203686 100644 --- a/SVHTTPRequest/SVHTTPRequest.m +++ b/SVHTTPRequest/SVHTTPRequest.m @@ -260,14 +260,11 @@ - (void)addParametersToRequest:(NSDictionary*)paramsDict { [postData appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; NSString *imageExtension = [obj getImageType]; - - if(imageExtension != nil) - { + if(imageExtension != nil) { [postData appendData:[[NSString stringWithFormat:@"Content-Disposition: attachment; name=\"%@\"; filename=\"userfile%d%x.%@\"\r\n", key,dataIdx,(int)[[NSDate date] timeIntervalSince1970],imageExtension] dataUsingEncoding:NSUTF8StringEncoding]]; [postData appendData:[[NSString stringWithFormat:@"Content-Type: image/%@\r\n\r\n",imageExtension] dataUsingEncoding:NSUTF8StringEncoding]]; } - else - { + else { [postData appendData:[[NSString stringWithFormat:@"Content-Disposition: attachment; name=\"%@\"; filename=\"userfile%d%x\"\r\n", key,dataIdx,(int)[[NSDate date] timeIntervalSince1970]] dataUsingEncoding:NSUTF8StringEncoding]]; [postData appendData:[@"Content-Type: application/octet-stream\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; } @@ -639,10 +636,8 @@ - (NSString *)base64EncodingWithLineLength:(unsigned int) lineLength { return result; } -- (BOOL)isJPG -{ - if (self.length > 4) - { +- (BOOL)isJPG { + if (self.length > 4) { unsigned char buffer[4]; [self getBytes:&buffer length:4]; @@ -655,10 +650,8 @@ - (BOOL)isJPG return NO; } -- (BOOL)isPNG -{ - if (self.length > 4) - { +- (BOOL)isPNG { + if (self.length > 4) { unsigned char buffer[4]; [self getBytes:&buffer length:4]; @@ -671,38 +664,30 @@ - (BOOL)isPNG return NO; } -- (BOOL)isGIF -{ - if(self.length >3) - { +- (BOOL)isGIF { + if(self.length >3) { unsigned char buffer[4]; [self getBytes:&buffer length:4]; return buffer[0]==0x47 && buffer[1]==0x49 && buffer[2]==0x46; //Signature ASCII 'G','I','F' - } return NO; } -- (NSString *)getImageType -{ +- (NSString *)getImageType { NSString *ret; - if([self isJPG]) - { + if([self isJPG]) { ret=@"jpg"; } - else if([self isGIF]) - { + else if([self isGIF]) { ret=@"gif"; } - else if([self isPNG]) - { + else if([self isPNG]) { ret=@"png"; } - else - { + else { ret=nil; } return ret; From a133449b2fff3c156b7d98bb364d13ea7cb772fb Mon Sep 17 00:00:00 2001 From: Sam Vermette Date: Wed, 6 Feb 2013 04:12:24 -0500 Subject: [PATCH 04/30] Remove @synthesize (Xcode 4.5+). --- SVHTTPRequest/SVHTTPClient.h | 5 ++--- SVHTTPRequest/SVHTTPClient.m | 23 +++++------------------ SVHTTPRequest/SVHTTPRequest.h | 1 - SVHTTPRequest/SVHTTPRequest.m | 31 ++++++++++++------------------- 4 files changed, 19 insertions(+), 41 deletions(-) diff --git a/SVHTTPRequest/SVHTTPClient.h b/SVHTTPRequest/SVHTTPClient.h index 093bfad..4b71981 100644 --- a/SVHTTPRequest/SVHTTPClient.h +++ b/SVHTTPRequest/SVHTTPClient.h @@ -19,6 +19,7 @@ typedef void (^SVHTTPRequestCompletionHandler)(id response, NSHTTPURLResponse *u + (SVHTTPClient*)sharedClientWithIdentifier:(NSString*)identifier; - (void)setBasicAuthWithUsername:(NSString*)username password:(NSString*)password; +- (void)setValue:(NSString *)value forHTTPHeaderField:(NSString *)field; - (SVHTTPRequest*)GET:(NSString*)path parameters:(NSDictionary*)parameters completion:(SVHTTPRequestCompletionHandler)completionBlock; - (SVHTTPRequest*)GET:(NSString*)path parameters:(NSDictionary*)parameters saveToPath:(NSString*)savePath progress:(void (^)(float progress))progressBlock completion:(SVHTTPRequestCompletionHandler)completionBlock; @@ -28,14 +29,12 @@ typedef void (^SVHTTPRequestCompletionHandler)(id response, NSHTTPURLResponse *u - (SVHTTPRequest*)PUT:(NSString*)path parameters:(NSDictionary*)parameters completion:(SVHTTPRequestCompletionHandler)completionBlock; - (SVHTTPRequest*)DELETE:(NSString*)path parameters:(NSDictionary*)parameters completion:(SVHTTPRequestCompletionHandler)completionBlock; - - (SVHTTPRequest*)HEAD:(NSString*)path parameters:(NSDictionary*)parameters completion:(SVHTTPRequestCompletionHandler)completionBlock; - (void)cancelRequestsWithPath:(NSString*)path; - (void)cancelAllRequests; -// header values common to all requests, e.g. API keys -- (void)setValue:(NSString *)value forHTTPHeaderField:(NSString *)field; + @property (nonatomic, strong) NSDictionary *baseParameters; @property (nonatomic, strong) NSString *username; diff --git a/SVHTTPRequest/SVHTTPClient.m b/SVHTTPRequest/SVHTTPClient.m index 0997e1b..5ec9e21 100644 --- a/SVHTTPRequest/SVHTTPClient.m +++ b/SVHTTPRequest/SVHTTPClient.m @@ -28,10 +28,6 @@ - (SVHTTPRequest*)queueRequest:(NSString*)path @implementation SVHTTPClient -@synthesize username, password, basePath, baseParameters, userAgent, sendParametersAsJSON, cachePolicy, timeoutInterval; -@synthesize operationQueue, HTTPHeaderFields; - - + (id)sharedClient { return [self sharedClientWithIdentifier:@"master"]; } @@ -68,17 +64,8 @@ - (id)init { - (void)setBasicAuthWithUsername:(NSString *)newUsername password:(NSString *)newPassword { - - if(username) - username = nil; - - if(password) - password = nil; - - if(newUsername && newPassword) { - username = newUsername; - password = newPassword; - } + self.username = newUsername; + self.password = newPassword; } #pragma mark - Request Methods @@ -128,10 +115,10 @@ - (void)cancelAllRequests { #pragma mark - - (NSMutableDictionary *)HTTPHeaderFields { - if(HTTPHeaderFields == nil) - HTTPHeaderFields = [NSMutableDictionary new]; + if(_HTTPHeaderFields == nil) + _HTTPHeaderFields = [NSMutableDictionary new]; - return HTTPHeaderFields; + return _HTTPHeaderFields; } - (void)setValue:(NSString *)value forHTTPHeaderField:(NSString *)field { diff --git a/SVHTTPRequest/SVHTTPRequest.h b/SVHTTPRequest/SVHTTPRequest.h index 22df5f0..6026327 100644 --- a/SVHTTPRequest/SVHTTPRequest.h +++ b/SVHTTPRequest/SVHTTPRequest.h @@ -32,7 +32,6 @@ typedef NSUInteger SVHTTPRequestMethod; + (SVHTTPRequest*)PUT:(NSString*)address parameters:(NSDictionary*)parameters completion:(SVHTTPRequestCompletionHandler)block; + (SVHTTPRequest*)DELETE:(NSString*)address parameters:(NSDictionary*)parameters completion:(SVHTTPRequestCompletionHandler)block; - + (SVHTTPRequest*)HEAD:(NSString*)address parameters:(NSDictionary*)parameters completion:(SVHTTPRequestCompletionHandler)block; - (SVHTTPRequest*)initWithAddress:(NSString*)urlString diff --git a/SVHTTPRequest/SVHTTPRequest.m b/SVHTTPRequest/SVHTTPRequest.m index d78b6d0..121d71e 100644 --- a/SVHTTPRequest/SVHTTPRequest.m +++ b/SVHTTPRequest/SVHTTPRequest.m @@ -75,20 +75,13 @@ - (void)callCompletionBlockWithResponse:(id)response error:(NSError *)error; @implementation SVHTTPRequest -// public properties -@synthesize sendParametersAsJSON, cachePolicy, timeoutInterval; - -// private properties -@synthesize operationRequest, operationData, operationConnection, operationParameters, operationURLResponse, operationFileHandle, state; -@synthesize operationSavePath, operationCompletionBlock, operationProgressBlock, timeoutTimer; -@synthesize expectedContentLength, receivedContentLength, saveDataDispatchGroup, saveDataDispatchQueue; -@synthesize requestPath, userAgent, client; +@synthesize state = _state; - (void)dealloc { - [operationConnection cancel]; + [_operationConnection cancel]; #if __IPHONE_OS_VERSION_MIN_REQUIRED < 60000 - dispatch_release(saveDataDispatchGroup); - dispatch_release(saveDataDispatchQueue); + dispatch_release(_saveDataDispatchGroup); + dispatch_release(_saveDataDispatchQueue); #endif } @@ -303,11 +296,11 @@ - (void)setValue:(NSString *)value forHTTPHeaderField:(NSString *)field { - (void)setTimeoutTimer:(NSTimer *)newTimer { - if(timeoutTimer) - [timeoutTimer invalidate], timeoutTimer = nil; + if(_timeoutTimer) + [_timeoutTimer invalidate], _timeoutTimer = nil; if(newTimer) - timeoutTimer = newTimer; + _timeoutTimer = newTimer; } #pragma mark - NSOperation methods @@ -337,7 +330,7 @@ - (void)start { [self addParametersToRequest:self.operationParameters]; if(self.userAgent) - [self.operationRequest setValue:userAgent forHTTPHeaderField:@"User-Agent"]; + [self.operationRequest setValue:self.userAgent forHTTPHeaderField:@"User-Agent"]; else if(defaultUserAgent) [self.operationRequest setValue:defaultUserAgent forHTTPHeaderField:@"User-Agent"]; @@ -382,7 +375,7 @@ - (void)start { // private method; not part of NSOperation - (void)finish { [self.operationConnection cancel]; - operationConnection = nil; + self.operationConnection = nil; [self decreaseTaskCount]; @@ -423,14 +416,14 @@ - (BOOL)isExecuting { - (SVHTTPRequestState)state { @synchronized(self) { - return state; + return _state; } } - (void)setState:(SVHTTPRequestState)newState { @synchronized(self) { [self willChangeValueForKey:@"state"]; - state = newState; + _state = newState; [self didChangeValueForKey:@"state"]; } } @@ -497,7 +490,7 @@ - (void)connectionDidFinishLoading:(NSURLConnection *)connection { id response = [NSData dataWithData:self.operationData]; NSError *error = nil; - if ([[operationURLResponse MIMEType] isEqualToString:@"application/json"]) { + if ([[self.operationURLResponse MIMEType] isEqualToString:@"application/json"]) { if(self.operationData && self.operationData.length > 0) { NSDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:response options:NSJSONReadingAllowFragments error:&error]; From 8a2d82a769116b4bac71561a6e7118bff22af930 Mon Sep 17 00:00:00 2001 From: Sam Vermette Date: Thu, 7 Mar 2013 15:16:12 -0500 Subject: [PATCH 05/30] Make setValue:forHTTPHeader: public for SVHTTPRequest as well. --- SVHTTPRequest/SVHTTPClient.m | 2 +- SVHTTPRequest/SVHTTPRequest.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/SVHTTPRequest/SVHTTPClient.m b/SVHTTPRequest/SVHTTPClient.m index 5ec9e21..c6d248d 100644 --- a/SVHTTPRequest/SVHTTPClient.m +++ b/SVHTTPRequest/SVHTTPClient.m @@ -146,7 +146,7 @@ - (SVHTTPRequest*)queueRequest:(NSString*)path [(id)requestOperation setClient:self]; [self.HTTPHeaderFields enumerateKeysAndObjectsUsingBlock:^(NSString *field, NSString *value, BOOL *stop) { - [(id)requestOperation setValue:value forHTTPHeaderField:field]; + [requestOperation setValue:value forHTTPHeaderField:field]; }]; if(self.username && self.password) diff --git a/SVHTTPRequest/SVHTTPRequest.h b/SVHTTPRequest/SVHTTPRequest.h index 6026327..8886b31 100644 --- a/SVHTTPRequest/SVHTTPRequest.h +++ b/SVHTTPRequest/SVHTTPRequest.h @@ -39,6 +39,8 @@ typedef NSUInteger SVHTTPRequestMethod; parameters:(NSDictionary*)parameters completion:(SVHTTPRequestCompletionHandler)completionBlock; +- (void)setValue:(NSString *)value forHTTPHeaderField:(NSString *)field; + + (void)setDefaultTimeoutInterval:(NSTimeInterval)interval; + (void)setDefaultUserAgent:(NSString*)userAgent; @@ -65,6 +67,5 @@ typedef NSUInteger SVHTTPRequestMethod; completion:(SVHTTPRequestCompletionHandler)completionBlock; - (void)signRequestWithUsername:(NSString*)username password:(NSString*)password; -- (void)setValue:(NSString *)value forHTTPHeaderField:(NSString *)field; @end \ No newline at end of file From ed7ddfca5809da81d1a17760bdc93dfd73097079 Mon Sep 17 00:00:00 2001 From: Sam Vermette Date: Thu, 7 Mar 2013 21:21:06 -0500 Subject: [PATCH 06/30] Add support for sending NSArray when sendParametersAsJSON is set to YES. --- SVHTTPRequest/SVHTTPClient.h | 6 +++--- SVHTTPRequest/SVHTTPClient.m | 18 ++++++++++++++---- SVHTTPRequest/SVHTTPRequest.h | 10 +++++----- SVHTTPRequest/SVHTTPRequest.m | 36 +++++++++++++++++++++-------------- 4 files changed, 44 insertions(+), 26 deletions(-) diff --git a/SVHTTPRequest/SVHTTPClient.h b/SVHTTPRequest/SVHTTPClient.h index 4b71981..6a3fab1 100644 --- a/SVHTTPRequest/SVHTTPClient.h +++ b/SVHTTPRequest/SVHTTPClient.h @@ -24,10 +24,10 @@ typedef void (^SVHTTPRequestCompletionHandler)(id response, NSHTTPURLResponse *u - (SVHTTPRequest*)GET:(NSString*)path parameters:(NSDictionary*)parameters completion:(SVHTTPRequestCompletionHandler)completionBlock; - (SVHTTPRequest*)GET:(NSString*)path parameters:(NSDictionary*)parameters saveToPath:(NSString*)savePath progress:(void (^)(float progress))progressBlock completion:(SVHTTPRequestCompletionHandler)completionBlock; -- (SVHTTPRequest*)POST:(NSString*)path parameters:(NSDictionary*)parameters completion:(SVHTTPRequestCompletionHandler)completionBlock; -- (SVHTTPRequest*)POST:(NSString*)path parameters:(NSDictionary*)parameters progress:(void (^)(float progress))progressBlock completion:(void (^)(id response, NSHTTPURLResponse *urlResponse, NSError *error))completionBlock; +- (SVHTTPRequest*)POST:(NSString*)path parameters:(NSObject*)parameters completion:(SVHTTPRequestCompletionHandler)completionBlock; +- (SVHTTPRequest*)POST:(NSString*)path parameters:(NSObject*)parameters progress:(void (^)(float progress))progressBlock completion:(void (^)(id response, NSHTTPURLResponse *urlResponse, NSError *error))completionBlock; +- (SVHTTPRequest*)PUT:(NSString*)path parameters:(NSObject*)parameters completion:(SVHTTPRequestCompletionHandler)completionBlock; -- (SVHTTPRequest*)PUT:(NSString*)path parameters:(NSDictionary*)parameters completion:(SVHTTPRequestCompletionHandler)completionBlock; - (SVHTTPRequest*)DELETE:(NSString*)path parameters:(NSDictionary*)parameters completion:(SVHTTPRequestCompletionHandler)completionBlock; - (SVHTTPRequest*)HEAD:(NSString*)path parameters:(NSDictionary*)parameters completion:(SVHTTPRequestCompletionHandler)completionBlock; diff --git a/SVHTTPRequest/SVHTTPClient.m b/SVHTTPRequest/SVHTTPClient.m index c6d248d..cd40114 100644 --- a/SVHTTPRequest/SVHTTPClient.m +++ b/SVHTTPRequest/SVHTTPClient.m @@ -133,12 +133,22 @@ - (SVHTTPRequest*)queueRequest:(NSString*)path completion:(SVHTTPRequestCompletionHandler)completionBlock { NSString *completeURLString = [NSString stringWithFormat:@"%@%@", self.basePath, path]; + id mergedParameters; - NSMutableDictionary *mergedParameters = [NSMutableDictionary dictionary]; - [mergedParameters addEntriesFromDictionary:parameters]; - [mergedParameters addEntriesFromDictionary:self.baseParameters]; + if((method == SVHTTPRequestMethodPOST || method == SVHTTPRequestMethodPUT) && self.sendParametersAsJSON && ![parameters isKindOfClass:[NSDictionary class]]) + mergedParameters = parameters; + else { + mergedParameters = [NSMutableDictionary dictionary]; + [mergedParameters addEntriesFromDictionary:parameters]; + [mergedParameters addEntriesFromDictionary:self.baseParameters]; + } - SVHTTPRequest *requestOperation = [(id)[SVHTTPRequest alloc] initWithAddress:completeURLString method:method parameters:mergedParameters saveToPath:savePath progress:progressBlock completion:completionBlock]; + SVHTTPRequest *requestOperation = [(id)[SVHTTPRequest alloc] initWithAddress:completeURLString + method:method + parameters:mergedParameters + saveToPath:savePath + progress:progressBlock + completion:completionBlock]; requestOperation.sendParametersAsJSON = self.sendParametersAsJSON; requestOperation.cachePolicy = self.cachePolicy; requestOperation.userAgent = self.userAgent; diff --git a/SVHTTPRequest/SVHTTPRequest.h b/SVHTTPRequest/SVHTTPRequest.h index 8886b31..92a9da5 100644 --- a/SVHTTPRequest/SVHTTPRequest.h +++ b/SVHTTPRequest/SVHTTPRequest.h @@ -27,16 +27,16 @@ typedef NSUInteger SVHTTPRequestMethod; + (SVHTTPRequest*)GET:(NSString*)address parameters:(NSDictionary*)parameters completion:(SVHTTPRequestCompletionHandler)block; + (SVHTTPRequest*)GET:(NSString*)address parameters:(NSDictionary*)parameters saveToPath:(NSString*)savePath progress:(void (^)(float progress))progressBlock completion:(SVHTTPRequestCompletionHandler)completionBlock; -+ (SVHTTPRequest*)POST:(NSString*)address parameters:(NSDictionary*)parameters completion:(SVHTTPRequestCompletionHandler)block; -+ (SVHTTPRequest*)POST:(NSString *)address parameters:(NSDictionary *)parameters progress:(void (^)(float))progressBlock completion:(void (^)(id, NSHTTPURLResponse*, NSError *))completionBlock; ++ (SVHTTPRequest*)POST:(NSString*)address parameters:(NSObject*)parameters completion:(SVHTTPRequestCompletionHandler)block; ++ (SVHTTPRequest*)POST:(NSString *)address parameters:(NSObject *)parameters progress:(void (^)(float))progressBlock completion:(void (^)(id, NSHTTPURLResponse*, NSError *))completionBlock; ++ (SVHTTPRequest*)PUT:(NSString*)address parameters:(NSObject*)parameters completion:(SVHTTPRequestCompletionHandler)block; -+ (SVHTTPRequest*)PUT:(NSString*)address parameters:(NSDictionary*)parameters completion:(SVHTTPRequestCompletionHandler)block; + (SVHTTPRequest*)DELETE:(NSString*)address parameters:(NSDictionary*)parameters completion:(SVHTTPRequestCompletionHandler)block; + (SVHTTPRequest*)HEAD:(NSString*)address parameters:(NSDictionary*)parameters completion:(SVHTTPRequestCompletionHandler)block; - (SVHTTPRequest*)initWithAddress:(NSString*)urlString method:(SVHTTPRequestMethod)method - parameters:(NSDictionary*)parameters + parameters:(NSObject*)parameters completion:(SVHTTPRequestCompletionHandler)completionBlock; - (void)setValue:(NSString *)value forHTTPHeaderField:(NSString *)field; @@ -61,7 +61,7 @@ typedef NSUInteger SVHTTPRequestMethod; - (SVHTTPRequest*)initWithAddress:(NSString*)urlString method:(SVHTTPRequestMethod)method - parameters:(NSDictionary*)parameters + parameters:(NSObject*)parameters saveToPath:(NSString*)savePath progress:(void (^)(float))progressBlock completion:(SVHTTPRequestCompletionHandler)completionBlock; diff --git a/SVHTTPRequest/SVHTTPRequest.m b/SVHTTPRequest/SVHTTPRequest.m index 2c646c1..1cdcf20 100644 --- a/SVHTTPRequest/SVHTTPRequest.m +++ b/SVHTTPRequest/SVHTTPRequest.m @@ -131,21 +131,21 @@ + (SVHTTPRequest*)GET:(NSString *)address parameters:(NSDictionary *)parameters return requestObject; } -+ (SVHTTPRequest*)POST:(NSString *)address parameters:(NSDictionary *)parameters completion:(SVHTTPRequestCompletionHandler)block { ++ (SVHTTPRequest*)POST:(NSString *)address parameters:(NSObject *)parameters completion:(SVHTTPRequestCompletionHandler)block { SVHTTPRequest *requestObject = [[self alloc] initWithAddress:address method:SVHTTPRequestMethodPOST parameters:parameters saveToPath:nil progress:nil completion:block]; [requestObject start]; return requestObject; } -+ (SVHTTPRequest*)POST:(NSString *)address parameters:(NSDictionary *)parameters progress:(void (^)(float))progressBlock completion:(void (^)(id, NSHTTPURLResponse*, NSError *))completionBlock { ++ (SVHTTPRequest*)POST:(NSString *)address parameters:(NSObject *)parameters progress:(void (^)(float))progressBlock completion:(void (^)(id, NSHTTPURLResponse*, NSError *))completionBlock { SVHTTPRequest *requestObject = [[self alloc] initWithAddress:address method:SVHTTPRequestMethodPOST parameters:parameters saveToPath:nil progress:progressBlock completion:completionBlock]; [requestObject start]; return requestObject; } -+ (SVHTTPRequest*)PUT:(NSString *)address parameters:(NSDictionary *)parameters completion:(SVHTTPRequestCompletionHandler)block { ++ (SVHTTPRequest*)PUT:(NSString *)address parameters:(NSObject *)parameters completion:(SVHTTPRequestCompletionHandler)block { SVHTTPRequest *requestObject = [[self alloc] initWithAddress:address method:SVHTTPRequestMethodPUT parameters:parameters saveToPath:nil progress:nil completion:block]; [requestObject start]; @@ -205,22 +205,24 @@ - (SVHTTPRequest*)initWithAddress:(NSString*)urlString method:(SVHTTPRequestMeth } -- (void)addParametersToRequest:(NSDictionary*)paramsDict { +- (void)addParametersToRequest:(NSObject*)parameters { NSString *method = self.operationRequest.HTTPMethod; if([method isEqualToString:@"POST"] || [method isEqualToString:@"PUT"]) { if(self.sendParametersAsJSON) { - [self.operationRequest setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; - NSError *jsonError; - NSData *jsonData = [NSJSONSerialization dataWithJSONObject:paramsDict options:0 error:&jsonError]; - - if(jsonData && jsonError) - [NSException raise:NSInvalidArgumentException format:@"Request parameters couldn't be serialized into JSON."]; - - [self.operationRequest setHTTPBody:jsonData]; - } else { + if([parameters isKindOfClass:[NSArray class]] || [parameters isKindOfClass:[NSDictionary class]]) { + [self.operationRequest setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; + NSError *jsonError; + NSData *jsonData = [NSJSONSerialization dataWithJSONObject:parameters options:0 error:&jsonError]; + [self.operationRequest setHTTPBody:jsonData]; + } + else + [NSException raise:NSInvalidArgumentException format:@"POST and PUT parameters must be provided as NSDictionary or NSArray when sendParametersAsJSON is set to YES."]; + } + else if([parameters isKindOfClass:[NSDictionary class]]) { __block BOOL hasData = NO; + NSDictionary *paramsDict = (NSDictionary*)parameters; [paramsDict.allValues enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { if([obj isKindOfClass:[NSData class]]) @@ -272,12 +274,18 @@ - (void)addParametersToRequest:(NSDictionary*)paramsDict { [self.operationRequest setHTTPBody:postData]; } } - } else { + else + [NSException raise:NSInvalidArgumentException format:@"POST and PUT parameters must be provided as NSDictionary when sendParametersAsJSON is set to NO."]; + } + else if([parameters isKindOfClass:[NSDictionary class]]) { + NSDictionary *paramsDict = (NSDictionary*)parameters; NSString *baseAddress = self.operationRequest.URL.absoluteString; if(paramsDict.count > 0) baseAddress = [baseAddress stringByAppendingFormat:@"?%@", [self parameterStringForDictionary:paramsDict]]; [self.operationRequest setURL:[NSURL URLWithString:baseAddress]]; } + else + [NSException raise:NSInvalidArgumentException format:@"GET and DELETE parameters must be provided as NSDictionary."]; } - (NSString*)parameterStringForDictionary:(NSDictionary*)parameters { From b2e6dcfc7094a6a7f637b9e7d1510124ac0449d6 Mon Sep 17 00:00:00 2001 From: Sam Vermette Date: Thu, 7 Mar 2013 21:23:24 -0500 Subject: [PATCH 07/30] Update installation instructions for CocoaPods. --- README.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7fb15e4..b0d389b 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@ -_**Important note if your project doesn't use ARC**: you must add the `-fobjc-arc` compiler flag to `SVHTTPRequest.m` in Target Settings > Build Phases > Compile Sources._ - # SVHTTPRequest -SVHTTPRequest is a simple and extremely straightforward way to communicate with RESTful web APIs for iOS and Mac. It's a simpler and cleaner alternative to bulky [ASIHTTPRequest](https://github.com/pokeb/asi-http-request/tree), [AFNetworking](https://github.com/AFNetworking/AFNetworking) and [RESTKit](https://github.com/RestKit/RestKit). It is blocked-based, uses `NSURLConnection`, ARC, as well as `NSJSONSerialization` to automatically parse JSON responses (making it only compatible with iOS 5 and Mac OS X Lion). +SVHTTPRequest is a simple and extremely straightforward way to communicate with RESTful web APIs for iOS and Mac. It's a simpler alternative to bulky [ASIHTTPRequest](https://github.com/pokeb/asi-http-request/tree), [AFNetworking](https://github.com/AFNetworking/AFNetworking) and [RESTKit](https://github.com/RestKit/RestKit). It is blocked-based, uses `NSURLConnection`, ARC, as well as `NSJSONSerialization` to automatically parse JSON responses (making it only compatible with iOS 5 and Mac OS X Lion). **SVHTTPRequest features:** @@ -14,6 +12,14 @@ SVHTTPRequest is a simple and extremely straightforward way to communicate with ## Installation +### From CocoaPods + +Add `pod 'SVHTTPRequest'` to your Podfile or `pod 'SVHTTPRequest', :head` if you're feeling adventurous. + +### Manually + +_**If your project doesn't use ARC**: you must add the `-fobjc-arc` compiler flag to `SVHTTPRequest.m` and `SVHTTPClient.m` in Target Settings > Build Phases > Compile Sources._ + * Drag the `SVHTTPRequest/SVHTTPRequest` folder into your project. * `#import "SVHTTPRequest.h"` (this will import `SVHTTPClient` as well) From 0b5ef371a94470cedc6d885159d0c30fe2418c37 Mon Sep 17 00:00:00 2001 From: Sam Vermette Date: Fri, 15 Mar 2013 01:08:02 -0400 Subject: [PATCH 08/30] Assign dispatch groups and queues instead of holding strong ref (causes warnings). --- SVHTTPRequest/SVHTTPRequest.m | 5 ----- 1 file changed, 5 deletions(-) diff --git a/SVHTTPRequest/SVHTTPRequest.m b/SVHTTPRequest/SVHTTPRequest.m index 1cdcf20..56eea5b 100644 --- a/SVHTTPRequest/SVHTTPRequest.m +++ b/SVHTTPRequest/SVHTTPRequest.m @@ -48,13 +48,8 @@ @interface SVHTTPRequest () @property (nonatomic, readwrite) UIBackgroundTaskIdentifier backgroundTaskIdentifier; #endif -#if __IPHONE_OS_VERSION_MIN_REQUIRED < 60000 @property (nonatomic, assign) dispatch_queue_t saveDataDispatchQueue; @property (nonatomic, assign) dispatch_group_t saveDataDispatchGroup; -#else -@property (nonatomic, strong) dispatch_queue_t saveDataDispatchQueue; -@property (nonatomic, strong) dispatch_group_t saveDataDispatchGroup; -#endif @property (nonatomic, copy) SVHTTPRequestCompletionHandler operationCompletionBlock; @property (nonatomic, copy) void (^operationProgressBlock)(float progress); From 7a2bfeb77cdc7182c9ef741c3af6c6acee464325 Mon Sep 17 00:00:00 2001 From: Sam Vermette Date: Sat, 23 Mar 2013 15:46:08 -0400 Subject: [PATCH 09/30] Revert "Assign dispatch groups and queues instead of holding strong ref (causes warnings)." This reverts commit 0b5ef371a94470cedc6d885159d0c30fe2418c37. --- SVHTTPRequest/SVHTTPRequest.m | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/SVHTTPRequest/SVHTTPRequest.m b/SVHTTPRequest/SVHTTPRequest.m index 56eea5b..1cdcf20 100644 --- a/SVHTTPRequest/SVHTTPRequest.m +++ b/SVHTTPRequest/SVHTTPRequest.m @@ -48,8 +48,13 @@ @interface SVHTTPRequest () @property (nonatomic, readwrite) UIBackgroundTaskIdentifier backgroundTaskIdentifier; #endif +#if __IPHONE_OS_VERSION_MIN_REQUIRED < 60000 @property (nonatomic, assign) dispatch_queue_t saveDataDispatchQueue; @property (nonatomic, assign) dispatch_group_t saveDataDispatchGroup; +#else +@property (nonatomic, strong) dispatch_queue_t saveDataDispatchQueue; +@property (nonatomic, strong) dispatch_group_t saveDataDispatchGroup; +#endif @property (nonatomic, copy) SVHTTPRequestCompletionHandler operationCompletionBlock; @property (nonatomic, copy) void (^operationProgressBlock)(float progress); From 3f42c467fc3702a7043ce0ff77eb77c96fbf848e Mon Sep 17 00:00:00 2001 From: Sam Vermette Date: Sat, 23 Mar 2013 15:46:46 -0400 Subject: [PATCH 10/30] Make sharedClient methods return id type. --- SVHTTPRequest/SVHTTPClient.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SVHTTPRequest/SVHTTPClient.h b/SVHTTPRequest/SVHTTPClient.h index 6a3fab1..f814290 100644 --- a/SVHTTPRequest/SVHTTPClient.h +++ b/SVHTTPRequest/SVHTTPClient.h @@ -15,8 +15,8 @@ typedef void (^SVHTTPRequestCompletionHandler)(id response, NSHTTPURLResponse *u @interface SVHTTPClient : NSObject -+ (SVHTTPClient*)sharedClient; -+ (SVHTTPClient*)sharedClientWithIdentifier:(NSString*)identifier; ++ (id)sharedClient; ++ (id)sharedClientWithIdentifier:(NSString*)identifier; - (void)setBasicAuthWithUsername:(NSString*)username password:(NSString*)password; - (void)setValue:(NSString *)value forHTTPHeaderField:(NSString *)field; From bb291fc88d7a1b673fce1aebbea7c00f31f04e6a Mon Sep 17 00:00:00 2001 From: Sam Vermette Date: Tue, 23 Apr 2013 21:18:58 -0400 Subject: [PATCH 11/30] Fix #39. --- SVHTTPRequest/SVHTTPClient.m | 1 + 1 file changed, 1 insertion(+) diff --git a/SVHTTPRequest/SVHTTPClient.m b/SVHTTPRequest/SVHTTPClient.m index cd40114..5425126 100644 --- a/SVHTTPRequest/SVHTTPClient.m +++ b/SVHTTPRequest/SVHTTPClient.m @@ -152,6 +152,7 @@ - (SVHTTPRequest*)queueRequest:(NSString*)path requestOperation.sendParametersAsJSON = self.sendParametersAsJSON; requestOperation.cachePolicy = self.cachePolicy; requestOperation.userAgent = self.userAgent; + requestOperation.timeoutInterval = self.timeoutInterval; [(id)requestOperation setClient:self]; From 0c0ede7b14211bb9ece621f08708271cb898b1c8 Mon Sep 17 00:00:00 2001 From: Sam Vermette Date: Sun, 28 Apr 2013 00:26:16 -0400 Subject: [PATCH 12/30] Clean up demo project. --- Demo/Demo/DemoViewController.m | 11 -- Demo/Demo/en.lproj/DemoViewController.xib | 180 +++++++++++++++------- 2 files changed, 124 insertions(+), 67 deletions(-) diff --git a/Demo/Demo/DemoViewController.m b/Demo/Demo/DemoViewController.m index 51fcb11..c648115 100644 --- a/Demo/Demo/DemoViewController.m +++ b/Demo/Demo/DemoViewController.m @@ -12,7 +12,6 @@ @implementation DemoViewController - (IBAction)watchersRequest { - watchersLabel.text = nil; [SVHTTPRequest GET:@"https://api.github.com/repos/samvermette/SVHTTPRequest" @@ -23,12 +22,9 @@ - (IBAction)watchersRequest { } - (IBAction)twitterRequest { - twitterImageView.image = nil; - followersLabel.text = nil; [[SVHTTPClient sharedClient] setBasePath:@"http://api.twitter.com/1/"]; - [[SVHTTPClient sharedClient] GET:@"users/profile_image" parameters:[NSDictionary dictionaryWithObjectsAndKeys: @"samvermette", @"screen_name", @@ -37,16 +33,9 @@ - (IBAction)twitterRequest { completion:^(id response, NSHTTPURLResponse *urlResponse, NSError *error) { twitterImageView.image = [UIImage imageWithData:response]; }]; - - [[SVHTTPClient sharedClient] GET:@"users/show.json" - parameters:[NSDictionary dictionaryWithObject:@"samvermette" forKey:@"screen_name"] - completion:^(id response, NSHTTPURLResponse *urlResponse, NSError *error) { - followersLabel.text = [NSString stringWithFormat:@"@samvermette has %@ followers", [response valueForKey:@"followers_count"]]; - }]; } - (IBAction)progressRequest { - progressLabel.text = nil; [SVHTTPRequest GET:@"http://sanjosetransit.com/extras/SJTransit_Icons.zip" diff --git a/Demo/Demo/en.lproj/DemoViewController.xib b/Demo/Demo/en.lproj/DemoViewController.xib index b7ba3e1..3cf5578 100644 --- a/Demo/Demo/en.lproj/DemoViewController.xib +++ b/Demo/Demo/en.lproj/DemoViewController.xib @@ -1,22 +1,22 @@ - 1280 - 11D50b - 2182 - 1138.32 - 568.00 + 1552 + 12D78 + 3084 + 1187.37 + 626.00 com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 1179 + 2083 YES + IBProxyObject IBUIButton IBUIImageView - IBUIView IBUILabel - IBProxyObject + IBUIView YES @@ -44,8 +44,9 @@ 292 - {{73, 18}, {171, 44}} + {{77, 48}, {164, 44}} + _NS:222 NO @@ -53,7 +54,7 @@ 0 0 1 - Github GET Request + GET JSON Request 3 MQA @@ -81,8 +82,9 @@ 292 - {{23, 70}, {269, 39}} + {{23, 90}, {269, 39}} + _NS:129 NO @@ -94,6 +96,7 @@ 1 MCAwIDAAA + darkTextColor 1 @@ -112,8 +115,9 @@ 292 - {{71, 124}, {173, 44}} + {{71, 164}, {173, 44}} + _NS:222 NO @@ -121,7 +125,7 @@ 0 0 1 - Twitter GET Request + GET Image Request 1 @@ -134,39 +138,20 @@ 292 - {{109, 192}, {96, 96}} + {{109, 222}, {96, 96}} - + + _NS:363 NO IBCocoaTouchFramework - - - 292 - {{23, 297}, {269, 39}} - - - _NS:129 - NO - YES - 7 - NO - IBCocoaTouchFramework - - - - 1 - 10 - 1 - - - 292 - {{60, 357}, {195, 44}} + {{60, 367}, {195, 44}} + _NS:225 NO @@ -190,8 +175,9 @@ 292 - {{23, 410}, {269, 39}} + {{23, 408}, {269, 39}} + _NS:328 NO YES @@ -210,6 +196,7 @@ {{0, 20}, {320, 460}} + NO @@ -244,14 +231,6 @@ 20 - - - followersLabel - - - - 24 - progressLabel @@ -319,7 +298,6 @@ - @@ -345,11 +323,6 @@ - - 21 - - - 25 @@ -373,7 +346,6 @@ 12.IBPluginDependency 15.IBPluginDependency 18.IBPluginDependency - 21.IBPluginDependency 25.IBPluginDependency 26.IBPluginDependency 6.IBPluginDependency @@ -392,7 +364,6 @@ com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin @@ -409,7 +380,104 @@ 28 - + + + YES + + DemoViewController + UIViewController + + YES + + YES + progressRequest + twitterRequest + watchersRequest + + + YES + id + id + id + + + + YES + + YES + progressRequest + twitterRequest + watchersRequest + + + YES + + progressRequest + id + + + twitterRequest + id + + + watchersRequest + id + + + + + YES + + YES + followersLabel + progressLabel + twitterImageView + watchersLabel + + + YES + UILabel + UILabel + UIImageView + UILabel + + + + YES + + YES + followersLabel + progressLabel + twitterImageView + watchersLabel + + + YES + + followersLabel + UILabel + + + progressLabel + UILabel + + + twitterImageView + UIImageView + + + watchersLabel + UILabel + + + + + IBProjectSource + ./Classes/DemoViewController.h + + + + 0 IBCocoaTouchFramework @@ -418,6 +486,6 @@ YES 3 - 1179 + 2083 From 6073f66392a2347e82dede21823531c66afe56d2 Mon Sep 17 00:00:00 2001 From: Sam Vermette Date: Sun, 28 Apr 2013 00:26:40 -0400 Subject: [PATCH 13/30] Fix bug when custom timeout interval isn't set. --- SVHTTPRequest/SVHTTPRequest.h | 1 - SVHTTPRequest/SVHTTPRequest.m | 11 ++++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/SVHTTPRequest/SVHTTPRequest.h b/SVHTTPRequest/SVHTTPRequest.h index 92a9da5..239c081 100644 --- a/SVHTTPRequest/SVHTTPRequest.h +++ b/SVHTTPRequest/SVHTTPRequest.h @@ -19,7 +19,6 @@ enum { SVHTTPRequestMethodDELETE, SVHTTPRequestMethodHEAD }; - typedef NSUInteger SVHTTPRequestMethod; @interface SVHTTPRequest : NSOperation diff --git a/SVHTTPRequest/SVHTTPRequest.m b/SVHTTPRequest/SVHTTPRequest.m index 1cdcf20..f0c8fb2 100644 --- a/SVHTTPRequest/SVHTTPRequest.m +++ b/SVHTTPRequest/SVHTTPRequest.m @@ -30,8 +30,8 @@ - (NSString*)encodedURLParameterString; typedef NSUInteger SVHTTPRequestState; static NSUInteger taskCount = 0; -static NSTimeInterval defaultTimeoutInterval = 20; static NSString *defaultUserAgent; +static NSTimeInterval SVHTTPRequestTimeoutInterval = 20; @interface SVHTTPRequest () @@ -90,13 +90,19 @@ - (void)dealloc { } + (void)setDefaultTimeoutInterval:(NSTimeInterval)interval { - defaultTimeoutInterval = interval; + SVHTTPRequestTimeoutInterval = interval; } + (void)setDefaultUserAgent:(NSString *)userAgent { defaultUserAgent = userAgent; } +- (NSUInteger)timeoutInterval { + if(_timeoutInterval == 0) + return SVHTTPRequestTimeoutInterval; + return _timeoutInterval; +} + - (void)increaseTaskCount { taskCount++; [self toggleNetworkActivityIndicator]; @@ -178,7 +184,6 @@ - (SVHTTPRequest*)initWithAddress:(NSString*)urlString method:(SVHTTPRequestMeth self.operationProgressBlock = progressBlock; self.operationSavePath = savePath; self.operationParameters = parameters; - self.timeoutInterval = defaultTimeoutInterval; self.saveDataDispatchGroup = dispatch_group_create(); self.saveDataDispatchQueue = dispatch_queue_create("com.samvermette.SVHTTPRequest", DISPATCH_QUEUE_SERIAL); From 2c18fe53f34aef8321492f8cb8cc5a751839a53a Mon Sep 17 00:00:00 2001 From: Sam Vermette Date: Sun, 28 Apr 2013 00:33:38 -0400 Subject: [PATCH 14/30] Update podspec to 0.5. --- Demo/Demo.xcodeproj/project.pbxproj | 8 ++++++-- SVHTTPRequest.podspec | 23 ++++++++++------------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/Demo/Demo.xcodeproj/project.pbxproj b/Demo/Demo.xcodeproj/project.pbxproj index bd01840..c7f528e 100644 --- a/Demo/Demo.xcodeproj/project.pbxproj +++ b/Demo/Demo.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 2206A0A0172CDCBE004A4006 /* SVHTTPRequest.podspec in Resources */ = {isa = PBXBuildFile; fileRef = 2206A09F172CDCBE004A4006 /* SVHTTPRequest.podspec */; }; 220DF2EE150A7B6800E52072 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 220DF2ED150A7B6800E52072 /* Cocoa.framework */; }; 220DF2F8150A7B6800E52072 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 220DF2F6150A7B6800E52072 /* InfoPlist.strings */; }; 220DF2FA150A7B6800E52072 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 220DF2F9150A7B6800E52072 /* main.m */; }; @@ -31,6 +32,7 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 2206A09F172CDCBE004A4006 /* SVHTTPRequest.podspec */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = SVHTTPRequest.podspec; sourceTree = ""; }; 220DF2EB150A7B6800E52072 /* MacDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MacDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 220DF2ED150A7B6800E52072 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = Library/Frameworks/Cocoa.framework; sourceTree = DEVELOPER_DIR; }; 220DF2F0150A7B6800E52072 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; @@ -63,7 +65,7 @@ 225389B114297AFE00856491 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/DemoViewController.xib; sourceTree = ""; }; 225389BE14297B0B00856491 /* SVHTTPRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SVHTTPRequest.h; sourceTree = ""; }; 225389BF14297B0B00856491 /* SVHTTPRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SVHTTPRequest.m; sourceTree = ""; }; - 22A748821630AA83004893A8 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; + 22A748821630AA83004893A8 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Default-568h@2x.png"; path = "../Default-568h@2x.png"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -124,8 +126,8 @@ 2253898914297AFD00856491 = { isa = PBXGroup; children = ( - 22A748821630AA83004893A8 /* Default-568h@2x.png */, 220FDF34149AC4880021F43D /* README.md */, + 2206A09F172CDCBE004A4006 /* SVHTTPRequest.podspec */, 2253899E14297AFE00856491 /* Demo */, 225389B814297B0B00856491 /* SVHTTPRequest */, 220DF2F3150A7B6800E52072 /* MacDemo */, @@ -172,6 +174,7 @@ 2253899F14297AFE00856491 /* Supporting Files */ = { isa = PBXGroup; children = ( + 22A748821630AA83004893A8 /* Default-568h@2x.png */, 225389A014297AFE00856491 /* Demo-Info.plist */, 225389A114297AFE00856491 /* InfoPlist.strings */, 225389A414297AFE00856491 /* main.m */, @@ -275,6 +278,7 @@ 225389B214297AFE00856491 /* DemoViewController.xib in Resources */, 220FDF35149AC4880021F43D /* README.md in Resources */, 22A748831630AA83004893A8 /* Default-568h@2x.png in Resources */, + 2206A0A0172CDCBE004A4006 /* SVHTTPRequest.podspec in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/SVHTTPRequest.podspec b/SVHTTPRequest.podspec index d5beaf2..3f1b4f5 100644 --- a/SVHTTPRequest.podspec +++ b/SVHTTPRequest.podspec @@ -1,15 +1,12 @@ Pod::Spec.new do |s| - s.name = 'SVHTTPRequest' - s.version = '0.4' - s.license = 'MIT' - s.summary = 'Simple REST client for iOS and Mac.' - s.homepage = 'http://samvermette.com/310' - s.author = { 'Sam Vermette' => 'hello@samvermette.com' } - s.source = { :git => 'https://github.com/samvermette/SVHTTPRequest.git', :tag => s.version.to_s } - - s.description = 'SVHTTPRequest is a simple and extremely straightforward way to communicate with RESTful web APIs for iOS and Mac. It is blocked-based, uses NSURLConnection, ARC, as well as NSJSONSerialization to automatically parse JSON responses (making it only compatible with iOS 5+ and OS X 10.7+).' - - s.source_files = 'SVHTTPRequest/*.{h,m}' - s.preserve_paths = 'Demo' - s.requires_arc = true + s.name = 'SVHTTPRequest' + s.version = '0.5' + s.license = 'MIT' + s.summary = 'Simple REST client for iOS and Mac.' + s.homepage = 'http://samvermette.com/310' + s.author = { 'Sam Vermette' => 'hello@samvermette.com' } + s.source = { :git => 'https://github.com/samvermette/SVHTTPRequest.git', :tag => s.version.to_s } + s.description = 'SVHTTPRequest lets you easily interact with RESTful (GET, POST, DELETE, PUT) web APIs. It is blocked-based, uses NSURLConnection, ARC, as well as NSJSONSerialization to automatically parse JSON responses.' + s.source_files = 'SVHTTPRequest/*.{h,m}' + s.requires_arc = true end From fd0cfa149feba82a1467f776389e5cdd13e7e6e0 Mon Sep 17 00:00:00 2001 From: Sam Vermette Date: Sun, 28 Apr 2013 00:38:23 -0400 Subject: [PATCH 15/30] Clean up Readme. --- Demo/Demo.xcodeproj/project.pbxproj | 10 ++++++---- README.md | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Demo/Demo.xcodeproj/project.pbxproj b/Demo/Demo.xcodeproj/project.pbxproj index c7f528e..0e8642c 100644 --- a/Demo/Demo.xcodeproj/project.pbxproj +++ b/Demo/Demo.xcodeproj/project.pbxproj @@ -7,7 +7,8 @@ objects = { /* Begin PBXBuildFile section */ - 2206A0A0172CDCBE004A4006 /* SVHTTPRequest.podspec in Resources */ = {isa = PBXBuildFile; fileRef = 2206A09F172CDCBE004A4006 /* SVHTTPRequest.podspec */; }; + 2206A0A2172CDEC3004A4006 /* SVHTTPRequest.podspec in Resources */ = {isa = PBXBuildFile; fileRef = 2206A0A1172CDEC3004A4006 /* SVHTTPRequest.podspec */; }; + 2206A0A3172CDEC3004A4006 /* SVHTTPRequest.podspec in Resources */ = {isa = PBXBuildFile; fileRef = 2206A0A1172CDEC3004A4006 /* SVHTTPRequest.podspec */; }; 220DF2EE150A7B6800E52072 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 220DF2ED150A7B6800E52072 /* Cocoa.framework */; }; 220DF2F8150A7B6800E52072 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 220DF2F6150A7B6800E52072 /* InfoPlist.strings */; }; 220DF2FA150A7B6800E52072 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 220DF2F9150A7B6800E52072 /* main.m */; }; @@ -32,7 +33,7 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - 2206A09F172CDCBE004A4006 /* SVHTTPRequest.podspec */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = SVHTTPRequest.podspec; sourceTree = ""; }; + 2206A0A1172CDEC3004A4006 /* SVHTTPRequest.podspec */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = SVHTTPRequest.podspec; path = ../SVHTTPRequest.podspec; sourceTree = ""; }; 220DF2EB150A7B6800E52072 /* MacDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MacDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 220DF2ED150A7B6800E52072 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = Library/Frameworks/Cocoa.framework; sourceTree = DEVELOPER_DIR; }; 220DF2F0150A7B6800E52072 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; @@ -127,7 +128,7 @@ isa = PBXGroup; children = ( 220FDF34149AC4880021F43D /* README.md */, - 2206A09F172CDCBE004A4006 /* SVHTTPRequest.podspec */, + 2206A0A1172CDEC3004A4006 /* SVHTTPRequest.podspec */, 2253899E14297AFE00856491 /* Demo */, 225389B814297B0B00856491 /* SVHTTPRequest */, 220DF2F3150A7B6800E52072 /* MacDemo */, @@ -266,6 +267,7 @@ 220DF2F8150A7B6800E52072 /* InfoPlist.strings in Resources */, 220DF2FE150A7B6800E52072 /* Credits.rtf in Resources */, 220DF304150A7B6800E52072 /* MainMenu.xib in Resources */, + 2206A0A3172CDEC3004A4006 /* SVHTTPRequest.podspec in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -278,7 +280,7 @@ 225389B214297AFE00856491 /* DemoViewController.xib in Resources */, 220FDF35149AC4880021F43D /* README.md in Resources */, 22A748831630AA83004893A8 /* Default-568h@2x.png in Resources */, - 2206A0A0172CDCBE004A4006 /* SVHTTPRequest.podspec in Resources */, + 2206A0A2172CDEC3004A4006 /* SVHTTPRequest.podspec in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/README.md b/README.md index b0d389b..f67a51a 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # SVHTTPRequest -SVHTTPRequest is a simple and extremely straightforward way to communicate with RESTful web APIs for iOS and Mac. It's a simpler alternative to bulky [ASIHTTPRequest](https://github.com/pokeb/asi-http-request/tree), [AFNetworking](https://github.com/AFNetworking/AFNetworking) and [RESTKit](https://github.com/RestKit/RestKit). It is blocked-based, uses `NSURLConnection`, ARC, as well as `NSJSONSerialization` to automatically parse JSON responses (making it only compatible with iOS 5 and Mac OS X Lion). +SVHTTPRequest lets you easily interact with RESTful (GET, POST, DELETE, PUT) web APIs. It is blocked-based, uses `NSURLConnection`, ARC, as well as `NSJSONSerialization` to automatically parse JSON responses. **SVHTTPRequest features:** -* straightforward singleton convenience methods for making `GET`, `POST`, `PUT`, `DELETE`, `HEAD` and download requests. +* class methods for quickly making `GET`, `POST`, `PUT`, `DELETE`, `HEAD` and download requests. * completion block handler returning `response` (`NSObject` if JSON, otherwise `NSData`), `NSHTTPURLResponse` and `NSError` objects. * persistent `basePath` and basic authentication signing when using `SVHTTPClient`. * support for `multipart/form-data` parameters in POST and PUT requests. From e91fab7e44d41c653ce9aebb8ef846e297c14a8d Mon Sep 17 00:00:00 2001 From: Sam Vermette Date: Mon, 29 Apr 2013 14:09:16 -0400 Subject: [PATCH 16/30] Fix compile error with setTimeoutInterval. --- SVHTTPRequest/SVHTTPClient.h | 4 ++-- SVHTTPRequest/SVHTTPClient.m | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/SVHTTPRequest/SVHTTPClient.h b/SVHTTPRequest/SVHTTPClient.h index f814290..1f397f9 100644 --- a/SVHTTPRequest/SVHTTPClient.h +++ b/SVHTTPRequest/SVHTTPClient.h @@ -15,8 +15,8 @@ typedef void (^SVHTTPRequestCompletionHandler)(id response, NSHTTPURLResponse *u @interface SVHTTPClient : NSObject -+ (id)sharedClient; -+ (id)sharedClientWithIdentifier:(NSString*)identifier; ++ (instancetype)sharedClient; ++ (instancetype)sharedClientWithIdentifier:(NSString*)identifier; - (void)setBasicAuthWithUsername:(NSString*)username password:(NSString*)password; - (void)setValue:(NSString *)value forHTTPHeaderField:(NSString *)field; diff --git a/SVHTTPRequest/SVHTTPClient.m b/SVHTTPRequest/SVHTTPClient.m index 5425126..c4b9e87 100644 --- a/SVHTTPRequest/SVHTTPClient.m +++ b/SVHTTPRequest/SVHTTPClient.m @@ -28,11 +28,11 @@ - (SVHTTPRequest*)queueRequest:(NSString*)path @implementation SVHTTPClient -+ (id)sharedClient { ++ (instancetype)sharedClient { return [self sharedClientWithIdentifier:@"master"]; } -+ (id)sharedClientWithIdentifier:(NSString *)identifier { ++ (instancetype)sharedClientWithIdentifier:(NSString *)identifier { SVHTTPClient *sharedClient = [[self sharedClients] objectForKey:identifier]; if(!sharedClient) { From 3fa7d473221515e9d8171471a7f153d987fd2d39 Mon Sep 17 00:00:00 2001 From: gcamp Date: Tue, 7 May 2013 14:30:25 -0400 Subject: [PATCH 17/30] Replace basic block by SVHTTPRequestCompletionHandler --- SVHTTPRequest/SVHTTPRequest.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SVHTTPRequest/SVHTTPRequest.h b/SVHTTPRequest/SVHTTPRequest.h index 239c081..afe2a6b 100644 --- a/SVHTTPRequest/SVHTTPRequest.h +++ b/SVHTTPRequest/SVHTTPRequest.h @@ -27,7 +27,7 @@ typedef NSUInteger SVHTTPRequestMethod; + (SVHTTPRequest*)GET:(NSString*)address parameters:(NSDictionary*)parameters saveToPath:(NSString*)savePath progress:(void (^)(float progress))progressBlock completion:(SVHTTPRequestCompletionHandler)completionBlock; + (SVHTTPRequest*)POST:(NSString*)address parameters:(NSObject*)parameters completion:(SVHTTPRequestCompletionHandler)block; -+ (SVHTTPRequest*)POST:(NSString *)address parameters:(NSObject *)parameters progress:(void (^)(float))progressBlock completion:(void (^)(id, NSHTTPURLResponse*, NSError *))completionBlock; ++ (SVHTTPRequest*)POST:(NSString *)address parameters:(NSObject *)parameters progress:(void (^)(float))progressBlock completion:(SVHTTPRequestCompletionHandler)completionBlock; + (SVHTTPRequest*)PUT:(NSString*)address parameters:(NSObject*)parameters completion:(SVHTTPRequestCompletionHandler)block; + (SVHTTPRequest*)DELETE:(NSString*)address parameters:(NSDictionary*)parameters completion:(SVHTTPRequestCompletionHandler)block; From 98ccae4dd294d0f3898cfa510cc9a291350eae3d Mon Sep 17 00:00:00 2001 From: Sam Vermette Date: Sun, 2 Jun 2013 17:11:24 -0400 Subject: [PATCH 18/30] Don't allow task count to go below zero. --- SVHTTPRequest/SVHTTPRequest.m | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/SVHTTPRequest/SVHTTPRequest.m b/SVHTTPRequest/SVHTTPRequest.m index f0c8fb2..3cdd466 100644 --- a/SVHTTPRequest/SVHTTPRequest.m +++ b/SVHTTPRequest/SVHTTPRequest.m @@ -29,7 +29,7 @@ - (NSString*)encodedURLParameterString; typedef NSUInteger SVHTTPRequestState; -static NSUInteger taskCount = 0; +static NSInteger SVHTTPRequestTaskCount = 0; static NSString *defaultUserAgent; static NSTimeInterval SVHTTPRequestTimeoutInterval = 20; @@ -103,20 +103,20 @@ - (NSUInteger)timeoutInterval { return _timeoutInterval; } -- (void)increaseTaskCount { - taskCount++; +- (void)increaseSVHTTPRequestTaskCount { + SVHTTPRequestTaskCount++; [self toggleNetworkActivityIndicator]; } -- (void)decreaseTaskCount { - taskCount--; +- (void)decreaseSVHTTPRequestTaskCount { + SVHTTPRequestTaskCount = MAX(0, SVHTTPRequestTaskCount-1); [self toggleNetworkActivityIndicator]; } - (void)toggleNetworkActivityIndicator { #if TARGET_OS_IPHONE dispatch_async(dispatch_get_main_queue(), ^{ - [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:(taskCount > 0)]; + [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:(SVHTTPRequestTaskCount > 0)]; }); #endif } @@ -351,7 +351,7 @@ - (void)start { #endif dispatch_async(dispatch_get_main_queue(), ^{ - [self increaseTaskCount]; + [self increaseSVHTTPRequestTaskCount]; }); if(self.operationParameters) @@ -405,7 +405,7 @@ - (void)finish { [self.operationConnection cancel]; self.operationConnection = nil; - [self decreaseTaskCount]; + [self decreaseSVHTTPRequestTaskCount]; #if TARGET_OS_IPHONE if(self.backgroundTaskIdentifier != UIBackgroundTaskInvalid) { From 91dd34d947fc2402b9fccf16cb4550acb36c340d Mon Sep 17 00:00:00 2001 From: gcamp Date: Mon, 16 Sep 2013 18:01:55 -0400 Subject: [PATCH 19/30] Fix build on newer Mac OS X --- SVHTTPRequest/SVHTTPRequest.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SVHTTPRequest/SVHTTPRequest.m b/SVHTTPRequest/SVHTTPRequest.m index 3cdd466..3a2dbf4 100644 --- a/SVHTTPRequest/SVHTTPRequest.m +++ b/SVHTTPRequest/SVHTTPRequest.m @@ -83,7 +83,7 @@ @implementation SVHTTPRequest - (void)dealloc { [_operationConnection cancel]; -#if __IPHONE_OS_VERSION_MIN_REQUIRED < 60000 +#if __IPHONE_OS_VERSION_MIN_REQUIRED < 60000 && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7 dispatch_release(_saveDataDispatchGroup); dispatch_release(_saveDataDispatchQueue); #endif From 2d978b39ea9e5b61c5cf0188d93a615a3b6368f8 Mon Sep 17 00:00:00 2001 From: gcamp Date: Mon, 16 Sep 2013 18:05:00 -0400 Subject: [PATCH 20/30] Fix build on newer Mac OS X --- SVHTTPRequest/SVHTTPRequest.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SVHTTPRequest/SVHTTPRequest.m b/SVHTTPRequest/SVHTTPRequest.m index 3a2dbf4..1159006 100644 --- a/SVHTTPRequest/SVHTTPRequest.m +++ b/SVHTTPRequest/SVHTTPRequest.m @@ -48,7 +48,7 @@ @interface SVHTTPRequest () @property (nonatomic, readwrite) UIBackgroundTaskIdentifier backgroundTaskIdentifier; #endif -#if __IPHONE_OS_VERSION_MIN_REQUIRED < 60000 +#if __IPHONE_OS_VERSION_MIN_REQUIRED < 60000 && MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_7 @property (nonatomic, assign) dispatch_queue_t saveDataDispatchQueue; @property (nonatomic, assign) dispatch_group_t saveDataDispatchGroup; #else From 83c2d9b32c278ebdca1deb06acbef3567460cabb Mon Sep 17 00:00:00 2001 From: gcamp Date: Mon, 16 Sep 2013 18:12:04 -0400 Subject: [PATCH 21/30] Actually support older and newer iOS and Mac --- SVHTTPRequest/SVHTTPRequest.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SVHTTPRequest/SVHTTPRequest.m b/SVHTTPRequest/SVHTTPRequest.m index 1159006..097a1fb 100644 --- a/SVHTTPRequest/SVHTTPRequest.m +++ b/SVHTTPRequest/SVHTTPRequest.m @@ -48,7 +48,7 @@ @interface SVHTTPRequest () @property (nonatomic, readwrite) UIBackgroundTaskIdentifier backgroundTaskIdentifier; #endif -#if __IPHONE_OS_VERSION_MIN_REQUIRED < 60000 && MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_7 +#if !OS_OBJECT_USE_OBJC @property (nonatomic, assign) dispatch_queue_t saveDataDispatchQueue; @property (nonatomic, assign) dispatch_group_t saveDataDispatchGroup; #else @@ -83,7 +83,7 @@ @implementation SVHTTPRequest - (void)dealloc { [_operationConnection cancel]; -#if __IPHONE_OS_VERSION_MIN_REQUIRED < 60000 && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7 +#if !OS_OBJECT_USE_OBJC dispatch_release(_saveDataDispatchGroup); dispatch_release(_saveDataDispatchQueue); #endif From 2369bee14c4418b7dc45bab5d9d2dc99714905cf Mon Sep 17 00:00:00 2001 From: gcamp Date: Tue, 17 Sep 2013 12:13:03 -0400 Subject: [PATCH 22/30] Support for passing an file NSURL in a POST or PUT parameter. This will upload the file linked to the URL. --- SVHTTPRequest/SVHTTPRequest.m | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/SVHTTPRequest/SVHTTPRequest.m b/SVHTTPRequest/SVHTTPRequest.m index 097a1fb..54ca010 100644 --- a/SVHTTPRequest/SVHTTPRequest.m +++ b/SVHTTPRequest/SVHTTPRequest.m @@ -230,7 +230,7 @@ - (void)addParametersToRequest:(NSObject*)parameters { NSDictionary *paramsDict = (NSDictionary*)parameters; [paramsDict.allValues enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { - if([obj isKindOfClass:[NSData class]]) + if([obj isKindOfClass:[NSData class]] || [obj isKindOfClass:[NSURL class]]) hasData = YES; else if(![obj isKindOfClass:[NSString class]] && ![obj isKindOfClass:[NSNumber class]]) [NSException raise:NSInvalidArgumentException format:@"%@ requests only accept NSString and NSNumber parameters.", self.operationRequest.HTTPMethod]; @@ -251,25 +251,38 @@ - (void)addParametersToRequest:(NSObject*)parameters { __block int dataIdx = 0; // add string parameters [paramsDict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { - if(![obj isKindOfClass:[NSData class]]) { + if(![obj isKindOfClass:[NSData class]] && ![obj isKindOfClass:[NSURL class]]) { [postData appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; [postData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", key] dataUsingEncoding:NSUTF8StringEncoding]]; [postData appendData:[[NSString stringWithFormat:@"%@", obj] dataUsingEncoding:NSUTF8StringEncoding]]; [postData appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; } else { + NSString *fileName = nil; + NSData *data = nil; + NSString *imageExtension = nil; + if ([obj isKindOfClass:[NSURL class]]) { + fileName = [obj lastPathComponent]; + data = [NSData dataWithContentsOfURL:obj]; + } + else { + imageExtension = [obj getImageType]; + fileName = [NSString stringWithFormat:@"userfile%d%x", dataIdx, (int)[[NSDate date] timeIntervalSince1970]]; + if (imageExtension != nil) + fileName = [fileName stringByAppendingPathExtension:imageExtension]; + data = obj; + } + [postData appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; + [postData appendData:[[NSString stringWithFormat:@"Content-Disposition: attachment; name=\"%@\"; filename=\"%@\"\r\n", key, fileName] dataUsingEncoding:NSUTF8StringEncoding]]; - NSString *imageExtension = [obj getImageType]; if(imageExtension != nil) { - [postData appendData:[[NSString stringWithFormat:@"Content-Disposition: attachment; name=\"%@\"; filename=\"userfile%d%x.%@\"\r\n", key,dataIdx,(int)[[NSDate date] timeIntervalSince1970],imageExtension] dataUsingEncoding:NSUTF8StringEncoding]]; - [postData appendData:[[NSString stringWithFormat:@"Content-Type: image/%@\r\n\r\n",imageExtension] dataUsingEncoding:NSUTF8StringEncoding]]; + [postData appendData:[[NSString stringWithFormat:@"Content-Type: image/%@\r\n\r\n",imageExtension] dataUsingEncoding:NSUTF8StringEncoding]]; } else { - [postData appendData:[[NSString stringWithFormat:@"Content-Disposition: attachment; name=\"%@\"; filename=\"userfile%d%x\"\r\n", key,dataIdx,(int)[[NSDate date] timeIntervalSince1970]] dataUsingEncoding:NSUTF8StringEncoding]]; [postData appendData:[@"Content-Type: application/octet-stream\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; } - [postData appendData:obj]; + [postData appendData:data]; [postData appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; dataIdx++; } From 7a46baa1c8c18e78cd394ffe04c8a46af4c03e6f Mon Sep 17 00:00:00 2001 From: Sam Vermette Date: Fri, 27 Sep 2013 23:07:18 -0400 Subject: [PATCH 23/30] Bump podspec to 0.5.1. --- SVHTTPRequest.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SVHTTPRequest.podspec b/SVHTTPRequest.podspec index 3f1b4f5..38b0e2e 100644 --- a/SVHTTPRequest.podspec +++ b/SVHTTPRequest.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'SVHTTPRequest' - s.version = '0.5' + s.version = '0.5.1' s.license = 'MIT' s.summary = 'Simple REST client for iOS and Mac.' s.homepage = 'http://samvermette.com/310' From 801745ce5db7eaa5bf659723c579a220c5bc0ec6 Mon Sep 17 00:00:00 2001 From: Sam Vermette Date: Wed, 26 Mar 2014 13:16:57 -0400 Subject: [PATCH 24/30] Any statusCode > 299 returns error. --- SVHTTPRequest/SVHTTPRequest.m | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/SVHTTPRequest/SVHTTPRequest.m b/SVHTTPRequest/SVHTTPRequest.m index f0c8fb2..cd68a01 100644 --- a/SVHTTPRequest/SVHTTPRequest.m +++ b/SVHTTPRequest/SVHTTPRequest.m @@ -544,13 +544,23 @@ - (void)callCompletionBlockWithResponse:(id)response error:(NSError *)error { dispatch_async(dispatch_get_main_queue(), ^{ NSError *serverError = error; - if(!serverError && self.operationURLResponse.statusCode == 500) { - serverError = [NSError errorWithDomain:NSURLErrorDomain - code:NSURLErrorBadServerResponse - userInfo:[NSDictionary dictionaryWithObjectsAndKeys: - @"Bad Server Response.", NSLocalizedDescriptionKey, - self.operationRequest.URL, NSURLErrorFailingURLErrorKey, - self.operationRequest.URL.absoluteString, NSURLErrorFailingURLStringErrorKey, nil]]; + if(!serverError) { + if(self.operationURLResponse.statusCode == 500) { + serverError = [NSError errorWithDomain:NSURLErrorDomain + code:NSURLErrorBadServerResponse + userInfo:[NSDictionary dictionaryWithObjectsAndKeys: + @"Bad Server Response.", NSLocalizedDescriptionKey, + self.operationRequest.URL, NSURLErrorFailingURLErrorKey, + self.operationRequest.URL.absoluteString, NSURLErrorFailingURLStringErrorKey, nil]]; + } + else if(self.operationURLResponse.statusCode > 299) { + serverError = [NSError errorWithDomain:NSURLErrorDomain + code:self.operationURLResponse.statusCode + userInfo:[NSDictionary dictionaryWithObjectsAndKeys: + self.operationRequest.URL, NSURLErrorFailingURLErrorKey, + self.operationRequest.URL.absoluteString, NSURLErrorFailingURLStringErrorKey, nil]]; + + } } if(self.operationCompletionBlock && !self.isCancelled) From 99f3bec70bbb35e3ac3cdf0552f1ad4f80240a03 Mon Sep 17 00:00:00 2001 From: Guillaume Campagna Date: Thu, 5 Jun 2014 15:37:27 -0700 Subject: [PATCH 25/30] Fix use in a iOS extension --- SVHTTPRequest/SVHTTPRequest.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/SVHTTPRequest/SVHTTPRequest.m b/SVHTTPRequest/SVHTTPRequest.m index 54ca010..ad4e201 100644 --- a/SVHTTPRequest/SVHTTPRequest.m +++ b/SVHTTPRequest/SVHTTPRequest.m @@ -114,7 +114,7 @@ - (void)decreaseSVHTTPRequestTaskCount { } - (void)toggleNetworkActivityIndicator { -#if TARGET_OS_IPHONE +#if TARGET_OS_IPHONE && !__has_feature(attribute_availability_app_extension) dispatch_async(dispatch_get_main_queue(), ^{ [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:(SVHTTPRequestTaskCount > 0)]; }); @@ -353,7 +353,7 @@ - (void)start { return; } -#if TARGET_OS_IPHONE +#if TARGET_OS_IPHONE && !__has_feature(attribute_availability_app_extension) // all requests should complete and run completion block unless we explicitely cancel them. self.backgroundTaskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ if(self.backgroundTaskIdentifier != UIBackgroundTaskInvalid) { @@ -420,7 +420,7 @@ - (void)finish { [self decreaseSVHTTPRequestTaskCount]; -#if TARGET_OS_IPHONE +#if TARGET_OS_IPHONE && !__has_feature(attribute_availability_app_extension) if(self.backgroundTaskIdentifier != UIBackgroundTaskInvalid) { [[UIApplication sharedApplication] endBackgroundTask:self.backgroundTaskIdentifier]; self.backgroundTaskIdentifier = UIBackgroundTaskInvalid; From 5615048d0b621b8e274ecca6bbd502b1cc8f8fec Mon Sep 17 00:00:00 2001 From: Tran-Quan Luong Date: Fri, 10 Oct 2014 15:14:00 -0400 Subject: [PATCH 26/30] Expose method to directly queue an SVHTTPRequest. --- SVHTTPRequest/SVHTTPClient.h | 2 +- SVHTTPRequest/SVHTTPClient.m | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/SVHTTPRequest/SVHTTPClient.h b/SVHTTPRequest/SVHTTPClient.h index 1f397f9..5c94860 100644 --- a/SVHTTPRequest/SVHTTPClient.h +++ b/SVHTTPRequest/SVHTTPClient.h @@ -33,7 +33,7 @@ typedef void (^SVHTTPRequestCompletionHandler)(id response, NSHTTPURLResponse *u - (void)cancelRequestsWithPath:(NSString*)path; - (void)cancelAllRequests; - +- (SVHTTPRequest*)queueRequest:(SVHTTPRequest*)requestOperation; @property (nonatomic, strong) NSDictionary *baseParameters; diff --git a/SVHTTPRequest/SVHTTPClient.m b/SVHTTPRequest/SVHTTPClient.m index c4b9e87..eb561af 100644 --- a/SVHTTPRequest/SVHTTPClient.m +++ b/SVHTTPRequest/SVHTTPClient.m @@ -149,6 +149,10 @@ - (SVHTTPRequest*)queueRequest:(NSString*)path saveToPath:savePath progress:progressBlock completion:completionBlock]; + return [self queueRequest:requestOperation]; +} + +- (SVHTTPRequest*)queueRequest:(SVHTTPRequest*)requestOperation { requestOperation.sendParametersAsJSON = self.sendParametersAsJSON; requestOperation.cachePolicy = self.cachePolicy; requestOperation.userAgent = self.userAgent; @@ -163,7 +167,6 @@ - (SVHTTPRequest*)queueRequest:(NSString*)path if(self.username && self.password) [(id)requestOperation signRequestWithUsername:self.username password:self.password]; - [(id)requestOperation setRequestPath:path]; [self.operationQueue addOperation:requestOperation]; return requestOperation; From d8d42583f5b45c7011d87108722bcf93b3f658fd Mon Sep 17 00:00:00 2001 From: Tran-Quan Luong Date: Fri, 10 Oct 2014 15:15:29 -0400 Subject: [PATCH 27/30] Set request parameters in initializer. Expose NSMutableURLRequest instance. --- SVHTTPRequest/SVHTTPRequest.h | 1 + SVHTTPRequest/SVHTTPRequest.m | 19 ++++++++++++------- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/SVHTTPRequest/SVHTTPRequest.h b/SVHTTPRequest/SVHTTPRequest.h index afe2a6b..61b6b3d 100644 --- a/SVHTTPRequest/SVHTTPRequest.h +++ b/SVHTTPRequest/SVHTTPRequest.h @@ -47,6 +47,7 @@ typedef NSUInteger SVHTTPRequestMethod; @property (nonatomic, readwrite) BOOL sendParametersAsJSON; @property (nonatomic, readwrite) NSURLRequestCachePolicy cachePolicy; @property (nonatomic, readwrite) NSUInteger timeoutInterval; +@property (nonatomic, strong) NSMutableURLRequest *operationRequest; @end diff --git a/SVHTTPRequest/SVHTTPRequest.m b/SVHTTPRequest/SVHTTPRequest.m index 87fbebe..75fa5eb 100644 --- a/SVHTTPRequest/SVHTTPRequest.m +++ b/SVHTTPRequest/SVHTTPRequest.m @@ -35,11 +35,9 @@ - (NSString*)encodedURLParameterString; @interface SVHTTPRequest () -@property (nonatomic, strong) NSMutableURLRequest *operationRequest; @property (nonatomic, strong) NSMutableData *operationData; @property (nonatomic, strong) NSFileHandle *operationFileHandle; @property (nonatomic, strong) NSURLConnection *operationConnection; -@property (nonatomic, strong) NSDictionary *operationParameters; @property (nonatomic, strong) NSHTTPURLResponse *operationURLResponse; @property (nonatomic, strong) NSString *operationSavePath; @property (nonatomic, assign) CFRunLoopRef operationRunLoop; @@ -183,12 +181,18 @@ - (SVHTTPRequest*)initWithAddress:(NSString*)urlString method:(SVHTTPRequestMeth self.operationCompletionBlock = completionBlock; self.operationProgressBlock = progressBlock; self.operationSavePath = savePath; - self.operationParameters = parameters; self.saveDataDispatchGroup = dispatch_group_create(); self.saveDataDispatchQueue = dispatch_queue_create("com.samvermette.SVHTTPRequest", DISPATCH_QUEUE_SERIAL); - self.operationRequest = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:urlString]]; + NSURL *url = [[NSURL alloc] initWithString:urlString]; + self.operationRequest = [[NSMutableURLRequest alloc] initWithURL:url]; + + NSString *path = url.path; + if ([path hasPrefix:@"/"]) { + path = [path substringFromIndex:1]; + } + [self setRequestPath:path]; // pipeline all but POST and downloads if(method != SVHTTPRequestMethodPOST && !savePath) @@ -204,8 +208,12 @@ - (SVHTTPRequest*)initWithAddress:(NSString*)urlString method:(SVHTTPRequestMeth [self.operationRequest setHTTPMethod:@"DELETE"]; else if(method == SVHTTPRequestMethodHEAD) [self.operationRequest setHTTPMethod:@"HEAD"]; + self.state = SVHTTPRequestStateReady; + if(parameters) + [self addParametersToRequest:parameters]; + return self; } @@ -367,9 +375,6 @@ - (void)start { [self increaseSVHTTPRequestTaskCount]; }); - if(self.operationParameters) - [self addParametersToRequest:self.operationParameters]; - if(self.userAgent) [self.operationRequest setValue:self.userAgent forHTTPHeaderField:@"User-Agent"]; else if(defaultUserAgent) From f5b72abcdace2be266416cdce79e4bb963fe6fad Mon Sep 17 00:00:00 2001 From: gcamp Date: Tue, 13 Jan 2015 15:45:48 -0500 Subject: [PATCH 28/30] Fix parameters as JSON not available from init --- SVHTTPRequest/SVHTTPRequest.h | 1 + SVHTTPRequest/SVHTTPRequest.m | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/SVHTTPRequest/SVHTTPRequest.h b/SVHTTPRequest/SVHTTPRequest.h index 61b6b3d..8403c52 100644 --- a/SVHTTPRequest/SVHTTPRequest.h +++ b/SVHTTPRequest/SVHTTPRequest.h @@ -38,6 +38,7 @@ typedef NSUInteger SVHTTPRequestMethod; parameters:(NSObject*)parameters completion:(SVHTTPRequestCompletionHandler)completionBlock; +- (void)preprocessParameters; - (void)setValue:(NSString *)value forHTTPHeaderField:(NSString *)field; + (void)setDefaultTimeoutInterval:(NSTimeInterval)interval; diff --git a/SVHTTPRequest/SVHTTPRequest.m b/SVHTTPRequest/SVHTTPRequest.m index 75fa5eb..4e6dbc6 100644 --- a/SVHTTPRequest/SVHTTPRequest.m +++ b/SVHTTPRequest/SVHTTPRequest.m @@ -35,6 +35,7 @@ - (NSString*)encodedURLParameterString; @interface SVHTTPRequest () +@property (nonatomic, strong) NSDictionary *parameters; @property (nonatomic, strong) NSMutableData *operationData; @property (nonatomic, strong) NSFileHandle *operationFileHandle; @property (nonatomic, strong) NSURLConnection *operationConnection; @@ -211,12 +212,16 @@ - (SVHTTPRequest*)initWithAddress:(NSString*)urlString method:(SVHTTPRequestMeth self.state = SVHTTPRequestStateReady; - if(parameters) - [self addParametersToRequest:parameters]; + self.parameters = parameters; return self; } +- (void)preprocessParameters { + if(self.parameters) + [self addParametersToRequest:self.parameters]; + self.parameters = nil; +} - (void)addParametersToRequest:(NSObject*)parameters { @@ -361,6 +366,8 @@ - (void)start { return; } + [self preprocessParameters]; + #if TARGET_OS_IPHONE && !__has_feature(attribute_availability_app_extension) // all requests should complete and run completion block unless we explicitely cancel them. self.backgroundTaskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ From d9c7cd7e3fe2ac8d35ffaa391bf1a7ea52873774 Mon Sep 17 00:00:00 2001 From: gcamp Date: Mon, 23 Mar 2015 10:43:29 -0400 Subject: [PATCH 29/30] Fix issue where JSON could be in ASCII and not parsed by NSJSONSerialization --- SVHTTPRequest/SVHTTPRequest.m | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/SVHTTPRequest/SVHTTPRequest.m b/SVHTTPRequest/SVHTTPRequest.m index 4e6dbc6..044293b 100644 --- a/SVHTTPRequest/SVHTTPRequest.m +++ b/SVHTTPRequest/SVHTTPRequest.m @@ -545,7 +545,14 @@ - (void)connectionDidFinishLoading:(NSURLConnection *)connection { if ([[self.operationURLResponse MIMEType] isEqualToString:@"application/json"]) { if(self.operationData && self.operationData.length > 0) { - NSDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:response options:NSJSONReadingAllowFragments error:&error]; + //We parse the string before, because we need it to be UTF-8 in NSJSONSerialization + NSString *utf8String = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding]; + if (utf8String == nil) { + utf8String = [[NSString alloc] initWithData:response encoding:NSASCIIStringEncoding]; + } + + NSDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:[utf8String dataUsingEncoding:NSUTF8StringEncoding] + options:NSJSONReadingAllowFragments error:&error]; if(jsonObject) response = jsonObject; From 6339ee4fabdfc00aac718866c32127f88f78bd51 Mon Sep 17 00:00:00 2001 From: juliensaad Date: Thu, 1 Mar 2018 17:54:05 -0500 Subject: [PATCH 30/30] Fix build assuming UIKit is included by pch --- SVHTTPRequest/SVHTTPRequest.m | 1 + 1 file changed, 1 insertion(+) diff --git a/SVHTTPRequest/SVHTTPRequest.m b/SVHTTPRequest/SVHTTPRequest.m index 044293b..7731675 100644 --- a/SVHTTPRequest/SVHTTPRequest.m +++ b/SVHTTPRequest/SVHTTPRequest.m @@ -8,6 +8,7 @@ // #import "SVHTTPRequest.h" +#import @interface NSData (Base64) - (NSString*)base64EncodingWithLineLength:(unsigned int)lineLength;