| // Copyright (c) 2006, Google Inc. |
| // All rights reserved. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are |
| // met: |
| // |
| // * Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above |
| // copyright notice, this list of conditions and the following disclaimer |
| // in the documentation and/or other materials provided with the |
| // distribution. |
| // * Neither the name of Google Inc. nor the names of its |
| // contributors may be used to endorse or promote products derived from |
| // this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| #import "HTTPMultipartUpload.h" |
| |
| #import "GTMDefines.h" |
| #import "encoding_util.h" |
| |
| @interface HTTPMultipartUpload (PrivateMethods) |
| - (NSString*)multipartBoundary; |
| // Each of the following methods will append the starting multipart boundary, |
| // but not the ending one. |
| - (NSData*)formDataForKey:(NSString*)key value:(NSString*)value; |
| - (NSData*)formDataForFileContents:(NSData*)contents name:(NSString*)name; |
| - (NSData*)formDataForFile:(NSString*)file name:(NSString*)name; |
| @end |
| |
| @implementation HTTPMultipartUpload |
| //============================================================================= |
| #pragma mark - |
| #pragma mark || Private || |
| //============================================================================= |
| - (NSString*)multipartBoundary { |
| // The boundary has 27 '-' characters followed by 16 hex digits |
| return [NSString |
| stringWithFormat:@"---------------------------%08X%08X", rand(), rand()]; |
| } |
| |
| //============================================================================= |
| - (NSData*)formDataForKey:(NSString*)key value:(NSString*)value { |
| NSMutableData* data = [NSMutableData data]; |
| [self appendBoundaryData:data]; |
| |
| NSString* escaped = PercentEncodeNSString(key); |
| NSString* fmt = @"Content-Disposition: form-data; name=\"%@\"\r\n\r\n%@\r\n"; |
| NSString *form = [NSString stringWithFormat:fmt, escaped, value]; |
| |
| [data appendData:[form dataUsingEncoding:NSUTF8StringEncoding]]; |
| return data; |
| } |
| |
| //============================================================================= |
| - (void)appendBoundaryData:(NSMutableData*)data { |
| NSString* fmt = @"--%@\r\n"; |
| NSString* pre = [NSString stringWithFormat:fmt, boundary_]; |
| |
| [data appendData:[pre dataUsingEncoding:NSUTF8StringEncoding]]; |
| } |
| |
| //============================================================================= |
| #pragma mark - |
| #pragma mark || Public || |
| //============================================================================= |
| - (id)initWithURL:(NSURL*)url { |
| if ((self = [super initWithURL:url])) { |
| boundary_ = [[self multipartBoundary] retain]; |
| files_ = [[NSMutableDictionary alloc] init]; |
| } |
| |
| return self; |
| } |
| |
| //============================================================================= |
| - (void)dealloc { |
| [parameters_ release]; |
| [files_ release]; |
| [boundary_ release]; |
| |
| [super dealloc]; |
| } |
| |
| //============================================================================= |
| - (void)setParameters:(NSDictionary*)parameters { |
| if (parameters != parameters_) { |
| [parameters_ release]; |
| parameters_ = [parameters copy]; |
| } |
| } |
| |
| //============================================================================= |
| - (NSDictionary*)parameters { |
| return parameters_; |
| } |
| |
| //============================================================================= |
| - (void)addFileAtPath:(NSString*)path name:(NSString*)name { |
| [files_ setObject:path forKey:name]; |
| } |
| |
| //============================================================================= |
| - (void)addFileContents:(NSData*)data name:(NSString*)name { |
| [files_ setObject:data forKey:name]; |
| } |
| |
| //============================================================================= |
| - (NSDictionary*)files { |
| return files_; |
| } |
| |
| //============================================================================= |
| - (NSString*)HTTPMethod { |
| return @"POST"; |
| } |
| |
| //============================================================================= |
| - (NSString*)contentType { |
| return [NSString |
| stringWithFormat:@"multipart/form-data; boundary=%@", boundary_]; |
| } |
| |
| //============================================================================= |
| - (NSData*)bodyData { |
| NSMutableData* postBody = [NSMutableData data]; |
| |
| // Add any parameters to the message |
| NSArray* parameterKeys = [parameters_ allKeys]; |
| NSString* key; |
| |
| NSInteger count = [parameterKeys count]; |
| for (NSInteger i = 0; i < count; ++i) { |
| key = [parameterKeys objectAtIndex:i]; |
| [postBody appendData:[self formDataForKey:key |
| value:[parameters_ objectForKey:key]]]; |
| } |
| |
| // Add any files to the message |
| NSArray* fileNames = [files_ allKeys]; |
| for (NSString* name in fileNames) { |
| // First append boundary |
| [self appendBoundaryData:postBody]; |
| // Then the formdata |
| id fileOrData = [files_ objectForKey:name]; |
| [HTTPRequest appendFileToBodyData:postBody |
| withName:name |
| withFileOrData:fileOrData]; |
| } |
| |
| NSString* epilogue = [NSString stringWithFormat:@"\r\n--%@--\r\n", boundary_]; |
| [postBody appendData:[epilogue dataUsingEncoding:NSUTF8StringEncoding]]; |
| |
| return postBody; |
| } |
| |
| @end |