aboutsummaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
authorNelson Billing <nbilling@google.com>2020-07-29 16:28:25 -0700
committerNelson Billing <nbilling@google.com>2020-07-29 23:30:33 +0000
commita740aa2625df2c0ed21ed7118bd8ab5faec375b8 (patch)
treedd0597c90bdac583d8bc26c1898b01757120f68f /src/common
parentCheck for tombstone as very first entry in the line table. (diff)
downloadbreakpad-a740aa2625df2c0ed21ed7118bd8ab5faec375b8.tar.xz
Fix Mac symupload non-XCode builds.
Change-Id: Ic4924032faba83fc14f62feaac9a97bbfd0971ed Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/2324311 Reviewed-by: Mark Mentovai <mark@chromium.org>
Diffstat (limited to 'src/common')
-rw-r--r--src/common/mac/HTTPGetRequest.h42
-rw-r--r--src/common/mac/HTTPGetRequest.m39
-rw-r--r--src/common/mac/HTTPMultipartUpload.h28
-rw-r--r--src/common/mac/HTTPMultipartUpload.m63
-rw-r--r--src/common/mac/HTTPPutRequest.h51
-rw-r--r--src/common/mac/HTTPPutRequest.m62
-rw-r--r--src/common/mac/HTTPRequest.h73
-rw-r--r--src/common/mac/HTTPRequest.m213
-rw-r--r--src/common/mac/HTTPSimplePostRequest.h57
-rw-r--r--src/common/mac/HTTPSimplePostRequest.m69
-rw-r--r--src/common/mac/SymbolCollectorClient.h102
-rw-r--r--src/common/mac/SymbolCollectorClient.m235
-rw-r--r--src/common/mac/encoding_util.h41
-rw-r--r--src/common/mac/encoding_util.m47
-rw-r--r--src/common/mac/minidump_upload.m135
15 files changed, 1210 insertions, 47 deletions
diff --git a/src/common/mac/HTTPGetRequest.h b/src/common/mac/HTTPGetRequest.h
new file mode 100644
index 00000000..3aa316b5
--- /dev/null
+++ b/src/common/mac/HTTPGetRequest.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2020, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import <Foundation/Foundation.h>
+
+#import "HTTPRequest.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Represents a HTTP GET request
+ */
+@interface HTTPGetRequest : HTTPRequest
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/src/common/mac/HTTPGetRequest.m b/src/common/mac/HTTPGetRequest.m
new file mode 100644
index 00000000..f9b7bf0e
--- /dev/null
+++ b/src/common/mac/HTTPGetRequest.m
@@ -0,0 +1,39 @@
+// Copyright (c) 2020, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import "HTTPGetRequest.h"
+
+@implementation HTTPGetRequest
+
+//=============================================================================
+- (NSString*)HTTPMethod {
+ return @"GET";
+}
+
+@end
diff --git a/src/common/mac/HTTPMultipartUpload.h b/src/common/mac/HTTPMultipartUpload.h
index 5eaaa91b..56d5394d 100644
--- a/src/common/mac/HTTPMultipartUpload.h
+++ b/src/common/mac/HTTPMultipartUpload.h
@@ -27,39 +27,37 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
#import <Foundation/Foundation.h>
#import "HTTPRequest.h"
- /**
- Represents a multipart/form-data HTTP upload (POST request).
- Each parameter pair is sent as a boundary.
- Each file is sent with a name field in addition to the filename and data.
- */
+/**
+ Represents a multipart/form-data HTTP upload (POST request).
+ Each parameter pair is sent as a boundary.
+ Each file is sent with a name field in addition to the filename and data.
+ */
@interface HTTPMultipartUpload : HTTPRequest {
@protected
- NSDictionary *parameters_; // The key/value pairs for sending data (STRONG)
- NSMutableDictionary *files_; // Dictionary of name/file-path (STRONG)
- NSString *boundary_; // The boundary string (STRONG)
+ NSDictionary* parameters_; // The key/value pairs for sending data (STRONG)
+ NSMutableDictionary* files_; // Dictionary of name/file-path (STRONG)
+ NSString* boundary_; // The boundary string (STRONG)
}
/**
Sets the parameters that will be sent in the multipart POST request.
*/
-- (void)setParameters:(NSDictionary *)parameters;
-- (NSDictionary *)parameters;
+- (void)setParameters:(NSDictionary*)parameters;
+- (NSDictionary*)parameters;
/**
Adds a file to be uploaded in the multipart POST request, by its file path.
*/
-- (void)addFileAtPath:(NSString *)path name:(NSString *)name;
+- (void)addFileAtPath:(NSString*)path name:(NSString*)name;
/**
Adds a file to be uploaded in the multipart POST request, by its name and
contents.
*/
-- (void)addFileContents:(NSData *)data name:(NSString *)name;
-- (NSDictionary *)files;
+- (void)addFileContents:(NSData*)data name:(NSString*)name;
+- (NSDictionary*)files;
@end
diff --git a/src/common/mac/HTTPMultipartUpload.m b/src/common/mac/HTTPMultipartUpload.m
index 7fc474b8..48af299d 100644
--- a/src/common/mac/HTTPMultipartUpload.m
+++ b/src/common/mac/HTTPMultipartUpload.m
@@ -30,15 +30,15 @@
#import "HTTPMultipartUpload.h"
#import "GTMDefines.h"
-#import "util.h"
+#import "encoding_util.h"
-@interface HTTPMultipartUpload(PrivateMethods)
-- (NSString *)multipartBoundary;
+@interface HTTPMultipartUpload (PrivateMethods)
+- (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 *)formDataForFileContents:(NSData *)contents name:(NSString *)name;
-- (NSData *)formDataForFile:(NSString *)file name:(NSString *)name;
+- (NSData*)formDataForKey:(NSString*)key value:(NSString*)value;
+- (NSData*)formDataForFileContents:(NSData*)contents name:(NSString*)name;
+- (NSData*)formDataForFile:(NSString*)file name:(NSString*)name;
@end
@implementation HTTPMultipartUpload
@@ -46,30 +46,29 @@
#pragma mark -
#pragma mark || Private ||
//=============================================================================
-- (NSString *)multipartBoundary {
+- (NSString*)multipartBoundary {
// The boundary has 27 '-' characters followed by 16 hex digits
- return [NSString stringWithFormat:@"---------------------------%08X%08X",
- rand(), rand()];
+ return [NSString
+ stringWithFormat:@"---------------------------%08X%08X", rand(), rand()];
}
//=============================================================================
-- (NSData *)formDataForKey:(NSString *)key value:(NSString *)value {
+- (NSData*)formDataForKey:(NSString*)key value:(NSString*)value {
NSMutableData* data = [NSMutableData data];
[self appendBoundaryData:data];
-
- NSString *escaped = PercentEncodeNSString(key);
- NSString *fmt =
- @"Content-Disposition: form-data; name=\"%@\"\r\n\r\n%@\r\n";
- NSString *form = [NSString stringWithFormat:fmt, boundary_, escaped, value];
+
+ NSString* escaped = PercentEncodeNSString(key);
+ NSString* fmt = @"Content-Disposition: form-data; name=\"%@\"\r\n\r\n%@\r\n";
+ NSString* form = [NSString stringWithFormat:fmt, boundary_, escaped, value];
[data appendData:[form dataUsingEncoding:NSUTF8StringEncoding]];
return data;
}
//=============================================================================
-- (void)appendBoundaryData: (NSMutableData*)data {
- NSString *fmt = @"--%@\r\n";
- NSString *pre = [NSString stringWithFormat:fmt, boundary_];
+- (void)appendBoundaryData:(NSMutableData*)data {
+ NSString* fmt = @"--%@\r\n";
+ NSString* pre = [NSString stringWithFormat:fmt, boundary_];
[data appendData:[pre dataUsingEncoding:NSUTF8StringEncoding]];
}
@@ -78,7 +77,7 @@
#pragma mark -
#pragma mark || Public ||
//=============================================================================
-- (id)initWithURL:(NSURL *)url {
+- (id)initWithURL:(NSURL*)url {
if ((self = [super initWithURL:url])) {
boundary_ = [[self multipartBoundary] retain];
files_ = [[NSMutableDictionary alloc] init];
@@ -97,7 +96,7 @@
}
//=============================================================================
-- (void)setParameters:(NSDictionary *)parameters {
+- (void)setParameters:(NSDictionary*)parameters {
if (parameters != parameters_) {
[parameters_ release];
parameters_ = [parameters copy];
@@ -105,22 +104,22 @@
}
//=============================================================================
-- (NSDictionary *)parameters {
+- (NSDictionary*)parameters {
return parameters_;
}
//=============================================================================
-- (void)addFileAtPath:(NSString *)path name:(NSString *)name {
+- (void)addFileAtPath:(NSString*)path name:(NSString*)name {
[files_ setObject:path forKey:name];
}
//=============================================================================
-- (void)addFileContents:(NSData *)data name:(NSString *)name {
+- (void)addFileContents:(NSData*)data name:(NSString*)name {
[files_ setObject:data forKey:name];
}
//=============================================================================
-- (NSDictionary *)files {
+- (NSDictionary*)files {
return files_;
}
@@ -131,17 +130,17 @@
//=============================================================================
- (NSString*)contentType {
- return [NSString stringWithFormat:@"multipart/form-data; boundary=%@",
- boundary_];
+ return [NSString
+ stringWithFormat:@"multipart/form-data; boundary=%@", boundary_];
}
//=============================================================================
- (NSData*)bodyData {
- NSMutableData *postBody = [NSMutableData data];
+ NSMutableData* postBody = [NSMutableData data];
// Add any parameters to the message
- NSArray *parameterKeys = [parameters_ allKeys];
- NSString *key;
+ NSArray* parameterKeys = [parameters_ allKeys];
+ NSString* key;
NSInteger count = [parameterKeys count];
for (NSInteger i = 0; i < count; ++i) {
@@ -151,8 +150,8 @@
}
// Add any files to the message
- NSArray *fileNames = [files_ allKeys];
- for (NSString *name in fileNames) {
+ NSArray* fileNames = [files_ allKeys];
+ for (NSString* name in fileNames) {
// First append boundary
[self appendBoundaryData:postBody];
// Then the formdata
@@ -162,7 +161,7 @@
withFileOrData:fileOrData];
}
- NSString *epilogue = [NSString stringWithFormat:@"\r\n--%@--\r\n", boundary_];
+ NSString* epilogue = [NSString stringWithFormat:@"\r\n--%@--\r\n", boundary_];
[postBody appendData:[epilogue dataUsingEncoding:NSUTF8StringEncoding]];
return postBody;
diff --git a/src/common/mac/HTTPPutRequest.h b/src/common/mac/HTTPPutRequest.h
new file mode 100644
index 00000000..431ea610
--- /dev/null
+++ b/src/common/mac/HTTPPutRequest.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2020, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import <Foundation/Foundation.h>
+
+#import "HTTPRequest.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Represents an HTTP PUT request.
+ */
+@interface HTTPPutRequest : HTTPRequest {
+ @protected
+ NSString* file_;
+}
+
+/**
+ Sets the path of the file that will be sent in the PUT request.
+ */
+- (void)setFile:(NSString*)file;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/src/common/mac/HTTPPutRequest.m b/src/common/mac/HTTPPutRequest.m
new file mode 100644
index 00000000..ec67376b
--- /dev/null
+++ b/src/common/mac/HTTPPutRequest.m
@@ -0,0 +1,62 @@
+// Copyright (c) 2020, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import "HTTPPutRequest.h"
+
+@implementation HTTPPutRequest
+
+//=============================================================================
+- (void)dealloc {
+ [file_ release];
+
+ [super dealloc];
+}
+
+//=============================================================================
+- (void)setFile:(NSString*)file {
+ file_ = [file copy];
+}
+
+//=============================================================================
+- (NSString*)HTTPMethod {
+ return @"PUT";
+}
+
+//=============================================================================
+- (NSData*)bodyData {
+ NSMutableData* postBody = [NSMutableData data];
+
+ [HTTPRequest appendFileToBodyData:postBody
+ withName:@"symbol_file"
+ withFileOrData:file_];
+
+ return postBody;
+}
+
+@end
diff --git a/src/common/mac/HTTPRequest.h b/src/common/mac/HTTPRequest.h
new file mode 100644
index 00000000..b78fad6b
--- /dev/null
+++ b/src/common/mac/HTTPRequest.h
@@ -0,0 +1,73 @@
+// Copyright (c) 2020, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+/**
+ Represents a single HTTP request. Sending the request is synchronous.
+ Once the send is complete, the response will be set.
+
+ This is a base interface that specific HTTP requests derive from.
+ It is not intended to be instantiated directly.
+ */
+@interface HTTPRequest : NSObject {
+ @protected
+ NSURL* URL_; // The destination URL (STRONG)
+ NSHTTPURLResponse* response_; // The response from the send (STRONG)
+}
+
+/**
+ Initializes the HTTPRequest and sets its URL.
+ */
+- (id)initWithURL:(NSURL*)URL;
+
+- (NSURL*)URL;
+
+- (NSHTTPURLResponse*)response;
+
+- (NSString*)HTTPMethod; // Internal, don't call outside class hierarchy.
+
+- (NSString*)contentType; // Internal, don't call outside class hierarchy.
+
+- (NSData*)bodyData; // Internal, don't call outside class hierarchy.
+
+- (NSData*)send:(NSError**)error;
+
+/**
+ Appends a file to the HTTP request, either by filename or by file content
+ (in the form of NSData).
+ */
++ (void)appendFileToBodyData:(NSMutableData*)data
+ withName:(NSString*)name
+ withFileOrData:(id)fileOrData;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/src/common/mac/HTTPRequest.m b/src/common/mac/HTTPRequest.m
new file mode 100644
index 00000000..ee7de3af
--- /dev/null
+++ b/src/common/mac/HTTPRequest.m
@@ -0,0 +1,213 @@
+// Copyright (c) 2020, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import "HTTPRequest.h"
+
+#include <Availability.h>
+#include <AvailabilityMacros.h>
+
+#import "encoding_util.h"
+
+// As -[NSURLConnection sendSynchronousRequest:returningResponse:error:] has
+// been deprecated with iOS 9.0 / OS X 10.11 SDKs, this function re-implements
+// it using -[NSURLSession dataTaskWithRequest:completionHandler:] which is
+// available on iOS 7+.
+static NSData* SendSynchronousNSURLRequest(NSURLRequest* req,
+ NSURLResponse** outResponse,
+ NSError** outError) {
+#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && defined(__IPHONE_7_0) && \
+ __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_7_0) || \
+ (defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \
+ defined(MAC_OS_X_VERSION_10_11) && \
+ MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11)
+ __block NSData* result = nil;
+ __block NSError* error = nil;
+ __block NSURLResponse* response = nil;
+ dispatch_semaphore_t waitSemaphone = dispatch_semaphore_create(0);
+ NSURLSessionConfiguration* config =
+ [NSURLSessionConfiguration defaultSessionConfiguration];
+ [config setTimeoutIntervalForRequest:240.0];
+ NSURLSession* session = [NSURLSession sessionWithConfiguration:config];
+ [[session
+ dataTaskWithRequest:req
+ completionHandler:^(NSData* data, NSURLResponse* resp, NSError* err) {
+ if (outError)
+ error = [err retain];
+ if (outResponse)
+ response = [resp retain];
+ if (err == nil)
+ result = [data retain];
+ dispatch_semaphore_signal(waitSemaphone);
+ }] resume];
+ dispatch_semaphore_wait(waitSemaphone, DISPATCH_TIME_FOREVER);
+ dispatch_release(waitSemaphone);
+ if (outError)
+ *outError = [error autorelease];
+ if (outResponse)
+ *outResponse = [response autorelease];
+ return [result autorelease];
+#else
+ return [NSURLConnection sendSynchronousRequest:req
+ returningResponse:outResponse
+ error:outError];
+#endif
+}
+
+@implementation HTTPRequest
+
+//=============================================================================
+- (id)initWithURL:(NSURL*)URL {
+ if ((self = [super init])) {
+ URL_ = [URL copy];
+ }
+
+ return self;
+}
+
+//=============================================================================
+- (void)dealloc {
+ [URL_ release];
+ [response_ release];
+
+ [super dealloc];
+}
+
+//=============================================================================
+- (NSURL*)URL {
+ return URL_;
+}
+
+//=============================================================================
+- (NSHTTPURLResponse*)response {
+ return response_;
+}
+
+//=============================================================================
+- (NSString*)HTTPMethod {
+ @throw [NSException
+ exceptionWithName:NSInternalInconsistencyException
+ reason:[NSString stringWithFormat:@"You must"
+ "override %@ in a subclass",
+ NSStringFromSelector(_cmd)]
+ userInfo:nil];
+}
+
+//=============================================================================
+- (NSString*)contentType {
+ return nil;
+}
+
+//=============================================================================
+- (NSData*)bodyData {
+ return nil;
+}
+
+//=============================================================================
+- (NSData*)send:(NSError**)withError {
+ NSMutableURLRequest* req = [[NSMutableURLRequest alloc]
+ initWithURL:URL_
+ cachePolicy:NSURLRequestUseProtocolCachePolicy
+ timeoutInterval:60.0];
+
+ NSString* contentType = [self contentType];
+ if ([contentType length] > 0) {
+ [req setValue:contentType forHTTPHeaderField:@"Content-type"];
+ }
+
+ NSData* bodyData = [self bodyData];
+ if ([bodyData length] > 0) {
+ [req setHTTPBody:bodyData];
+ }
+
+ [req setHTTPMethod:[self HTTPMethod]];
+
+ [response_ release];
+ response_ = nil;
+
+ NSData* data = nil;
+ if ([[req URL] isFileURL]) {
+ [[req HTTPBody] writeToURL:[req URL] options:0 error:withError];
+ } else {
+ NSURLResponse* response = nil;
+ data = SendSynchronousNSURLRequest(req, &response, withError);
+ response_ = (NSHTTPURLResponse*)[response retain];
+ }
+ [req release];
+
+ return data;
+}
+
+//=============================================================================
++ (NSData*)formDataForFileContents:(NSData*)contents withName:(NSString*)name {
+ NSMutableData* data = [NSMutableData data];
+ NSString* escaped = PercentEncodeNSString(name);
+ NSString* fmt = @"Content-Disposition: form-data; name=\"%@\"; "
+ "filename=\"minidump.dmp\"\r\nContent-Type: "
+ "application/octet-stream\r\n\r\n";
+ NSString* pre = [NSString stringWithFormat:fmt, escaped];
+
+ [data appendData:[pre dataUsingEncoding:NSUTF8StringEncoding]];
+ [data appendData:contents];
+
+ return data;
+}
+
+//=============================================================================
++ (NSData*)formDataForFile:(NSString*)file withName:(NSString*)name {
+ NSData* contents = [NSData dataWithContentsOfFile:file];
+
+ return [HTTPRequest formDataForFileContents:contents withName:name];
+}
+
+//=============================================================================
++ (NSData*)formDataForKey:(NSString*)key value:(NSString*)value {
+ NSString* escaped = PercentEncodeNSString(key);
+ NSString* fmt = @"Content-Disposition: form-data; name=\"%@\"\r\n\r\n%@\r\n";
+ NSString* form = [NSString stringWithFormat:fmt, escaped, value];
+
+ return [form dataUsingEncoding:NSUTF8StringEncoding];
+}
+
+//=============================================================================
++ (void)appendFileToBodyData:(NSMutableData*)data
+ withName:(NSString*)name
+ withFileOrData:(id)fileOrData {
+ NSData* fileData;
+
+ // The object can be either the path to a file (NSString) or the contents
+ // of the file (NSData).
+ if ([fileOrData isKindOfClass:[NSData class]])
+ fileData = [self formDataForFileContents:fileOrData withName:name];
+ else
+ fileData = [HTTPRequest formDataForFile:fileOrData withName:name];
+
+ [data appendData:fileData];
+}
+
+@end
diff --git a/src/common/mac/HTTPSimplePostRequest.h b/src/common/mac/HTTPSimplePostRequest.h
new file mode 100644
index 00000000..bfabfead
--- /dev/null
+++ b/src/common/mac/HTTPSimplePostRequest.h
@@ -0,0 +1,57 @@
+// Copyright (c) 2020, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import <Foundation/Foundation.h>
+
+#import "HTTPRequest.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Represents a simple (non-multipart) HTTP POST request.
+ */
+@interface HTTPSimplePostRequest : HTTPRequest {
+ @protected
+ NSString* contentType_;
+ NSString* body_;
+}
+
+/**
+ Sets the content type of the POST request.
+ */
+- (void)setContentType:(NSString*)contentType;
+
+/**
+ Sets the contents of the POST request's body.
+ */
+- (void)setBody:(NSString*)body;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/src/common/mac/HTTPSimplePostRequest.m b/src/common/mac/HTTPSimplePostRequest.m
new file mode 100644
index 00000000..4cb3ef15
--- /dev/null
+++ b/src/common/mac/HTTPSimplePostRequest.m
@@ -0,0 +1,69 @@
+// Copyright (c) 2020, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import "HTTPSimplePostRequest.h"
+
+@implementation HTTPSimplePostRequest
+
+//=============================================================================
+- (void)dealloc {
+ [contentType_ release];
+ [body_ release];
+
+ [super dealloc];
+}
+
+//=============================================================================
+- (void)setContentType:(NSString*)contentType {
+ contentType_ = [contentType copy];
+}
+
+//=============================================================================
+- (void)setBody:(NSString*)body {
+ body_ = [body copy];
+}
+
+//=============================================================================
+- (NSString*)HTTPMethod {
+ return @"POST";
+}
+
+//=============================================================================
+- (NSString*)contentType {
+ return contentType_;
+}
+
+//=============================================================================
+- (NSData*)bodyData {
+ NSMutableData* data = [NSMutableData data];
+ [data appendData:[body_ dataUsingEncoding:NSUTF8StringEncoding]];
+ return data;
+}
+
+@end
diff --git a/src/common/mac/SymbolCollectorClient.h b/src/common/mac/SymbolCollectorClient.h
new file mode 100644
index 00000000..1f27f23f
--- /dev/null
+++ b/src/common/mac/SymbolCollectorClient.h
@@ -0,0 +1,102 @@
+// Copyright (c) 2020, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Represents a response from a sym-upload-v2 server to a createUploadURLOnServer
+ call.
+ */
+@interface UploadURLResponse : NSObject {
+ @protected
+ NSString* uploadURL_;
+ NSString* uploadKey_;
+}
+
+- (id)initWithUploadURL:(NSString*)uploadURL withUploadKey:(NSString*)uploadKey;
+
+- (NSString*)uploadURL;
+- (NSString*)uploadKey;
+@end
+
+/**
+ Possible return statuses from a sym-upload-v2 server to a
+ completeUploadOnServer call.
+ */
+typedef NS_ENUM(NSInteger, CompleteUploadResult) {
+ CompleteUploadResultOk,
+ CompleteUploadResultDuplicateData,
+ CompleteUploadResultError
+};
+
+/**
+ Possible return statuses from a sym-upload-v2 server to a
+ checkSymbolStatusOnServer call.
+ */
+typedef NS_ENUM(NSInteger, SymbolStatus) {
+ SymbolStatusFound,
+ SymbolStatusMissing,
+ SymbolStatusUnknown
+};
+
+/**
+ Interface to help a client interact with a sym-upload-v2 server, over HTTP.
+ For details of the API and protocol, see :/docs/sym_upload_v2_protocol.md.
+ */
+@interface SymbolCollectorClient : NSObject
+;
+
+/**
+ Calls the /v1/symbols/{debug_file}/{debug_id}:checkStatus API on the server.
+ */
++ (SymbolStatus)checkSymbolStatusOnServer:(NSString*)APIURL
+ withAPIKey:(NSString*)APIKey
+ withDebugFile:(NSString*)debugFile
+ withDebugID:(NSString*)debugID;
+
+/**
+ Calls the /v1/uploads:create API on the server.
+ */
++ (UploadURLResponse*)createUploadURLOnServer:(NSString*)APIURL
+ withAPIKey:(NSString*)APIKey;
+
+/**
+ Calls the /v1/uploads/{key}:complete API on the server.
+ */
++ (CompleteUploadResult)completeUploadOnServer:(NSString*)APIURL
+ withAPIKey:(NSString*)APIKey
+ withUploadKey:(NSString*)uploadKey
+ withDebugFile:(NSString*)debugFile
+ withDebugID:(NSString*)debugID;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/src/common/mac/SymbolCollectorClient.m b/src/common/mac/SymbolCollectorClient.m
new file mode 100644
index 00000000..b997607f
--- /dev/null
+++ b/src/common/mac/SymbolCollectorClient.m
@@ -0,0 +1,235 @@
+// Copyright (c) 2020, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import "SymbolCollectorClient.h"
+
+#import "HTTPGetRequest.h"
+#import "HTTPSimplePostRequest.h"
+
+@implementation UploadURLResponse
+
+//=============================================================================
+- (id)initWithUploadURL:(NSString*)uploadURL
+ withUploadKey:(NSString*)uploadKey {
+ if (self = [super init]) {
+ uploadURL_ = [uploadURL copy];
+ uploadKey_ = [uploadKey copy];
+ }
+ return self;
+}
+
+//=============================================================================
+- (void)dealloc {
+ [uploadURL_ release];
+ [uploadKey_ release];
+
+ [super dealloc];
+}
+
+//=============================================================================
+- (NSString*)uploadURL {
+ return uploadURL_;
+}
+
+//=============================================================================
+- (NSString*)uploadKey {
+ return uploadKey_;
+}
+@end
+
+@implementation SymbolCollectorClient
+
+//=============================================================================
++ (SymbolStatus)checkSymbolStatusOnServer:(NSString*)APIURL
+ withAPIKey:(NSString*)APIKey
+ withDebugFile:(NSString*)debugFile
+ withDebugID:(NSString*)debugID {
+ NSURL* URL = [NSURL
+ URLWithString:[NSString
+ stringWithFormat:@"%@/v1/symbols/%@/%@:checkStatus"
+ @"?key=%@",
+ APIURL, debugFile, debugID, APIKey]];
+
+ HTTPGetRequest* getRequest = [[HTTPGetRequest alloc] initWithURL:URL];
+ NSError* error = nil;
+ NSData* data = [getRequest send:&error];
+ NSString* result = [[NSString alloc] initWithData:data
+ encoding:NSUTF8StringEncoding];
+ int responseCode = [[getRequest response] statusCode];
+ [getRequest release];
+
+ if (error || responseCode != 200) {
+ fprintf(stdout, "Failed to check symbol status.\n");
+ fprintf(stdout, "Response code: %d\n", responseCode);
+ fprintf(stdout, "Response:\n");
+ fprintf(stdout, "%s\n", [result UTF8String]);
+ return SymbolStatusUnknown;
+ }
+
+ error = nil;
+ NSRegularExpression* statusRegex = [NSRegularExpression
+ regularExpressionWithPattern:@"\"status\": \"([^\"]+)\""
+ options:0
+ error:&error];
+ NSArray* matches =
+ [statusRegex matchesInString:result
+ options:0
+ range:NSMakeRange(0, [result length])];
+ if ([matches count] != 1) {
+ fprintf(stdout, "Failed to parse check symbol status response.");
+ fprintf(stdout, "Response:\n");
+ fprintf(stdout, "%s\n", [result UTF8String]);
+ return SymbolStatusUnknown;
+ }
+
+ NSString* status = [result substringWithRange:[matches[0] rangeAtIndex:1]];
+ [result release];
+
+ return [status isEqualToString:@"FOUND"] ? SymbolStatusFound
+ : SymbolStatusMissing;
+}
+
+//=============================================================================
++ (UploadURLResponse*)createUploadURLOnServer:(NSString*)APIURL
+ withAPIKey:(NSString*)APIKey {
+ NSURL* URL = [NSURL
+ URLWithString:[NSString stringWithFormat:@"%@/v1/uploads:create?key=%@",
+ APIURL, APIKey]];
+
+ HTTPSimplePostRequest* postRequest =
+ [[HTTPSimplePostRequest alloc] initWithURL:URL];
+ NSError* error = nil;
+ NSData* data = [postRequest send:&error];
+ NSString* result = [[NSString alloc] initWithData:data
+ encoding:NSUTF8StringEncoding];
+ int responseCode = [[postRequest response] statusCode];
+ [postRequest release];
+
+ if (error || responseCode != 200) {
+ fprintf(stdout, "Failed to create upload URL.\n");
+ fprintf(stdout, "Response code: %d\n", responseCode);
+ fprintf(stdout, "Response:\n");
+ fprintf(stdout, "%s\n", [result UTF8String]);
+ return nil;
+ }
+
+ // Note camel-case rather than underscores.
+ NSRegularExpression* uploadURLRegex = [NSRegularExpression
+ regularExpressionWithPattern:@"\"uploadUrl\": \"([^\"]+)\""
+ options:0
+ error:&error];
+ NSRegularExpression* uploadKeyRegex = [NSRegularExpression
+ regularExpressionWithPattern:@"\"uploadKey\": \"([^\"]+)\""
+ options:0
+ error:&error];
+
+ NSArray* uploadURLMatches =
+ [uploadURLRegex matchesInString:result
+ options:0
+ range:NSMakeRange(0, [result length])];
+ NSArray* uploadKeyMatches =
+ [uploadKeyRegex matchesInString:result
+ options:0
+ range:NSMakeRange(0, [result length])];
+ if ([uploadURLMatches count] != 1 || [uploadKeyMatches count] != 1) {
+ fprintf(stdout, "Failed to parse create url response.");
+ fprintf(stdout, "Response:\n");
+ fprintf(stdout, "%s\n", [result UTF8String]);
+ return nil;
+ }
+ NSString* uploadURL =
+ [result substringWithRange:[uploadURLMatches[0] rangeAtIndex:1]];
+ NSString* uploadKey =
+ [result substringWithRange:[uploadKeyMatches[0] rangeAtIndex:1]];
+
+ return [[UploadURLResponse alloc] initWithUploadURL:uploadURL
+ withUploadKey:uploadKey];
+}
+
+//=============================================================================
++ (CompleteUploadResult)completeUploadOnServer:(NSString*)APIURL
+ withAPIKey:(NSString*)APIKey
+ withUploadKey:(NSString*)uploadKey
+ withDebugFile:(NSString*)debugFile
+ withDebugID:(NSString*)debugID {
+ NSURL* URL = [NSURL
+ URLWithString:[NSString
+ stringWithFormat:@"%@/v1/uploads/%@:complete?key=%@",
+ APIURL, uploadKey, APIKey]];
+ NSString* body =
+ [NSString stringWithFormat:
+ @"{ symbol_id: { debug_file: \"%@\", debug_id: \"%@\" } }",
+ debugFile, debugID];
+
+ HTTPSimplePostRequest* postRequest =
+ [[HTTPSimplePostRequest alloc] initWithURL:URL];
+ [postRequest setBody:body];
+ [postRequest setContentType:@"application/json"];
+
+ NSError* error = nil;
+ NSData* data = [postRequest send:&error];
+ NSString* result = [[NSString alloc] initWithData:data
+ encoding:NSUTF8StringEncoding];
+ int responseCode = [[postRequest response] statusCode];
+ [postRequest release];
+
+ if (error || responseCode != 200) {
+ fprintf(stdout, "Failed to complete upload URL.\n");
+ fprintf(stdout, "Response code: %d\n", responseCode);
+ fprintf(stdout, "Response:\n");
+ fprintf(stdout, "%s\n", [result UTF8String]);
+ return CompleteUploadResultError;
+ }
+
+ // Note camel-case rather than underscores.
+ NSRegularExpression* completeResultRegex = [NSRegularExpression
+ regularExpressionWithPattern:@"\"result\": \"([^\"]+)\""
+ options:0
+ error:&error];
+
+ NSArray* completeResultMatches =
+ [completeResultRegex matchesInString:result
+ options:0
+ range:NSMakeRange(0, [result length])];
+
+ if ([completeResultMatches count] != 1) {
+ fprintf(stdout, "Failed to parse complete upload response.");
+ fprintf(stdout, "Response:\n");
+ fprintf(stdout, "%s\n", [result UTF8String]);
+ return CompleteUploadResultError;
+ }
+ NSString* completeResult =
+ [result substringWithRange:[completeResultMatches[0] rangeAtIndex:1]];
+ [result release];
+
+ return ([completeResult isEqualToString:@"DUPLICATE_DATA"])
+ ? CompleteUploadResultDuplicateData
+ : CompleteUploadResultOk;
+}
+@end
diff --git a/src/common/mac/encoding_util.h b/src/common/mac/encoding_util.h
new file mode 100644
index 00000000..6495a742
--- /dev/null
+++ b/src/common/mac/encoding_util.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2020, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_BREAKPAD_COMMON_MAC_ENCODING_UTIL_H
+#define GOOGLE_BREAKPAD_COMMON_MAC_ENCODING_UTIL_H
+
+#import <Foundation/Foundation.h>
+
+// As -[NSString stringByAddingPercentEscapesUsingEncoding:] has been
+// deprecated with iOS 9.0 / OS X 10.11 SDKs, this function re-implements it
+// using -[NSString stringByAddingPercentEncodingWithAllowedCharacters:] when
+// using those SDKs.
+NSString* PercentEncodeNSString(NSString* key);
+
+#endif // GOOGLE_BREAKPAD_COMMON_MAC_ENCODING_UTIL_H
diff --git a/src/common/mac/encoding_util.m b/src/common/mac/encoding_util.m
new file mode 100644
index 00000000..86d70fb6
--- /dev/null
+++ b/src/common/mac/encoding_util.m
@@ -0,0 +1,47 @@
+// Copyright (c) 2020, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "encoding_util.h"
+
+#include <Availability.h>
+#include <AvailabilityMacros.h>
+#import <Foundation/Foundation.h>
+
+NSString* PercentEncodeNSString(NSString* key) {
+#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && defined(__IPHONE_9_0) && \
+ __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_9_0) || \
+ (defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \
+ defined(MAC_OS_X_VERSION_10_11) && \
+ MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11)
+ return [key stringByAddingPercentEncodingWithAllowedCharacters:
+ [NSCharacterSet URLQueryAllowedCharacterSet]];
+#else
+ return [key stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
+#endif
+}
diff --git a/src/common/mac/minidump_upload.m b/src/common/mac/minidump_upload.m
new file mode 100644
index 00000000..1fe4f213
--- /dev/null
+++ b/src/common/mac/minidump_upload.m
@@ -0,0 +1,135 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// minidump_upload.m: Upload a minidump to a HTTP server. The upload is sent as
+// a multipart/form-data POST request with the following parameters:
+// prod: the product name
+// ver: the product version
+// symbol_file: the breakpad format symbol file
+
+#import <unistd.h>
+
+#import <Foundation/Foundation.h>
+
+#import "common/mac/HTTPMultipartUpload.h"
+
+typedef struct {
+ NSString* minidumpPath;
+ NSString* uploadURLStr;
+ NSString* product;
+ NSString* version;
+ BOOL success;
+} Options;
+
+//=============================================================================
+static void Start(Options* options) {
+ NSURL* url = [NSURL URLWithString:options->uploadURLStr];
+ HTTPMultipartUpload* ul = [[HTTPMultipartUpload alloc] initWithURL:url];
+ NSMutableDictionary* parameters = [NSMutableDictionary dictionary];
+
+ // Add parameters
+ [parameters setObject:options->product forKey:@"prod"];
+ [parameters setObject:options->version forKey:@"ver"];
+ [ul setParameters:parameters];
+
+ // Add file
+ [ul addFileAtPath:options->minidumpPath name:@"upload_file_minidump"];
+
+ // Send it
+ NSError* error = nil;
+ NSData* data = [ul send:&error];
+ NSString* result = [[NSString alloc] initWithData:data
+ encoding:NSUTF8StringEncoding];
+
+ NSLog(@"Send: %@", error ? [error description] : @"No Error");
+ NSLog(@"Response: %ld", (long)[[ul response] statusCode]);
+ NSLog(@"Result: %lu bytes\n%@", (unsigned long)[data length], result);
+
+ [result release];
+ [ul release];
+ options->success = !error;
+}
+
+//=============================================================================
+static void Usage(int argc, const char* argv[]) {
+ fprintf(stderr, "Submit minidump information.\n");
+ fprintf(stderr,
+ "Usage: %s -p <product> -v <version> <minidump> "
+ "<upload-URL>\n",
+ argv[0]);
+ fprintf(stderr, "<minidump> should be a minidump.\n");
+ fprintf(stderr, "<upload-URL> is the destination for the upload\n");
+
+ fprintf(stderr, "\t-h: Usage\n");
+ fprintf(stderr, "\t-?: Usage\n");
+}
+
+//=============================================================================
+static void SetupOptions(int argc, const char* argv[], Options* options) {
+ extern int optind;
+ char ch;
+
+ while ((ch = getopt(argc, (char* const*)argv, "p:v:h?")) != -1) {
+ switch (ch) {
+ case 'p':
+ options->product = [NSString stringWithUTF8String:optarg];
+ break;
+ case 'v':
+ options->version = [NSString stringWithUTF8String:optarg];
+ break;
+
+ default:
+ Usage(argc, argv);
+ exit(0);
+ break;
+ }
+ }
+
+ if ((argc - optind) != 2) {
+ fprintf(stderr, "%s: Missing symbols file and/or upload-URL\n", argv[0]);
+ Usage(argc, argv);
+ exit(1);
+ }
+
+ options->minidumpPath = [NSString stringWithUTF8String:argv[optind]];
+ options->uploadURLStr = [NSString stringWithUTF8String:argv[optind + 1]];
+}
+
+//=============================================================================
+int main(int argc, const char* argv[]) {
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+ Options options;
+
+ bzero(&options, sizeof(Options));
+ SetupOptions(argc, argv, &options);
+ Start(&options);
+
+ [pool release];
+ return options.success ? 0 : 1;
+}