1*9712c20fSFrederick Mayle// Copyright 2006 Google LLC 2*9712c20fSFrederick Mayle// 3*9712c20fSFrederick Mayle// Redistribution and use in source and binary forms, with or without 4*9712c20fSFrederick Mayle// modification, are permitted provided that the following conditions are 5*9712c20fSFrederick Mayle// met: 6*9712c20fSFrederick Mayle// 7*9712c20fSFrederick Mayle// * Redistributions of source code must retain the above copyright 8*9712c20fSFrederick Mayle// notice, this list of conditions and the following disclaimer. 9*9712c20fSFrederick Mayle// * Redistributions in binary form must reproduce the above 10*9712c20fSFrederick Mayle// copyright notice, this list of conditions and the following disclaimer 11*9712c20fSFrederick Mayle// in the documentation and/or other materials provided with the 12*9712c20fSFrederick Mayle// distribution. 13*9712c20fSFrederick Mayle// * Neither the name of Google LLC nor the names of its 14*9712c20fSFrederick Mayle// contributors may be used to endorse or promote products derived from 15*9712c20fSFrederick Mayle// this software without specific prior written permission. 16*9712c20fSFrederick Mayle// 17*9712c20fSFrederick Mayle// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18*9712c20fSFrederick Mayle// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19*9712c20fSFrederick Mayle// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20*9712c20fSFrederick Mayle// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21*9712c20fSFrederick Mayle// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22*9712c20fSFrederick Mayle// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23*9712c20fSFrederick Mayle// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24*9712c20fSFrederick Mayle// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25*9712c20fSFrederick Mayle// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26*9712c20fSFrederick Mayle// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27*9712c20fSFrederick Mayle// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28*9712c20fSFrederick Mayle 29*9712c20fSFrederick Mayle#import "HTTPMultipartUpload.h" 30*9712c20fSFrederick Mayle 31*9712c20fSFrederick Mayle#import "GTMDefines.h" 32*9712c20fSFrederick Mayle#import "encoding_util.h" 33*9712c20fSFrederick Mayle 34*9712c20fSFrederick Mayle@interface HTTPMultipartUpload (PrivateMethods) 35*9712c20fSFrederick Mayle- (NSString*)multipartBoundary; 36*9712c20fSFrederick Mayle// Each of the following methods will append the starting multipart boundary, 37*9712c20fSFrederick Mayle// but not the ending one. 38*9712c20fSFrederick Mayle- (NSData*)formDataForKey:(NSString*)key value:(NSString*)value; 39*9712c20fSFrederick Mayle- (NSData*)formDataForFileContents:(NSData*)contents name:(NSString*)name; 40*9712c20fSFrederick Mayle- (NSData*)formDataForFile:(NSString*)file name:(NSString*)name; 41*9712c20fSFrederick Mayle@end 42*9712c20fSFrederick Mayle 43*9712c20fSFrederick Mayle@implementation HTTPMultipartUpload 44*9712c20fSFrederick Mayle//============================================================================= 45*9712c20fSFrederick Mayle#pragma mark - 46*9712c20fSFrederick Mayle#pragma mark || Private || 47*9712c20fSFrederick Mayle//============================================================================= 48*9712c20fSFrederick Mayle- (NSString*)multipartBoundary { 49*9712c20fSFrederick Mayle // The boundary has 27 '-' characters followed by 16 hex digits 50*9712c20fSFrederick Mayle return [NSString 51*9712c20fSFrederick Mayle stringWithFormat:@"---------------------------%08X%08X", rand(), rand()]; 52*9712c20fSFrederick Mayle} 53*9712c20fSFrederick Mayle 54*9712c20fSFrederick Mayle//============================================================================= 55*9712c20fSFrederick Mayle- (NSData*)formDataForKey:(NSString*)key value:(NSString*)value { 56*9712c20fSFrederick Mayle NSMutableData* data = [NSMutableData data]; 57*9712c20fSFrederick Mayle [self appendBoundaryData:data]; 58*9712c20fSFrederick Mayle 59*9712c20fSFrederick Mayle NSString* escaped = PercentEncodeNSString(key); 60*9712c20fSFrederick Mayle NSString* fmt = @"Content-Disposition: form-data; name=\"%@\"\r\n\r\n%@\r\n"; 61*9712c20fSFrederick Mayle NSString *form = [NSString stringWithFormat:fmt, escaped, value]; 62*9712c20fSFrederick Mayle 63*9712c20fSFrederick Mayle [data appendData:[form dataUsingEncoding:NSUTF8StringEncoding]]; 64*9712c20fSFrederick Mayle return data; 65*9712c20fSFrederick Mayle} 66*9712c20fSFrederick Mayle 67*9712c20fSFrederick Mayle//============================================================================= 68*9712c20fSFrederick Mayle- (void)appendBoundaryData:(NSMutableData*)data { 69*9712c20fSFrederick Mayle NSString* fmt = @"--%@\r\n"; 70*9712c20fSFrederick Mayle NSString* pre = [NSString stringWithFormat:fmt, boundary_]; 71*9712c20fSFrederick Mayle 72*9712c20fSFrederick Mayle [data appendData:[pre dataUsingEncoding:NSUTF8StringEncoding]]; 73*9712c20fSFrederick Mayle} 74*9712c20fSFrederick Mayle 75*9712c20fSFrederick Mayle//============================================================================= 76*9712c20fSFrederick Mayle#pragma mark - 77*9712c20fSFrederick Mayle#pragma mark || Public || 78*9712c20fSFrederick Mayle//============================================================================= 79*9712c20fSFrederick Mayle- (id)initWithURL:(NSURL*)url { 80*9712c20fSFrederick Mayle if ((self = [super initWithURL:url])) { 81*9712c20fSFrederick Mayle boundary_ = [[self multipartBoundary] retain]; 82*9712c20fSFrederick Mayle files_ = [[NSMutableDictionary alloc] init]; 83*9712c20fSFrederick Mayle } 84*9712c20fSFrederick Mayle 85*9712c20fSFrederick Mayle return self; 86*9712c20fSFrederick Mayle} 87*9712c20fSFrederick Mayle 88*9712c20fSFrederick Mayle//============================================================================= 89*9712c20fSFrederick Mayle- (void)dealloc { 90*9712c20fSFrederick Mayle [parameters_ release]; 91*9712c20fSFrederick Mayle [files_ release]; 92*9712c20fSFrederick Mayle [boundary_ release]; 93*9712c20fSFrederick Mayle 94*9712c20fSFrederick Mayle [super dealloc]; 95*9712c20fSFrederick Mayle} 96*9712c20fSFrederick Mayle 97*9712c20fSFrederick Mayle//============================================================================= 98*9712c20fSFrederick Mayle- (void)setParameters:(NSDictionary*)parameters { 99*9712c20fSFrederick Mayle if (parameters != parameters_) { 100*9712c20fSFrederick Mayle [parameters_ release]; 101*9712c20fSFrederick Mayle parameters_ = [parameters copy]; 102*9712c20fSFrederick Mayle } 103*9712c20fSFrederick Mayle} 104*9712c20fSFrederick Mayle 105*9712c20fSFrederick Mayle//============================================================================= 106*9712c20fSFrederick Mayle- (NSDictionary*)parameters { 107*9712c20fSFrederick Mayle return parameters_; 108*9712c20fSFrederick Mayle} 109*9712c20fSFrederick Mayle 110*9712c20fSFrederick Mayle//============================================================================= 111*9712c20fSFrederick Mayle- (void)addFileAtPath:(NSString*)path name:(NSString*)name { 112*9712c20fSFrederick Mayle [files_ setObject:path forKey:name]; 113*9712c20fSFrederick Mayle} 114*9712c20fSFrederick Mayle 115*9712c20fSFrederick Mayle//============================================================================= 116*9712c20fSFrederick Mayle- (void)addFileContents:(NSData*)data name:(NSString*)name { 117*9712c20fSFrederick Mayle [files_ setObject:data forKey:name]; 118*9712c20fSFrederick Mayle} 119*9712c20fSFrederick Mayle 120*9712c20fSFrederick Mayle//============================================================================= 121*9712c20fSFrederick Mayle- (NSDictionary*)files { 122*9712c20fSFrederick Mayle return files_; 123*9712c20fSFrederick Mayle} 124*9712c20fSFrederick Mayle 125*9712c20fSFrederick Mayle//============================================================================= 126*9712c20fSFrederick Mayle- (NSString*)HTTPMethod { 127*9712c20fSFrederick Mayle return @"POST"; 128*9712c20fSFrederick Mayle} 129*9712c20fSFrederick Mayle 130*9712c20fSFrederick Mayle//============================================================================= 131*9712c20fSFrederick Mayle- (NSString*)contentType { 132*9712c20fSFrederick Mayle return [NSString 133*9712c20fSFrederick Mayle stringWithFormat:@"multipart/form-data; boundary=%@", boundary_]; 134*9712c20fSFrederick Mayle} 135*9712c20fSFrederick Mayle 136*9712c20fSFrederick Mayle//============================================================================= 137*9712c20fSFrederick Mayle- (NSData*)bodyData { 138*9712c20fSFrederick Mayle NSMutableData* postBody = [NSMutableData data]; 139*9712c20fSFrederick Mayle 140*9712c20fSFrederick Mayle // Add any parameters to the message 141*9712c20fSFrederick Mayle NSArray* parameterKeys = [parameters_ allKeys]; 142*9712c20fSFrederick Mayle NSString* key; 143*9712c20fSFrederick Mayle 144*9712c20fSFrederick Mayle NSInteger count = [parameterKeys count]; 145*9712c20fSFrederick Mayle for (NSInteger i = 0; i < count; ++i) { 146*9712c20fSFrederick Mayle key = [parameterKeys objectAtIndex:i]; 147*9712c20fSFrederick Mayle [postBody appendData:[self formDataForKey:key 148*9712c20fSFrederick Mayle value:[parameters_ objectForKey:key]]]; 149*9712c20fSFrederick Mayle } 150*9712c20fSFrederick Mayle 151*9712c20fSFrederick Mayle // Add any files to the message 152*9712c20fSFrederick Mayle NSArray* fileNames = [files_ allKeys]; 153*9712c20fSFrederick Mayle for (NSString* name in fileNames) { 154*9712c20fSFrederick Mayle // First append boundary 155*9712c20fSFrederick Mayle [self appendBoundaryData:postBody]; 156*9712c20fSFrederick Mayle // Then the formdata 157*9712c20fSFrederick Mayle id fileOrData = [files_ objectForKey:name]; 158*9712c20fSFrederick Mayle [HTTPRequest appendFileToBodyData:postBody 159*9712c20fSFrederick Mayle withName:name 160*9712c20fSFrederick Mayle withFileOrData:fileOrData]; 161*9712c20fSFrederick Mayle } 162*9712c20fSFrederick Mayle 163*9712c20fSFrederick Mayle NSString* epilogue = [NSString stringWithFormat:@"\r\n--%@--\r\n", boundary_]; 164*9712c20fSFrederick Mayle [postBody appendData:[epilogue dataUsingEncoding:NSUTF8StringEncoding]]; 165*9712c20fSFrederick Mayle 166*9712c20fSFrederick Mayle return postBody; 167*9712c20fSFrederick Mayle} 168*9712c20fSFrederick Mayle 169*9712c20fSFrederick Mayle@end 170