From 945e196d1fc54453b7033b1e742458d3e0456969 Mon Sep 17 00:00:00 2001 From: Mattt Thompson Date: Mon, 26 Sep 2011 11:50:13 -0500 Subject: [PATCH] Renaming AFMultipartFormDataProxy to AFMultipartFormData, in order to eliminate any confusion about it relating to a web proxy Removing NSObject protocol from AFMultipartFormData protocol, since that's one of the points of abstracting away the interface Refactoring mutlipart form appending methods to eliminate overlap, and be more useful in general Updating documentation --- AFNetworking/AFHTTPClient.h | 35 +++++++++++++--------- AFNetworking/AFHTTPClient.m | 58 ++++++++++++++----------------------- 2 files changed, 43 insertions(+), 50 deletions(-) diff --git a/AFNetworking/AFHTTPClient.h b/AFNetworking/AFHTTPClient.h index 4a9c358..5788133 100644 --- a/AFNetworking/AFHTTPClient.h +++ b/AFNetworking/AFHTTPClient.h @@ -23,7 +23,7 @@ #import #import "AFHTTPRequestOperation.h" -@protocol AFMultipartFormDataProxy; +@protocol AFMultipartFormData; /** `AFHTTPClient` objects encapsulates the common patterns of communicating with an application, webservice, or API. It encapsulates persistent information, like base URL, authorization credentials, and HTTP headers, and uses them to construct and manage the execution of HTTP request operations. @@ -133,21 +133,21 @@ path:(NSString *)path parameters:(NSDictionary *)parameters; /** - Creates an `NSMutableURLRequest` object with the specified HTTP method and path, and constructs a `multipart/form-data` HTTP body, using the specified parameters and multipart form data block. + Creates an `NSMutableURLRequest` object with the specified HTTP method and path, and constructs a `multipart/form-data` HTTP body, using the specified parameters and multipart form data block. See http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.2 @param method The HTTP method for the request. Must be either `POST`, `PUT`, or `DELETE`. @param path The path to be appended to the HTTP client's base URL and used as the request URL. @param parameters The parameters to be encoded and set in the request HTTP body. - @param block A block that takes a single argument and appends data to the HTTP body. The block argument is an object adopting the `AFMultipartFormDataProxy` protocol. This can be used to upload files, encode HTTP body as JSON or XML, or specify multiple values for the same parameter, as one might for array values. + @param block A block that takes a single argument and appends data to the HTTP body. The block argument is an object adopting the `AFMultipartFormData` protocol. This can be used to upload files, encode HTTP body as JSON or XML, or specify multiple values for the same parameter, as one might for array values. - @see AFMultipartFormDataProxy + @see AFMultipartFormData @return An `NSMutableURLRequest` object */ - (NSMutableURLRequest *)multipartFormRequestWithMethod:(NSString *)method path:(NSString *)path parameters:(NSDictionary *)parameters - constructingBodyWithBlock:(void (^)(id formData))block; + constructingBodyWithBlock:(void (^)(id formData))block; ///-------------------------------- @@ -237,9 +237,9 @@ #pragma mark - /** - The `AFMultipartFormDataProxy` protocol defines the methods supported by the parameter in the block argument of `multipartFormRequestWithMethod:path:parameters:constructingBodyWithBlock:`. + The `AFMultipartFormData` protocol defines the methods supported by the parameter in the block argument of `multipartFormRequestWithMethod:path:parameters:constructingBodyWithBlock:`. */ -@protocol AFMultipartFormDataProxy +@protocol AFMultipartFormData /** Appends HTTP headers, followed by the encoded data and the multipart form boundary. @@ -250,13 +250,23 @@ - (void)appendPartWithHeaders:(NSDictionary *)headers body:(NSData *)body; /** - 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. + Appends the HTTP headers `Content-Disposition: form-data; name=#{name}"`, followed by the encoded data and the multipart form boundary. @param data The data to be encoded and appended to the form 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 mimeType:(NSString *)mimeType name:(NSString *)name; +- (void)appendPartWithFormData:(NSData *)data name:(NSString *)name; + +/** + Appends the HTTP header `Content-Disposition: file; filename=#{generated filename}; name=#{name}"` and `Content-Type: #{mimeType}`, followed by the encoded file data and the multipart form boundary. + + @param data The data to be encoded and appended to the form 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/. This parameter must not be `nil`. + @param name The name to be associated with the specified data. This parameter must not be `nil`. + + @discussion The filename associated with this data in the form will be automatically generated using the parameter name specified and a unique timestamp-based hash. + */ +- (void)appendPartWithFileData:(NSData *)data mimeType:(NSString *)mimeType name:(NSString *)name; /** Appends the HTTP header `Content-Disposition: file; filename=#{filename}"` and `Content-Type: #{mimeType}`, followed by the encoded file data and the multipart form boundary. @@ -264,10 +274,9 @@ @param fileURL The URL for the local file to have its contents appended to the form data. This parameter must not be `nil`. @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`. + @param error If an error occurs, upon return contains an `NSError` object that describes the problem. */ -- (void)appendPartWithFile:(NSURL *)fileURL mimeType:(NSString *)mimeType fileName:(NSString *)fileName; - -- (void)appendPartWithFileData:(NSData *)data mimeType:(NSString *)mimeType name:(NSString *)name; +- (void)appendPartWithFile:(NSURL *)fileURL mimeType:(NSString *)mimeType fileName:(NSString *)fileName error:(NSError **)error; /** Appends encoded data to the form data. diff --git a/AFNetworking/AFHTTPClient.m b/AFNetworking/AFHTTPClient.m index 0cc0eeb..dccd40a 100644 --- a/AFNetworking/AFHTTPClient.m +++ b/AFNetworking/AFHTTPClient.m @@ -34,7 +34,7 @@ static NSString * AFMultipartFormFinalBoundary() { return [NSString stringWithFormat:@"%@--%@--", kAFMultipartFormLineDelimiter, kAFMultipartFormBoundary]; } -@interface AFMultipartFormDataProxy : NSObject { +@interface AFMultipartFormData : NSObject { @private NSStringEncoding _stringEncoding; NSMutableData *_mutableData; @@ -192,7 +192,7 @@ static NSString * AFURLEncodedStringFromStringWithEncoding(NSString *string, NSS - (NSMutableURLRequest *)multipartFormRequestWithMethod:(NSString *)method path:(NSString *)path parameters:(NSDictionary *)parameters - constructingBodyWithBlock:(void (^)(id formData))block + constructingBodyWithBlock:(void (^)(id formData))block { if (!([method isEqualToString:@"POST"] || [method isEqualToString:@"PUT"] || [method isEqualToString:@"DELETE"])) { [NSException raise:@"Invalid HTTP Method" format:@"%@ is not supported for multipart form requests; must be either POST, PUT, or DELETE", method]; @@ -200,7 +200,7 @@ static NSString * AFURLEncodedStringFromStringWithEncoding(NSString *string, NSS } NSMutableURLRequest *request = [self requestWithMethod:method path:path parameters:nil]; - __block AFMultipartFormDataProxy *formData = [[AFMultipartFormDataProxy alloc] initWithStringEncoding:self.stringEncoding]; + __block AFMultipartFormData *formData = [[AFMultipartFormData alloc] initWithStringEncoding:self.stringEncoding]; id key = nil; NSEnumerator *enumerator = [parameters keyEnumerator]; @@ -214,7 +214,7 @@ static NSString * AFURLEncodedStringFromStringWithEncoding(NSString *string, NSS data = [[value description] dataUsingEncoding:self.stringEncoding]; } - [formData appendPartWithHeaders:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"form-data; name=\"%@\"", [key description]] forKey:@"Content-Disposition"] body:data]; + [formData appendPartWithFormData:data name:[key description]]; } if (block) { @@ -272,15 +272,12 @@ static NSString * AFURLEncodedStringFromStringWithEncoding(NSString *string, NSS #pragma mark - -// multipart/form-data; see http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.2 -@interface AFMultipartFormDataProxy () +@interface AFMultipartFormData () @property (readwrite, nonatomic, assign) NSStringEncoding stringEncoding; @property (readwrite, nonatomic, retain) NSMutableData *mutableData; - -- (void)appendBlankLine; @end -@implementation AFMultipartFormDataProxy +@implementation AFMultipartFormData @synthesize stringEncoding = _stringEncoding; @synthesize mutableData = _mutableData; @@ -307,48 +304,28 @@ static NSString * AFURLEncodedStringFromStringWithEncoding(NSString *string, NSS return finalizedData; } -#pragma mark - AFMultipartFormDataProxy +#pragma mark - AFMultipartFormData - (void)appendPartWithHeaders:(NSDictionary *)headers body:(NSData *)body { - [self appendString:AFMultipartFormEncapsulationBoundary()]; for (NSString *field in [headers allKeys]) { [self appendString:[NSString stringWithFormat:@"%@: %@%@", field, [headers valueForKey:field], kAFMultipartFormLineDelimiter]]; } - [self appendBlankLine]; + [self appendString:kAFMultipartFormLineDelimiter]; [self appendData:body]; } -- (void)appendPartWithFormData:(NSData *)data mimeType:(NSString *)mimeType name:(NSString *)name { +- (void)appendPartWithFormData:(NSData *)data name:(NSString *)name { NSMutableDictionary *mutableHeaders = [NSMutableDictionary dictionary]; [mutableHeaders setValue:[NSString stringWithFormat:@"form-data; name=\"%@\"", name] forKey:@"Content-Disposition"]; - if (mimeType) { - [mutableHeaders setValue:mimeType forKey:@"Content-Type"]; - } - - [self appendPartWithHeaders:mutableHeaders body:data]; -} - -- (void)appendPartWithFile:(NSURL *)fileURL mimeType:(NSString *)mimeType fileName:(NSString *)fileName { - if (![fileURL isFileURL]) { - [NSException raise:@"Invalid fileURL value" format:@"%@ must be a valid file URL", fileURL]; - 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]]; [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]]; + NSString *fileName = [[NSString stringWithFormat:@"%@-%d", name, [[NSDate date] hash]] stringByAppendingPathExtension:[mimeType lastPathComponent]]; NSMutableDictionary *mutableHeaders = [NSMutableDictionary dictionary]; [mutableHeaders setValue:[NSString stringWithFormat:@"file; name=\"%@\"; filename=\"%@\"", name, fileName] forKey:@"Content-Disposition"]; @@ -357,6 +334,17 @@ static NSString * AFURLEncodedStringFromStringWithEncoding(NSString *string, NSS [self appendPartWithHeaders:mutableHeaders body:data]; } +- (void)appendPartWithFile:(NSURL *)fileURL mimeType:(NSString *)mimeType fileName:(NSString *)fileName error:(NSError **)error { + NSData *data = [NSData dataWithContentsOfFile:[fileURL absoluteString] options:0 error:error]; + if (data) { + NSMutableDictionary *mutableHeaders = [NSMutableDictionary dictionary]; + [mutableHeaders setValue:[NSString stringWithFormat:@"file; filename=\"%@\"", fileName] forKey:@"Content-Disposition"]; + [mutableHeaders setValue:mimeType forKey:@"Content-Type"]; + + [self appendPartWithHeaders:mutableHeaders body:data]; + } +} + - (void)appendData:(NSData *)data { [self.mutableData appendData:data]; } @@ -365,8 +353,4 @@ static NSString * AFURLEncodedStringFromStringWithEncoding(NSString *string, NSS [self appendData:[string dataUsingEncoding:self.stringEncoding]]; } -- (void)appendBlankLine { - [self appendString:kAFMultipartFormLineDelimiter]; -} - @end