Escape more characters in Mac OS sym-upload-v2 debug_file strings.

- Attempt to escape all characters which must be escaped in a URL or JSON string, for debug_file, since almost all of these are legal filename characters.

Change-Id: Ic7a9c1aef00093d164683be7db84f4f282f45f7a
Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/2339706
Reviewed-by: Mark Mentovai <mark@chromium.org>
diff --git a/src/common/mac/SymbolCollectorClient.m b/src/common/mac/SymbolCollectorClient.m
index 70f511f..f7cd923 100644
--- a/src/common/mac/SymbolCollectorClient.m
+++ b/src/common/mac/SymbolCollectorClient.m
@@ -70,9 +70,16 @@
                                withAPIKey:(NSString*)APIKey
                             withDebugFile:(NSString*)debugFile
                               withDebugID:(NSString*)debugID {
-  NSString* escapedDebugFile =
-      [debugFile stringByAddingPercentEncodingWithAllowedCharacters:
-                     [NSCharacterSet URLHostAllowedCharacterSet]];
+  // Note that forward-slash is listed as a character to escape here, for
+  // completeness, however it is illegal in a debugFile input.
+  NSMutableCharacterSet* allowedDebugFileCharacters = [NSMutableCharacterSet
+      characterSetWithCharactersInString:@" \"\\/#%:?@|^`{}<>[]&=;"];
+  [allowedDebugFileCharacters
+      formUnionWithCharacterSet:[NSCharacterSet controlCharacterSet]];
+  [allowedDebugFileCharacters invert];
+  NSString* escapedDebugFile = [debugFile
+      stringByAddingPercentEncodingWithAllowedCharacters:
+          allowedDebugFileCharacters];
 
   NSURL* URL = [NSURL
       URLWithString:[NSString
@@ -187,17 +194,31 @@
       URLWithString:[NSString
                         stringWithFormat:@"%@/v1/uploads/%@:complete?key=%@",
                                          APIURL, uploadKey, APIKey]];
-  NSString* body =
-      [NSString stringWithFormat:
-                    @"{ symbol_id: { debug_file: \"%@\", debug_id: \"%@\" } }",
-                    debugFile, debugID];
+
+  NSDictionary* symbolIdDictionary =
+      [NSDictionary dictionaryWithObjectsAndKeys:debugFile, @"debug_file",
+                                                 debugID, @"debug_id", nil];
+  NSDictionary* jsonDictionary = [NSDictionary
+      dictionaryWithObjectsAndKeys:symbolIdDictionary, @"symbol_id", nil];
+  NSError* error;
+  NSData* jsonData =
+      [NSJSONSerialization dataWithJSONObject:jsonDictionary
+                                      options:NSJSONWritingPrettyPrinted
+                                        error:&error];
+  if (error) {
+    fprintf(stdout,
+            "Failed to complete upload. Could not write JSON payload.\n");
+    return CompleteUploadResultError;
+  }
+  NSString* body = [[NSString alloc] initWithData:jsonData
+                                         encoding:NSUTF8StringEncoding];
 
   HTTPSimplePostRequest* postRequest =
       [[HTTPSimplePostRequest alloc] initWithURL:URL];
   [postRequest setBody:body];
   [postRequest setContentType:@"application/json"];
 
-  NSError* error = nil;
+  error = nil;
   NSData* data = [postRequest send:&error];
   NSString* result = [[NSString alloc] initWithData:data
                                            encoding:NSUTF8StringEncoding];