OLD | NEW |
| (Empty) |
1 // Copyright (c) 2006, Google Inc. | |
2 // All rights reserved. | |
3 // | |
4 // Redistribution and use in source and binary forms, with or without | |
5 // modification, are permitted provided that the following conditions are | |
6 // met: | |
7 // | |
8 // * Redistributions of source code must retain the above copyright | |
9 // notice, this list of conditions and the following disclaimer. | |
10 // * Redistributions in binary form must reproduce the above | |
11 // copyright notice, this list of conditions and the following disclaimer | |
12 // in the documentation and/or other materials provided with the | |
13 // distribution. | |
14 // * Neither the name of Google Inc. nor the names of its | |
15 // contributors may be used to endorse or promote products derived from | |
16 // this software without specific prior written permission. | |
17 // | |
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
29 | |
30 #import "HTTPMultipartUpload.h" | |
31 | |
32 @interface HTTPMultipartUpload(PrivateMethods) | |
33 - (NSString *)multipartBoundary; | |
34 - (NSData *)formDataForKey:(NSString *)key value:(NSString *)value; | |
35 - (NSData *)formDataForFileContents:(NSData *)contents name:(NSString *)name; | |
36 - (NSData *)formDataForFile:(NSString *)file name:(NSString *)name; | |
37 @end | |
38 | |
39 @implementation HTTPMultipartUpload | |
40 //============================================================================= | |
41 #pragma mark - | |
42 #pragma mark || Private || | |
43 //============================================================================= | |
44 - (NSString *)multipartBoundary { | |
45 // The boundary has 27 '-' characters followed by 16 hex digits | |
46 return [NSString stringWithFormat:@"---------------------------%08X%08X", | |
47 rand(), rand()]; | |
48 } | |
49 | |
50 //============================================================================= | |
51 - (NSData *)formDataForKey:(NSString *)key value:(NSString *)value { | |
52 NSString *escaped = | |
53 [key stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; | |
54 NSString *fmt = | |
55 @"--%@\r\nContent-Disposition: form-data; name=\"%@\"\r\n\r\n%@\r\n"; | |
56 NSString *form = [NSString stringWithFormat:fmt, boundary_, escaped, value]; | |
57 | |
58 return [form dataUsingEncoding:NSUTF8StringEncoding]; | |
59 } | |
60 | |
61 //============================================================================= | |
62 - (NSData *)formDataForFileContents:(NSData *)contents name:(NSString *)name { | |
63 NSMutableData *data = [NSMutableData data]; | |
64 NSString *escaped = | |
65 [name stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; | |
66 NSString *fmt = @"--%@\r\nContent-Disposition: form-data; name=\"%@\"; " | |
67 "filename=\"minidump.dmp\"\r\nContent-Type: application/octet-stream\r\n\r\n
"; | |
68 NSString *pre = [NSString stringWithFormat:fmt, boundary_, escaped]; | |
69 NSString *post = [NSString stringWithFormat:@"\r\n--%@--\r\n", boundary_]; | |
70 | |
71 [data appendData:[pre dataUsingEncoding:NSUTF8StringEncoding]]; | |
72 [data appendData:contents]; | |
73 [data appendData:[post dataUsingEncoding:NSUTF8StringEncoding]]; | |
74 | |
75 return data; | |
76 } | |
77 | |
78 //============================================================================= | |
79 - (NSData *)formDataForFile:(NSString *)file name:(NSString *)name { | |
80 NSData *contents = [NSData dataWithContentsOfFile:file]; | |
81 | |
82 return [self formDataForFileContents:contents name:name]; | |
83 } | |
84 | |
85 //============================================================================= | |
86 #pragma mark - | |
87 #pragma mark || Public || | |
88 //============================================================================= | |
89 - (id)initWithURL:(NSURL *)url { | |
90 if ((self = [super init])) { | |
91 url_ = [url copy]; | |
92 boundary_ = [[self multipartBoundary] retain]; | |
93 files_ = [[NSMutableDictionary alloc] init]; | |
94 } | |
95 | |
96 return self; | |
97 } | |
98 | |
99 //============================================================================= | |
100 - (void)dealloc { | |
101 [url_ release]; | |
102 [parameters_ release]; | |
103 [files_ release]; | |
104 [boundary_ release]; | |
105 [response_ release]; | |
106 | |
107 [super dealloc]; | |
108 } | |
109 | |
110 //============================================================================= | |
111 - (NSURL *)URL { | |
112 return url_; | |
113 } | |
114 | |
115 //============================================================================= | |
116 - (void)setParameters:(NSDictionary *)parameters { | |
117 if (parameters != parameters_) { | |
118 [parameters_ release]; | |
119 parameters_ = [parameters copy]; | |
120 } | |
121 } | |
122 | |
123 //============================================================================= | |
124 - (NSDictionary *)parameters { | |
125 return parameters_; | |
126 } | |
127 | |
128 //============================================================================= | |
129 - (void)addFileAtPath:(NSString *)path name:(NSString *)name { | |
130 [files_ setObject:path forKey:name]; | |
131 } | |
132 | |
133 //============================================================================= | |
134 - (void)addFileContents:(NSData *)data name:(NSString *)name { | |
135 [files_ setObject:data forKey:name]; | |
136 } | |
137 | |
138 //============================================================================= | |
139 - (NSDictionary *)files { | |
140 return files_; | |
141 } | |
142 | |
143 //============================================================================= | |
144 - (NSData *)send:(NSError **)error { | |
145 NSMutableURLRequest *req = | |
146 [[NSMutableURLRequest alloc] | |
147 initWithURL:url_ cachePolicy:NSURLRequestUseProtocolCachePolicy | |
148 timeoutInterval:10.0 ]; | |
149 | |
150 NSMutableData *postBody = [NSMutableData data]; | |
151 int i, count; | |
152 | |
153 [req setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@", | |
154 boundary_] forHTTPHeaderField:@"Content-type"]; | |
155 | |
156 // Add any parameters to the message | |
157 NSArray *parameterKeys = [parameters_ allKeys]; | |
158 NSString *key; | |
159 | |
160 count = [parameterKeys count]; | |
161 for (i = 0; i < count; ++i) { | |
162 key = [parameterKeys objectAtIndex:i]; | |
163 [postBody appendData:[self formDataForKey:key | |
164 value:[parameters_ objectForKey:key]]]; | |
165 } | |
166 | |
167 // Add any files to the message | |
168 NSArray *fileNames = [files_ allKeys]; | |
169 count = [fileNames count]; | |
170 for (i = 0; i < count; ++i) { | |
171 NSString *name = [fileNames objectAtIndex:i]; | |
172 id fileOrData = [files_ objectForKey:name]; | |
173 NSData *fileData; | |
174 | |
175 // The object can be either the path to a file (NSString) or the contents | |
176 // of the file (NSData). | |
177 if ([fileOrData isKindOfClass:[NSData class]]) | |
178 fileData = [self formDataForFileContents:fileOrData name:name]; | |
179 else | |
180 fileData = [self formDataForFile:fileOrData name:name]; | |
181 | |
182 [postBody appendData:fileData]; | |
183 } | |
184 | |
185 [req setHTTPBody:postBody]; | |
186 [req setHTTPMethod:@"POST"]; | |
187 | |
188 [response_ release]; | |
189 response_ = nil; | |
190 | |
191 NSData *data = [NSURLConnection sendSynchronousRequest:req | |
192 returningResponse:&response_ | |
193 error:error]; | |
194 | |
195 [response_ retain]; | |
196 | |
197 return data; | |
198 } | |
199 | |
200 //============================================================================= | |
201 - (NSHTTPURLResponse *)response { | |
202 return response_; | |
203 } | |
204 | |
205 @end | |
OLD | NEW |