Created
May 31, 2012 02:10
-
-
Save echoz/2840408 to your computer and use it in GitHub Desktop.
Class to generate HTTP Post Body
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// LBCHTTPPostBody.h | |
// LBCCore | |
// | |
// Created by Jeremy Foo on 22/5/12. | |
// Copyright (c) 2012 BOB FTW PTE LTD. All rights reserved. | |
// | |
// Permission is hereby granted, free of charge, to any person obtaining a copy of | |
// this software and associated documentation files (the "Software"), to deal in | |
// the Software without restriction, including without limitation the rights to | |
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of | |
// the Software, and to permit persons to whom the Software is furnished to do so, | |
// subject to the following conditions: | |
// | |
// The above copyright notice and this permission notice shall be included in all | |
// copies or substantial portions of the Software. | |
// | |
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
// SOFTWARE. | |
#import <Foundation/Foundation.h> | |
// result is either a stream file NSURL or a NSData | |
typedef void (^LBCHTTPPostBodyGenerationCompletionHandler)(BOOL isStreamFile, NSString *contentType, NSString *contentLength, id result, NSError *error); | |
typedef enum { | |
LBCHTTPPostBodyNoSuchStreamFileError, | |
LBCHTTPPostBodyWrongURLPathSpecifiedError | |
} LBCHTTPPostBodyErrorStatus; | |
extern NSString *const LBCHTTPPostBodyErrorDomain; | |
@interface LBCHTTPPostBody : NSObject <NSStreamDelegate, NSCoding> | |
@property (readonly) NSMutableDictionary *parameters; | |
+(void)performStreamGenerationOfParamters:(NSDictionary *)params toPath:(NSURL *)path completion:(LBCHTTPPostBodyGenerationCompletionHandler)completion; | |
+(void)performAutomaticHTTPBodyGenerationOfParameters:(NSDictionary *)params completion:(LBCHTTPPostBodyGenerationCompletionHandler)completion; | |
-(id)initWithHTTPParameters:(NSDictionary *)params; | |
-(void)performAutomatic:(BOOL)automatic HTTPBodyGenerationWithCompletion:(LBCHTTPPostBodyGenerationCompletionHandler)completion; | |
-(void)performStreamGenerationToPath:(NSURL *)path completion:(LBCHTTPPostBodyGenerationCompletionHandler)completion; | |
// HTTPBody Specific Methods | |
+(BOOL)isExistingFileURLForObject:(id)obj; | |
+(BOOL)needMultiPartForParameters:(NSDictionary *)params hasExternalFile:(BOOL *)externalFile; | |
// NSData Convinence Methods | |
+(NSData *)octetStreamHeaderForName:(NSString *)name filename:(NSString *)filename; | |
+(NSData *)octetStreamFooter; | |
+(void)appendData:(NSMutableData *)data key:(NSString *)key value:(NSString *)value; | |
+(void)appendData:(NSMutableData *)data key:(NSString *)key data:(NSData *)dataValue; | |
+(NSInteger)appendOutputStream:(NSOutputStream *)stream key:(NSString *)key value:(NSString *)value; | |
+(NSInteger)appendOutputStream:(NSOutputStream *)stream key:(NSString *)key data:(NSData *)dataValue; | |
// String Utilities | |
+(NSString *)hashForData:(NSData *)data; | |
+(NSString *)urlEncodedStringFromParams:(NSDictionary *)params; | |
+(NSString *)escapeString:(NSString *)str; | |
+(NSString *)escapeString:(NSString *)str withEscapees:(NSString *)escapees; | |
+(NSString *)multipartBoundary; | |
+(NSString *)contentTypeForMultipart; | |
+(NSURL *)fileURLForTemporaryStreamFile; | |
@end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// LBCHTTPPostBody.m | |
// LBCCore | |
// | |
// Created by Jeremy Foo on 22/5/12. | |
// Copyright (c) 2012 BOB FTW PTE LTD. All rights reserved. | |
// | |
// Permission is hereby granted, free of charge, to any person obtaining a copy of | |
// this software and associated documentation files (the "Software"), to deal in | |
// the Software without restriction, including without limitation the rights to | |
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of | |
// the Software, and to permit persons to whom the Software is furnished to do so, | |
// subject to the following conditions: | |
// | |
// The above copyright notice and this permission notice shall be included in all | |
// copies or substantial portions of the Software. | |
// | |
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
// SOFTWARE. | |
#import "LBCHTTPPostBody.h" | |
#import <CommonCrypto/CommonDigest.h> | |
#define HTTP_MULTIPART_BOUNDARY @"h3110th1s1slbcur1r3qu35tsh-t-t-p-b0und4r7" | |
#define FILE_STREAM_FORMNAME_KEY @"FORMNAME" | |
#define FILE_STREAM_FILEPATH_KEY @"FILEPATH" | |
NSString *const LBCHTTPPostBodyErrorDomain = @"LBCHTTPPostBodyErrorDomain"; | |
@interface LBCHTTPPostBody (/* Private Method */) | |
@property (nonatomic, copy) LBCHTTPPostBodyGenerationCompletionHandler _completion; | |
@property (nonatomic, retain) NSString *_pathToMultipartBody; | |
@property (nonatomic, retain) NSInputStream *_fileStream; | |
@property (nonatomic, retain) NSOutputStream *_multipartBodyOutputStream; | |
@property (nonatomic, retain) NSMutableArray *_filesToStream; | |
-(void)_processFileStream; | |
-(void)_prepareHTTPBodyForStreamToPath:(NSURL *)path; | |
-(void)_completeStreamConstruction; | |
@end | |
@implementation LBCHTTPPostBody | |
@synthesize parameters; | |
@synthesize _completion; | |
@synthesize _fileStream = __fileStream, _multipartBodyOutputStream = __multipartBodyOutputStream, _pathToMultipartBody = __pathToMultipartBody, _filesToStream = __filesToStream; | |
#pragma mark - NSCoding | |
-(void)encodeWithCoder:(NSCoder *)aCoder { | |
[aCoder encodeObject:self.parameters forKey:@"paramters"]; | |
} | |
-(id)initWithCoder:(NSCoder *)aDecoder { | |
return [self initWithHTTPParameters:[aDecoder decodeObjectForKey:@"parameters"]]; | |
} | |
#pragma mark - Object Life Cycle | |
+(void)performAutomaticHTTPBodyGenerationOfParameters:(NSDictionary *)params completion:(LBCHTTPPostBodyGenerationCompletionHandler)completion { | |
NSAssert1((completion != nil), @"Completion cannot be nil if this is a static method call", nil); | |
LBCHTTPPostBody *postbody = [[LBCHTTPPostBody alloc] initWithHTTPParameters:params]; | |
[postbody performAutomatic:YES HTTPBodyGenerationWithCompletion:^(BOOL isStreamFile, NSString *contentType, NSString *contentLength, id result, NSError *error) { | |
completion(isStreamFile, contentType, contentLength, result, error); | |
}]; | |
[postbody release]; | |
} | |
+(void)performStreamGenerationOfParamters:(NSDictionary *)params toPath:(NSURL *)path completion:(LBCHTTPPostBodyGenerationCompletionHandler)completion { | |
NSAssert1((completion != nil), @"Completion cannot be nil if this is a static method call", nil); | |
LBCHTTPPostBody *postbody = [[LBCHTTPPostBody alloc] initWithHTTPParameters:params]; | |
[postbody performStreamGenerationToPath:path completion:^(BOOL isStreamFile, NSString *contentType, NSString *contentLength, id result, NSError *error) { | |
completion(isStreamFile, contentType, contentLength, result, error); | |
}]; | |
[postbody release]; | |
} | |
-(id)initWithHTTPParameters:(NSDictionary *)params { | |
if ((self = [super init])) { | |
parameters = [params mutableCopy]; | |
} | |
return self; | |
} | |
-(void)dealloc { | |
[__pathToMultipartBody release], __pathToMultipartBody = nil; | |
[__multipartBodyOutputStream release], __multipartBodyOutputStream = nil; | |
[__fileStream release], __fileStream = nil; | |
[__filesToStream release], __filesToStream = nil; | |
[_completion release], _completion = nil; | |
[parameters release], parameters = nil; | |
[super dealloc]; | |
} | |
#pragma mark - Body Generation | |
-(void)performStreamGenerationToPath:(NSURL *)path completion:(LBCHTTPPostBodyGenerationCompletionHandler)completion { | |
if (![path isFileURL]) { | |
if (completion) | |
completion(NO, nil, nil, nil, [NSError errorWithDomain:LBCHTTPPostBodyErrorDomain code:LBCHTTPPostBodyWrongURLPathSpecifiedError userInfo:nil]); | |
return; | |
} | |
self._completion = completion; | |
[self _prepareHTTPBodyForStreamToPath:path]; | |
} | |
-(void)performAutomatic:(BOOL)automatic HTTPBodyGenerationWithCompletion:(LBCHTTPPostBodyGenerationCompletionHandler)completion { | |
NSAssert1((completion != nil), @"Completion block cannot be nil", nil); | |
// do check to decide if you want to URLEncode or not | |
// if a URL exists as a param and is a fileURL to a valid file | |
// do no URL encode, generate a stream instead. | |
BOOL hasExternalFile = NO; | |
if ([[self class] needMultiPartForParameters:parameters hasExternalFile:&hasExternalFile]) { | |
// lets do bit wise values to decide if we should use in memory generation | |
// the only condition we should do contrary is when auto is YES and hasExternal is YES | |
int extFile = 0; | |
if (hasExternalFile) | |
extFile = 1; | |
int atmtic = 0; | |
if (automatic) | |
atmtic = 1; | |
if (~(extFile & atmtic)) { | |
// can generate in memory in place | |
NSMutableData *postData = [NSMutableData data]; | |
NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", [[self class] multipartBoundary]]; | |
@autoreleasepool { | |
for (NSString *key in parameters) { | |
[postData appendData:[[NSString stringWithFormat:@"--%@\r\n", [[self class] multipartBoundary]] dataUsingEncoding:NSUTF8StringEncoding]]; | |
if ([[parameters objectForKey:key] isKindOfClass:[NSData class]]) { | |
[[self class] appendData:postData key:key data:[parameters objectForKey:key]]; | |
} else if ([[parameters objectForKey:key] isKindOfClass:[NSURL class]]) { | |
if (([[parameters objectForKey:key] filePathURL]) && | |
([[NSFileManager defaultManager] fileExistsAtPath:[[[parameters objectForKey:key] filePathURL] path]])) { | |
NSData *fileData = [NSData dataWithContentsOfFile:[[parameters objectForKey:key] path]]; | |
[[self class] appendData:postData key:key data:fileData]; | |
} else { | |
[[self class] appendData:postData key:key value:[[parameters objectForKey:key] absoluteString]]; | |
} | |
} else { | |
[[self class] appendData:postData key:key value:[parameters objectForKey:key]]; | |
} | |
} | |
[postData appendData:[[NSString stringWithFormat:@"--%@--\r\n", [[self class] multipartBoundary]] dataUsingEncoding:NSUTF8StringEncoding]]; | |
} | |
if (completion) | |
completion(NO, contentType, [NSString stringWithFormat:@"%ld", [postData length]], postData, nil); | |
} else { | |
// need to do generation | |
self._completion = completion; | |
[self _prepareHTTPBodyForStreamToPath:[[self class] fileURLForTemporaryStreamFile]]; | |
} | |
} else { | |
NSString *contentType = @"application/x-www-form-urlencoded"; | |
NSData *postData = [[[self class] urlEncodedStringFromParams:parameters] dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]; | |
if (completion) | |
completion(NO, contentType, [NSString stringWithFormat:@"%ld", [postData length]], postData, nil); | |
} | |
} | |
#pragma mark - Stream Construction | |
-(void)_completeStreamConstruction { | |
if ([[NSFileManager defaultManager] fileExistsAtPath:self._pathToMultipartBody]) { | |
NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", [[self class] multipartBoundary]]; | |
NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:self._pathToMultipartBody error:nil]; | |
NSString *contentLength = [NSString stringWithFormat:@"%lld", [[fileAttributes objectForKey:@"NSFileSize"] unsignedLongLongValue]]; | |
if (_completion) | |
_completion(YES, contentType, contentLength, self._pathToMultipartBody, nil); | |
} else { | |
if (_completion) { | |
NSError *error = [NSError errorWithDomain:LBCHTTPPostBodyErrorDomain code:LBCHTTPPostBodyNoSuchStreamFileError userInfo:[NSDictionary dictionaryWithObject:self._pathToMultipartBody forKey:@"NoSuchFile"]]; | |
_completion(NO, nil, nil, nil, error); | |
} | |
} | |
[self release]; | |
} | |
-(void)_prepareHTTPBodyForStreamToPath:(NSURL *)path { | |
// generate unique file to insert shit into | |
if (![path isFileURL]) | |
return; | |
self._pathToMultipartBody = [path path]; | |
self._multipartBodyOutputStream = [NSOutputStream outputStreamToFileAtPath:self._pathToMultipartBody append:YES]; | |
[self._multipartBodyOutputStream open]; | |
// sort keys into normal http post params and files | |
NSMutableArray *sortedKeys = [NSMutableArray arrayWithCapacity:[parameters count]]; | |
NSMutableArray *urlKeys = [NSMutableArray arrayWithCapacity:1]; | |
[parameters enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { | |
if ([[self class] isExistingFileURLForObject:obj]) { | |
[urlKeys addObject:key]; | |
} else { | |
[sortedKeys addObject:[NSDictionary dictionaryWithObjectsAndKeys:key, FILE_STREAM_FORMNAME_KEY, obj, FILE_STREAM_FILEPATH_KEY, nil]]; | |
} | |
}]; | |
// deal with normal HTTP POST params | |
NSMutableData *data = [NSMutableData data]; | |
for (NSString *key in sortedKeys) { | |
[[self class] appendData:data key:key data:[parameters objectForKey:key]]; | |
} | |
[self._multipartBodyOutputStream write:[data bytes] maxLength:[data length]]; | |
// deal with files. | |
[self retain]; | |
if ([urlKeys count] > 0) { | |
self._filesToStream = urlKeys; | |
[self _processFileStream]; | |
} else { | |
[self _completeStreamConstruction]; | |
} | |
} | |
-(void)_processFileStream { | |
if (self._fileStream) { | |
[self._fileStream close]; | |
[self._fileStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; | |
self._fileStream = nil; | |
} | |
if ([self._filesToStream count] > 0) { | |
NSDictionary *fileDict = [self._filesToStream lastObject]; | |
NSData *header = [[self class] octetStreamHeaderForName:[fileDict objectForKey:FILE_STREAM_FORMNAME_KEY] filename:[[fileDict objectForKey:FILE_STREAM_FILEPATH_KEY] lastPathComponent]]; | |
[self._multipartBodyOutputStream write:[header bytes] maxLength:[header length]]; | |
self._fileStream = [[[NSInputStream alloc] initWithFileAtPath:[[fileDict objectForKey:FILE_STREAM_FILEPATH_KEY] path]] autorelease]; | |
self._fileStream.delegate = self; | |
[self._fileStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; | |
NSData *HTTPBoundary = [[NSString stringWithFormat:@"--%@\r\n", [[self class] multipartBoundary]] dataUsingEncoding:NSUTF8StringEncoding]; | |
[self._multipartBodyOutputStream write:[HTTPBoundary bytes] maxLength:[HTTPBoundary length]]; | |
[self._fileStream open]; | |
[self._filesToStream removeLastObject]; | |
} else { | |
// complete and call handler | |
NSData *closeHTTPBoundary = [[NSString stringWithFormat:@"--%@--\r\n", [[self class] multipartBoundary]] dataUsingEncoding:NSUTF8StringEncoding]; | |
[self._multipartBodyOutputStream write:[closeHTTPBoundary bytes] maxLength:[closeHTTPBoundary length]]; | |
[self _completeStreamConstruction]; | |
} | |
} | |
-(void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode { | |
if (aStream == self._fileStream) { | |
uint8_t buf[1024*100]; | |
NSUInteger len = 0; | |
switch(eventCode) { | |
case NSStreamEventOpenCompleted: | |
NSLog(@"Media file opened"); | |
break; | |
case NSStreamEventHasBytesAvailable: | |
len = [self._fileStream read:buf maxLength:1024]; | |
if (len) { | |
[self._multipartBodyOutputStream write:buf maxLength:len]; | |
} else { | |
NSLog(@"Buffer finished; wrote to %@", self._pathToMultipartBody); | |
NSData *footer = [[self class] octetStreamFooter]; | |
[self._multipartBodyOutputStream write:[footer bytes] maxLength:[footer length]]; | |
[self _processFileStream]; | |
} | |
break; | |
case NSStreamEventErrorOccurred: | |
NSLog(@"ERROR piping image to body file %@", [aStream streamError]); | |
if (_completion) | |
_completion(NO, nil, nil, nil, [aStream streamError]); | |
[self release]; | |
break; | |
default: | |
NSLog(@"Unhandled stream event (%ld)", eventCode); | |
break; | |
} | |
} | |
} | |
#pragma mark - String utility functions | |
+(NSString *)escapeString:(NSString *)str withEscapees:(NSString *)escapees { | |
return [(NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)str, NULL, (CFStringRef)escapees, kCFStringEncodingUTF8) autorelease]; | |
} | |
+(NSString *)escapeString:(NSString *)str { | |
//return [[self class] escapeString:str withEscapees:@" ()<>#%{}|\\^~[]`;/?:@=&$"]; | |
return [[self class] escapeString:str withEscapees:@" ()<>#{}|\\^~[]`;$"]; | |
} | |
+(NSString *)hashForData:(NSData *)data { | |
// calculate MD5 of nsdata for filename | |
unsigned char result[CC_MD5_DIGEST_LENGTH]; | |
CC_MD5([data bytes], (uint)[data length], result); | |
NSMutableString *hash = [NSMutableString string]; | |
for (int i = 0; i < 16; i++) | |
[hash appendFormat:@"%02X", result[i]]; | |
return hash; | |
} | |
+(NSString *)urlEncodedStringFromParams:(NSDictionary *)params { | |
NSMutableString *post = [NSMutableString string]; | |
id param = nil; | |
for (NSString *key in params) { | |
if ([post length] > 0) { | |
[post appendString:@"&"]; | |
} | |
param = [params objectForKey:key]; | |
if ([param isKindOfClass:[NSNumber class]]) { | |
param = [param stringValue]; | |
} else { | |
param = [NSString stringWithFormat:@"%@", param]; | |
} | |
[post appendFormat:@"%@=%@",[[self class] escapeString:key], [[self class] escapeString:param]]; | |
} | |
return post; | |
} | |
+(NSString *)multipartBoundary { | |
return HTTP_MULTIPART_BOUNDARY; | |
} | |
+(NSString *)contentTypeForMultipart { | |
return [NSString stringWithFormat:@"multipart/form-data; boundary=%@", [[self class] multipartBoundary]]; | |
} | |
+(NSURL *)fileURLForTemporaryStreamFile { | |
CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault); | |
CFStringRef uuidStr = CFUUIDCreateString(kCFAllocatorDefault, uuid); | |
NSString *extension = @"multipartbody"; | |
NSString *bodyFileName = [(NSString *)uuidStr | |
stringByAppendingPathExtension:extension]; | |
CFRelease(uuidStr); | |
CFRelease(uuid); | |
return [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:bodyFileName]]; | |
} | |
#pragma mark - Generation of URL Request | |
+(void)appendData:(NSMutableData *)data key:(NSString *)key value:(NSString *)value { | |
// write content disposition | |
[data appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n", key] dataUsingEncoding:NSUTF8StringEncoding]]; | |
// write value | |
[data appendData:[[NSString stringWithFormat:@"\r\n%@\r\n", value] dataUsingEncoding:NSUTF8StringEncoding]]; | |
} | |
+(NSData *)octetStreamHeaderForName:(NSString *)name filename:(NSString *)filename { | |
NSMutableData *data = [NSMutableData data]; | |
[data appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", name, filename] dataUsingEncoding:NSUTF8StringEncoding]]; | |
[data appendData:[[NSString stringWithFormat:@"Content-Type: application/octet-stream\r\n"] dataUsingEncoding:NSUTF8StringEncoding]]; | |
[data appendData:[[NSString stringWithFormat:@"Content-Transfer-Encoding: base64\r\n"] dataUsingEncoding:NSUTF8StringEncoding]]; | |
[data appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; | |
return data; | |
} | |
+(NSData *)octetStreamFooter { | |
return [@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]; | |
} | |
+(void)appendData:(NSMutableData *)data key:(NSString *)key data:(NSData *)dataValue { | |
[data appendData:[[self class] octetStreamHeaderForName:key filename:[[self class] hashForData:dataValue]]]; | |
[data appendData:[NSData dataWithData:dataValue]]; | |
[data appendData:[[self class] octetStreamFooter]]; | |
} | |
+(NSInteger)appendOutputStream:(NSOutputStream *)stream key:(NSString *)key value:(NSString *)value { | |
NSMutableData *data = [NSMutableData data]; | |
[[self class] appendData:data key:key value:value]; | |
return [stream write:[data bytes] maxLength:[data length]]; | |
} | |
+(NSInteger)appendOutputStream:(NSOutputStream *)stream key:(NSString *)key data:(NSData *)dataValue { | |
NSMutableData *data = [NSMutableData data]; | |
[[self class] appendData:data key:key data:dataValue]; | |
return [stream write:[data bytes] maxLength:[data length]]; | |
} | |
+(BOOL)isExistingFileURLForObject:(id)obj { | |
if ([obj isKindOfClass:[NSURL class]]) { | |
if (([((NSURL *)obj) filePathURL]) && ([[NSFileManager defaultManager] fileExistsAtPath:[[((NSURL *)obj) filePathURL] path]])) { | |
return YES; | |
} | |
} | |
return NO; | |
} | |
+(BOOL)needMultiPartForParameters:(NSDictionary *)params hasExternalFile:(BOOL *)externalFile { | |
BOOL needMultiPart = NO; | |
id testobj = nil; | |
if (externalFile) | |
*externalFile = NO; | |
for (NSString *key in params) { | |
testobj = [params objectForKey:key]; | |
if ([[self class] isExistingFileURLForObject:testobj]) { | |
needMultiPart = YES; | |
if (externalFile) | |
*externalFile = YES; | |
break; | |
} else if ([testobj isKindOfClass:[NSData class]]) { | |
needMultiPart = YES; | |
break; | |
} | |
} | |
return needMultiPart; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment