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