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