1 diff --git a/src/common/linux/http_upload.cc b/src/common/linux/http_upload.cc
2 index 702526af..0a1019dd 100644
3 --- a/src/common/linux/http_upload.cc
4 +++ b/src/common/linux/http_upload.cc
5 @@ -55,7 +55,7 @@ static const char kUserAgent[] = "Breakpad/1.0 (Linux)";
8 bool HTTPUpload::SendRequest(const string &url,
9 - const map<string, string> ¶meters,
10 + const string ¶meters,
11 const map<string, string> &files,
13 const string &proxy_user_pwd,
14 @@ -66,9 +66,6 @@ bool HTTPUpload::SendRequest(const string &url,
15 if (response_code != NULL)
18 - if (!CheckParameters(parameters))
21 // We may have been linked statically; if curl_easy_init is in the
22 // current binary, no need to search for a dynamic version.
23 void* curl_lib = dlopen(NULL, RTLD_NOW);
24 @@ -133,14 +130,14 @@ bool HTTPUpload::SendRequest(const string &url,
26 CURLFORMcode (*curl_formadd)(struct curl_httppost **, struct curl_httppost **, ...);
27 *(void**) (&curl_formadd) = dlsym(curl_lib, "curl_formadd");
28 - map<string, string>::const_iterator iter = parameters.begin();
29 - for (; iter != parameters.end(); ++iter)
30 - (*curl_formadd)(&formpost, &lastptr,
31 - CURLFORM_COPYNAME, iter->first.c_str(),
32 - CURLFORM_COPYCONTENTS, iter->second.c_str(),
34 + (*curl_formadd)(&formpost, &lastptr, CURLFORM_COPYNAME, "extra",
35 + CURLFORM_BUFFER, "extra.json", CURLFORM_BUFFERPTR,
36 + parameters.c_str(), CURLFORM_BUFFERLENGTH,
37 + parameters.length(), CURLFORM_CONTENTTYPE, "application/json",
41 + map<string, string>::const_iterator iter = files.begin();
42 for (iter = files.begin(); iter != files.end(); ++iter) {
43 (*curl_formadd)(&formpost, &lastptr,
44 CURLFORM_COPYNAME, iter->first.c_str(),
45 @@ -210,21 +207,4 @@ bool HTTPUpload::CheckCurlLib(void* curl_lib) {
46 dlsym(curl_lib, "curl_easy_setopt");
50 -bool HTTPUpload::CheckParameters(const map<string, string> ¶meters) {
51 - for (map<string, string>::const_iterator pos = parameters.begin();
52 - pos != parameters.end(); ++pos) {
53 - const string &str = pos->first;
54 - if (str.size() == 0)
55 - return false; // disallow empty parameter names
56 - for (unsigned int i = 0; i < str.size(); ++i) {
58 - if (c < 32 || c == '"' || c > 127) {
66 } // namespace google_breakpad
67 diff --git a/src/common/linux/http_upload.h b/src/common/linux/http_upload.h
68 index bc1d5d57..95dedebc 100644
69 --- a/src/common/linux/http_upload.h
70 +++ b/src/common/linux/http_upload.h
73 // HTTPUpload provides a "nice" API to send a multipart HTTP(S) POST
74 // request using libcurl. It currently supports requests that contain
75 -// a set of string parameters (key/value pairs), and a file to upload.
76 +// parameters encoded in a JSON string, and a file to upload.
78 #ifndef COMMON_LINUX_HTTP_UPLOAD_H__
79 #define COMMON_LINUX_HTTP_UPLOAD_H__
80 @@ -49,8 +49,7 @@ class HTTPUpload {
81 // request to the given URL.
82 // Each key in |files| is the name of the file part of the request
83 // (i.e. it corresponds to the name= attribute on an <input type="file">.
84 - // Parameter names must contain only printable ASCII characters,
85 - // and may not contain a quote (") character.
86 + // Parameters are specified as a JSON-encoded string in |parameters|.
87 // Only HTTP(S) URLs are currently supported. Returns true on success.
88 // If the request is successful and response_body is non-NULL,
89 // the response body will be returned in response_body.
90 @@ -59,7 +58,7 @@ class HTTPUpload {
91 // If the send fails, a description of the error will be
92 // returned in error_description.
93 static bool SendRequest(const string &url,
94 - const map<string, string> ¶meters,
95 + const string ¶meters,
96 const map<string, string> &files,
98 const string &proxy_user_pwd,
99 @@ -69,11 +68,6 @@ class HTTPUpload {
100 string *error_description);
103 - // Checks that the given list of parameters has only printable
104 - // ASCII characters in the parameter name, and does not contain
105 - // any quote (") characters. Returns true if so.
106 - static bool CheckParameters(const map<string, string> ¶meters);
108 // Checks the curl_lib parameter points to a valid curl lib.
109 static bool CheckCurlLib(void* curl_lib);
111 diff --git a/src/common/mac/HTTPMultipartUpload.h b/src/common/mac/HTTPMultipartUpload.h
112 index 42e8fed3..0cea733e 100644
113 --- a/src/common/mac/HTTPMultipartUpload.h
114 +++ b/src/common/mac/HTTPMultipartUpload.h
116 @interface HTTPMultipartUpload : NSObject {
118 NSURL *url_; // The destination URL (STRONG)
119 - NSDictionary *parameters_; // The key/value pairs for sending data (STRONG)
120 + NSMutableString *parameters_; // The JSON payload for sending data (STRONG)
121 NSMutableDictionary *files_; // Dictionary of name/file-path (STRONG)
122 NSString *boundary_; // The boundary string (STRONG)
123 NSHTTPURLResponse *response_; // The response from the send (STRONG)
128 -- (void)setParameters:(NSDictionary *)parameters;
129 -- (NSDictionary *)parameters;
130 +- (void)setParameters:(NSMutableString *)parameters;
131 +- (NSMutableString *)parameters;
133 - (void)addFileAtPath:(NSString *)path name:(NSString *)name;
134 - (void)addFileContents:(NSData *)data name:(NSString *)name;
135 diff --git a/src/common/mac/HTTPMultipartUpload.m b/src/common/mac/HTTPMultipartUpload.m
136 index a3677f25..d2480493 100644
137 --- a/src/common/mac/HTTPMultipartUpload.m
138 +++ b/src/common/mac/HTTPMultipartUpload.m
139 @@ -93,7 +93,7 @@ static NSData *SendSynchronousNSURLRequest(NSURLRequest *req,
140 - (NSString *)multipartBoundary;
141 // Each of the following methods will append the starting multipart boundary,
142 // but not the ending one.
143 -- (NSData *)formDataForKey:(NSString *)key value:(NSString *)value;
144 +- (NSData *)formDataForJSON:(NSString *)json;
145 - (NSData *)formDataForFileContents:(NSData *)contents name:(NSString *)name;
146 - (NSData *)formDataForFile:(NSString *)file name:(NSString *)name;
148 @@ -110,13 +110,16 @@ static NSData *SendSynchronousNSURLRequest(NSURLRequest *req,
151 //=============================================================================
152 -- (NSData *)formDataForKey:(NSString *)key value:(NSString *)value {
153 - NSString *escaped = PercentEncodeNSString(key);
155 - @"--%@\r\nContent-Disposition: form-data; name=\"%@\"\r\n\r\n%@\r\n";
156 - NSString *form = [NSString stringWithFormat:fmt, boundary_, escaped, value];
157 +- (NSData *)formDataForJSON:(NSString *)json {
158 + NSMutableData *data = [NSMutableData data];
159 + NSString *fmt = @"--%@\r\nContent-Disposition: form-data; name=\"extra\"; "
160 + "filename=\"extra.json\"\r\nContent-Type: application/json\r\n\r\n";
161 + NSString *form = [NSString stringWithFormat:fmt, boundary_];
163 + [data appendData:[form dataUsingEncoding:NSUTF8StringEncoding]];
164 + [data appendData:[json dataUsingEncoding:NSUTF8StringEncoding]];
166 - return [form dataUsingEncoding:NSUTF8StringEncoding];
170 //=============================================================================
171 @@ -171,15 +174,15 @@ static NSData *SendSynchronousNSURLRequest(NSURLRequest *req,
174 //=============================================================================
175 -- (void)setParameters:(NSDictionary *)parameters {
176 +- (void)setParameters:(NSMutableString *)parameters {
177 if (parameters != parameters_) {
178 [parameters_ release];
179 - parameters_ = [parameters copy];
180 + parameters_ = [parameters mutableCopy];
184 //=============================================================================
185 -- (NSDictionary *)parameters {
186 +- (NSMutableString *)parameters {
190 @@ -210,16 +213,8 @@ static NSData *SendSynchronousNSURLRequest(NSURLRequest *req,
191 [req setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",
192 boundary_] forHTTPHeaderField:@"Content-type"];
194 - // Add any parameters to the message
195 - NSArray *parameterKeys = [parameters_ allKeys];
198 - NSInteger count = [parameterKeys count];
199 - for (NSInteger i = 0; i < count; ++i) {
200 - key = [parameterKeys objectAtIndex:i];
201 - [postBody appendData:[self formDataForKey:key
202 - value:[parameters_ objectForKey:key]]];
204 + // Add JSON parameters to the message
205 + [postBody appendData:[self formDataForJSON:parameters_]];
207 // Add any files to the message
208 NSArray *fileNames = [files_ allKeys];
209 diff --git a/src/common/windows/http_upload.cc b/src/common/windows/http_upload.cc
210 index b0cc9078..5df17e1a 100644
211 --- a/src/common/windows/http_upload.cc
212 +++ b/src/common/windows/http_upload.cc
213 @@ -141,23 +141,6 @@ namespace {
217 - bool CheckParameters(const map<wstring, wstring> ¶meters) {
218 - for (map<wstring, wstring>::const_iterator pos = parameters.begin();
219 - pos != parameters.end(); ++pos) {
220 - const wstring &str = pos->first;
221 - if (str.size() == 0) {
222 - return false; // disallow empty parameter names
224 - for (unsigned int i = 0; i < str.size(); ++i) {
225 - wchar_t c = str[i];
226 - if (c < 32 || c == '"' || c > 127) {
234 // Converts a UTF16 string to UTF8.
235 string WideToUTF8(const wstring &wide) {
236 return WideToMBCP(wide, CP_UTF8);
237 @@ -390,7 +373,7 @@ namespace {
241 - bool GenerateRequestBody(const map<wstring, wstring> ¶meters,
242 + bool GenerateRequestBody(const string ¶meters,
243 const map<wstring, wstring> &files,
244 const wstring &boundary,
245 string *request_body) {
246 @@ -401,14 +384,19 @@ namespace {
248 request_body->clear();
250 - // Append each of the parameter pairs as a form-data part
251 - for (map<wstring, wstring>::const_iterator pos = parameters.begin();
252 - pos != parameters.end(); ++pos) {
253 - request_body->append("--" + boundary_str + "\r\n");
254 - request_body->append("Content-Disposition: form-data; name=\"" +
255 - WideToUTF8(pos->first) + "\"\r\n\r\n" +
256 - WideToUTF8(pos->second) + "\r\n");
257 + // Append the extra data as a single JSON form entry
258 + request_body->append("--" + boundary_str + "\r\n");
259 + request_body->append(
260 + "Content-Disposition: form-data; "
262 + "filename=\"extra.json\"\r\n");
263 + request_body->append("Content-Type: application/json\r\n");
264 + request_body->append("\r\n");
266 + if (!parameters.empty()) {
267 + request_body->append(parameters);
269 + request_body->append("\r\n");
271 // Now append each upload file as a binary (octet-stream) part
272 for (map<wstring, wstring>::const_iterator pos = files.begin();
273 @@ -463,16 +451,11 @@ namespace google_breakpad {
275 bool HTTPUpload::SendMultipartPostRequest(
277 - const map<wstring, wstring>& parameters,
278 + const string& parameters,
279 const map<wstring, wstring>& files,
281 wstring* response_body,
282 int* response_code) {
283 - // TODO(bryner): support non-ASCII parameter names
284 - if (!CheckParameters(parameters)) {
288 wstring boundary = GenerateMultipartBoundary();
289 wstring content_type_header = GenerateMultipartPostRequestHeader(boundary);
291 diff --git a/src/common/windows/http_upload.h b/src/common/windows/http_upload.h
292 index 57e526e3..1e47f582 100644
293 --- a/src/common/windows/http_upload.h
294 +++ b/src/common/windows/http_upload.h
297 // HTTPUpload provides a "nice" API to send a multipart HTTP(S) POST
298 // request using wininet. It currently supports requests that contain
299 -// a set of string parameters (key/value pairs), and a file to upload.
300 +// parameters encoded in a JSON string, and a file to upload.
302 #ifndef COMMON_WINDOWS_HTTP_UPLOAD_H_
303 #define COMMON_WINDOWS_HTTP_UPLOAD_H_
306 namespace google_breakpad {
315 @@ -81,8 +81,7 @@ class HTTPUpload {
316 // request to the given URL.
317 // Each key in |files| is the name of the file part of the request
318 // (i.e. it corresponds to the name= attribute on an <input type="file">.
319 - // Parameter names must contain only printable ASCII characters,
320 - // and may not contain a quote (") character.
321 + // Parameters are specified as a JSON-encoded string in |parameters|.
322 // Only HTTP(S) URLs are currently supported. Returns true on success.
323 // If the request is successful and response_body is non-NULL,
324 // the response body will be returned in response_body.
325 @@ -90,7 +89,7 @@ class HTTPUpload {
326 // received (or 0 if the request failed before getting an HTTP response).
327 static bool SendMultipartPostRequest(
329 - const map<wstring, wstring>& parameters,
330 + const string& parameters,
331 const map<wstring, wstring>& files,
333 wstring *response_body,