commit
b985ed9015
2 changed files with 69 additions and 43 deletions
|
|
@ -37,7 +37,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The url used as the base for paths specified in methods such as `getPath:parameters:success:failure`
|
The url used as the base for paths specified in methods such as `getPath:parameteres:success:failure`
|
||||||
*/
|
*/
|
||||||
@property (readonly, nonatomic, retain) NSURL *baseURL;
|
@property (readonly, nonatomic, retain) NSURL *baseURL;
|
||||||
|
|
||||||
|
|
@ -49,7 +49,7 @@
|
||||||
/**
|
/**
|
||||||
The operation queue which manages operations enqueued by the HTTP client.
|
The operation queue which manages operations enqueued by the HTTP client.
|
||||||
*/
|
*/
|
||||||
@property (readonly, nonatomic, retain) NSOperationQueue *operationQueue;
|
@property (readonly, nonatomic, retain) NSOperationQueue *operationQueue;;
|
||||||
|
|
||||||
///---------------------------------------------
|
///---------------------------------------------
|
||||||
/// @name Creating and Initializing HTTP Clients
|
/// @name Creating and Initializing HTTP Clients
|
||||||
|
|
@ -250,20 +250,24 @@
|
||||||
- (void)appendPartWithHeaders:(NSDictionary *)headers body:(NSData *)body;
|
- (void)appendPartWithHeaders:(NSDictionary *)headers body:(NSData *)body;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Appends the HTTP header `Content-Disposition: form-data; name=#{name}"`, followed by the encoded data and the multipart form boundary.
|
Appends the HTTP headers `Content-Disposition: form-data; name=#{name}"` and, if mimeType is specified, `Content-Type: #{mimeType}`, followed by the encoded data and the multipart form boundary.
|
||||||
|
|
||||||
@param data The data to be encoded and appended to the form data.
|
@param data The data to be encoded and appended to the form data.
|
||||||
@param name The name to be associated with the specified data.
|
@param mimeType The MIME type of the specified data. (For example, the MIME type for a JPEG image is image/jpeg.) For a list of valid MIME types, see http://www.iana.org/assignments/media-types/. If `nil`, the `Content-Type` header will be omitted.
|
||||||
|
@param name The name to be associated with the specified data. This parameter must not be `nil`.
|
||||||
*/
|
*/
|
||||||
- (void)appendPartWithFormData:(NSData *)data name:(NSString *)name;
|
- (void)appendPartWithFormData:(NSData *)data mimeType:(NSString *)mimeType name:(NSString *)name;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Appends the HTTP header `Content-Disposition: file; filename=#{filename}"`, followed by the encoded file data and the multipart form boundary.
|
Appends the HTTP header `Content-Disposition: file; filename=#{filename}"` and `Content-Type: #{mimeType}`, followed by the encoded file data and the multipart form boundary.
|
||||||
|
|
||||||
@param fileURL The URL for the local file to have its contents appended to the form data.
|
@param fileURL The URL for the local file to have its contents appended to the form data. This parameter must not be `nil`.
|
||||||
@param fileNameOrNil The filename to be associated with the file contents. If `nil`, the last path component followed by its file extension will be used instead.
|
@param mimeType The MIME type of the specified data. (For example, the MIME type for a JPEG image is image/jpeg.) For a list of valid MIME types, see http://www.iana.org/assignments/media-types/. This parameter must not be `nil`.
|
||||||
|
@param fileName The filename to be associated with the file contents. This parameter must not be `nil`.
|
||||||
*/
|
*/
|
||||||
- (void)appendPartWithFile:(NSURL *)fileURL fileName:(NSString *)fileNameOrNil;
|
- (void)appendPartWithFile:(NSURL *)fileURL mimeType:(NSString *)mimeType fileName:(NSString *)fileName;
|
||||||
|
|
||||||
|
- (void)appendPartWithFileData:(NSData *)data mimeType:(NSString *)mimeType name:(NSString *)name;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Appends encoded data to the form data.
|
Appends encoded data to the form data.
|
||||||
|
|
|
||||||
|
|
@ -27,22 +27,22 @@ static NSString * const kAFMultipartFormLineDelimiter = @"\r\n"; // CRLF
|
||||||
static NSString * const kAFMultipartFormBoundary = @"Boundary+0xAbCdEfGbOuNdArY";
|
static NSString * const kAFMultipartFormBoundary = @"Boundary+0xAbCdEfGbOuNdArY";
|
||||||
|
|
||||||
static NSString * AFMultipartFormEncapsulationBoundary() {
|
static NSString * AFMultipartFormEncapsulationBoundary() {
|
||||||
return [NSString stringWithFormat:@"--%@", kAFMultipartFormBoundary];
|
return [NSString stringWithFormat:@"%@--%@%@", kAFMultipartFormLineDelimiter, kAFMultipartFormBoundary, kAFMultipartFormLineDelimiter];
|
||||||
}
|
}
|
||||||
|
|
||||||
static NSString * AFMultipartFormFinalBoundary() {
|
static NSString * AFMultipartFormFinalBoundary() {
|
||||||
return [NSString stringWithFormat:@"--%@--", kAFMultipartFormBoundary];
|
return [NSString stringWithFormat:@"%@--%@--", kAFMultipartFormLineDelimiter, kAFMultipartFormBoundary];
|
||||||
}
|
}
|
||||||
|
|
||||||
@interface AFMutableMultipartFormData : NSObject <AFMultipartFormDataProxy> {
|
@interface AFMultipartFormDataProxy : NSObject <AFMultipartFormDataProxy> {
|
||||||
@private
|
@private
|
||||||
NSStringEncoding _stringEncoding;
|
NSStringEncoding _stringEncoding;
|
||||||
NSMutableArray *_mutableLines;
|
NSMutableData *_mutableData;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithStringEncoding:(NSStringEncoding)encoding;
|
@property (readonly) NSData *data;
|
||||||
|
|
||||||
- (NSData *)data;
|
- (id)initWithStringEncoding:(NSStringEncoding)encoding;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
@ -200,17 +200,21 @@ static NSString * AFURLEncodedStringFromStringWithEncoding(NSString *string, NSS
|
||||||
}
|
}
|
||||||
|
|
||||||
NSMutableURLRequest *request = [self requestWithMethod:method path:path parameters:nil];
|
NSMutableURLRequest *request = [self requestWithMethod:method path:path parameters:nil];
|
||||||
__block AFMutableMultipartFormData *formData = [[AFMutableMultipartFormData alloc] initWithStringEncoding:self.stringEncoding];
|
__block AFMultipartFormDataProxy *formData = [[AFMultipartFormDataProxy alloc] initWithStringEncoding:self.stringEncoding];
|
||||||
|
|
||||||
id key = nil;
|
id key = nil;
|
||||||
NSEnumerator *enumerator = [parameters keyEnumerator];
|
NSEnumerator *enumerator = [parameters keyEnumerator];
|
||||||
while ((key = [enumerator nextObject])) {
|
while ((key = [enumerator nextObject])) {
|
||||||
id value = [parameters valueForKey:key];
|
id value = [parameters valueForKey:key];
|
||||||
if (![value isKindOfClass:[NSData class]]) {
|
NSData *data = nil;
|
||||||
value = [value description];
|
|
||||||
|
if ([value isKindOfClass:[NSData class]]) {
|
||||||
|
data = value;
|
||||||
|
} else {
|
||||||
|
data = [[value description] dataUsingEncoding:self.stringEncoding];
|
||||||
}
|
}
|
||||||
|
|
||||||
[formData appendPartWithFormData:[value dataUsingEncoding:self.stringEncoding] name:[key description]];
|
[formData appendPartWithHeaders:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"form-data; name=\"%@\"", [key description]] forKey:@"Content-Disposition"] body:data];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (block) {
|
if (block) {
|
||||||
|
|
@ -269,16 +273,16 @@ static NSString * AFURLEncodedStringFromStringWithEncoding(NSString *string, NSS
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
|
|
||||||
// multipart/form-data; see http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.2
|
// multipart/form-data; see http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.2
|
||||||
@interface AFMutableMultipartFormData ()
|
@interface AFMultipartFormDataProxy ()
|
||||||
@property (readwrite, nonatomic, assign) NSStringEncoding stringEncoding;
|
@property (readwrite, nonatomic, assign) NSStringEncoding stringEncoding;
|
||||||
@property (readwrite, nonatomic, retain) NSMutableArray *mutableLines;
|
@property (readwrite, nonatomic, retain) NSMutableData *mutableData;
|
||||||
|
|
||||||
- (void)appendBlankLine;
|
- (void)appendBlankLine;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation AFMutableMultipartFormData
|
@implementation AFMultipartFormDataProxy
|
||||||
@synthesize stringEncoding = _stringEncoding;
|
@synthesize stringEncoding = _stringEncoding;
|
||||||
@synthesize mutableLines = _mutableLines;
|
@synthesize mutableData = _mutableData;
|
||||||
|
|
||||||
- (id)initWithStringEncoding:(NSStringEncoding)encoding {
|
- (id)initWithStringEncoding:(NSStringEncoding)encoding {
|
||||||
self = [super init];
|
self = [super init];
|
||||||
|
|
@ -287,64 +291,82 @@ static NSString * AFURLEncodedStringFromStringWithEncoding(NSString *string, NSS
|
||||||
}
|
}
|
||||||
|
|
||||||
self.stringEncoding = encoding;
|
self.stringEncoding = encoding;
|
||||||
self.mutableLines = [NSMutableArray array];
|
self.mutableData = [NSMutableData dataWithLength:0];
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)dealloc {
|
- (void)dealloc {
|
||||||
[_mutableLines release];
|
[_mutableData release];
|
||||||
[super dealloc];
|
[super dealloc];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSData *)data {
|
- (NSData *)data {
|
||||||
if ([self.mutableLines count] == 0) {
|
NSMutableData *finalizedData = [NSMutableData dataWithData:self.mutableData];
|
||||||
return nil;
|
[finalizedData appendData:[AFMultipartFormFinalBoundary() dataUsingEncoding:self.stringEncoding]];
|
||||||
}
|
return finalizedData;
|
||||||
|
|
||||||
return [[[[self.mutableLines componentsJoinedByString:kAFMultipartFormLineDelimiter] stringByAppendingString:kAFMultipartFormLineDelimiter] stringByAppendingString:AFMultipartFormFinalBoundary()] dataUsingEncoding:self.stringEncoding];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - AFMultipartFormDataProxy
|
#pragma mark - AFMultipartFormDataProxy
|
||||||
|
|
||||||
- (void)appendPartWithHeaders:(NSDictionary *)headers body:(NSData *)body {
|
- (void)appendPartWithHeaders:(NSDictionary *)headers body:(NSData *)body {
|
||||||
if ([self.mutableLines count] > 0) {
|
|
||||||
[self appendString:AFMultipartFormEncapsulationBoundary()];
|
[self appendString:AFMultipartFormEncapsulationBoundary()];
|
||||||
}
|
|
||||||
|
|
||||||
for (NSString *field in [headers allKeys]) {
|
for (NSString *field in [headers allKeys]) {
|
||||||
[self appendString:[NSString stringWithFormat:@"%@: %@", field, [headers valueForKey:field]]];
|
[self appendString:[NSString stringWithFormat:@"%@: %@%@", field, [headers valueForKey:field], kAFMultipartFormLineDelimiter]];
|
||||||
}
|
}
|
||||||
|
|
||||||
[self appendBlankLine];
|
[self appendBlankLine];
|
||||||
[self appendData:body];
|
[self appendData:body];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)appendPartWithFormData:(NSData *)data name:(NSString *)name {
|
- (void)appendPartWithFormData:(NSData *)data mimeType:(NSString *)mimeType name:(NSString *)name {
|
||||||
[self appendPartWithHeaders:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"form-data; name=\"%@\"", name] forKey:@"Content-Disposition"] body:data];
|
NSMutableDictionary *mutableHeaders = [NSMutableDictionary dictionary];
|
||||||
|
[mutableHeaders setValue:[NSString stringWithFormat:@"form-data; name=\"%@\"", name] forKey:@"Content-Disposition"];
|
||||||
|
if (mimeType) {
|
||||||
|
[mutableHeaders setValue:mimeType forKey:@"Content-Type"];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)appendPartWithFile:(NSURL *)fileURL fileName:(NSString *)fileNameOrNil {
|
[self appendPartWithHeaders:mutableHeaders body:data];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)appendPartWithFile:(NSURL *)fileURL mimeType:(NSString *)mimeType fileName:(NSString *)fileName {
|
||||||
if (![fileURL isFileURL]) {
|
if (![fileURL isFileURL]) {
|
||||||
[NSException raise:@"Invalid fileURL value" format:@"%@ must be a valid file URL", fileURL];
|
[NSException raise:@"Invalid fileURL value" format:@"%@ must be a valid file URL", fileURL];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NSMutableDictionary *mutableHeaders = [NSMutableDictionary dictionary];
|
||||||
|
[mutableHeaders setValue:[NSString stringWithFormat:@"file; filename=\"%@\"", fileName] forKey:@"Content-Disposition"];
|
||||||
|
[mutableHeaders setValue:mimeType forKey:@"Content-Type"];
|
||||||
|
|
||||||
NSData *data = [NSData dataWithContentsOfFile:[fileURL absoluteString]];
|
NSData *data = [NSData dataWithContentsOfFile:[fileURL absoluteString]];
|
||||||
NSString *fileName = fileNameOrNil ? fileNameOrNil : [[fileURL lastPathComponent] stringByAppendingPathExtension:[fileURL pathExtension]];
|
|
||||||
[self appendPartWithHeaders:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"file; filename=\"%@\"", fileName] forKey:@"Content-Disposition"] body:data];
|
[self appendPartWithHeaders:mutableHeaders body:data];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)appendPartWithFileData:(NSData *)data mimeType:(NSString *)mimeType name:(NSString *)name {
|
||||||
|
|
||||||
|
NSString *fileName = [[NSString stringWithFormat:@"%d", [[NSDate date] hash]] stringByAppendingPathExtension:[mimeType lastPathComponent]];
|
||||||
|
|
||||||
|
NSMutableDictionary *mutableHeaders = [NSMutableDictionary dictionary];
|
||||||
|
[mutableHeaders setValue:[NSString stringWithFormat:@"file; name=\"%@\"; filename=\"%@\"", name, fileName] forKey:@"Content-Disposition"];
|
||||||
|
[mutableHeaders setValue:mimeType forKey:@"Content-Type"];
|
||||||
|
|
||||||
|
[self appendPartWithHeaders:mutableHeaders body:data];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)appendData:(NSData *)data {
|
- (void)appendData:(NSData *)data {
|
||||||
[self appendString:[[[NSString alloc] initWithData:data encoding:self.stringEncoding] autorelease]];
|
[self.mutableData appendData:data];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)appendString:(NSString *)string {
|
- (void)appendString:(NSString *)string {
|
||||||
[self.mutableLines addObject:string];
|
[self appendData:[string dataUsingEncoding:self.stringEncoding]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)appendBlankLine {
|
- (void)appendBlankLine {
|
||||||
[self appendString:@""];
|
[self appendString:kAFMultipartFormLineDelimiter];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue