aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNelson Billing <nbilling@google.com>2020-07-22 14:44:06 -0700
committerNelson Billing <nbilling@google.com>2020-07-24 00:20:34 +0000
commit114336881a21459d2c7fab2de5e010b5faf55e55 (patch)
tree2c284a5e6e7f2d1cba5596505aab47f77646246c /src
parentThere are source files with APSL-2.0 as well. (diff)
downloadbreakpad-114336881a21459d2c7fab2de5e010b5faf55e55.tar.xz
Port new symbol API to symupload on Mac.
- See documentation in Linux implementation commit: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/1422400. Change-Id: If3ff256e63f2db3ac9c0be78cfc17754d532cb88 Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/1497653 Reviewed-by: Ivan Penkov <ivanpe@chromium.org>
Diffstat (limited to 'src')
-rw-r--r--src/common/mac/HTTPMultipartUpload.h34
-rw-r--r--src/common/mac/HTTPMultipartUpload.m156
-rw-r--r--src/tools/mac/symupload/HTTPGetRequest.h42
-rw-r--r--src/tools/mac/symupload/HTTPGetRequest.m39
-rw-r--r--src/tools/mac/symupload/HTTPPutRequest.h51
-rw-r--r--src/tools/mac/symupload/HTTPPutRequest.m62
-rw-r--r--src/tools/mac/symupload/HTTPRequest.h73
-rw-r--r--src/tools/mac/symupload/HTTPRequest.m214
-rw-r--r--src/tools/mac/symupload/HTTPSimplePostRequest.h57
-rw-r--r--src/tools/mac/symupload/HTTPSimplePostRequest.m69
-rw-r--r--src/tools/mac/symupload/SymbolCollectorClient.h100
-rw-r--r--src/tools/mac/symupload/SymbolCollectorClient.m247
-rw-r--r--src/tools/mac/symupload/symupload.m143
-rw-r--r--src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj44
-rw-r--r--src/tools/mac/symupload/util.h52
15 files changed, 1229 insertions, 154 deletions
diff --git a/src/common/mac/HTTPMultipartUpload.h b/src/common/mac/HTTPMultipartUpload.h
index 42e8fed3..5eaaa91b 100644
--- a/src/common/mac/HTTPMultipartUpload.h
+++ b/src/common/mac/HTTPMultipartUpload.h
@@ -27,35 +27,39 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// HTTPMultipartUpload: A multipart/form-data HTTP uploader.
-// Each parameter pair is sent as a boundary
-// Each file is sent with a name field in addition to the filename and data
-// The data will be sent synchronously.
+
#import <Foundation/Foundation.h>
-@interface HTTPMultipartUpload : NSObject {
+#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.
+ */
+@interface HTTPMultipartUpload : HTTPRequest {
@protected
- NSURL *url_; // The destination URL (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)
- NSHTTPURLResponse *response_; // The response from the send (STRONG)
}
-- (id)initWithURL:(NSURL *)url;
-
-- (NSURL *)URL;
-
+/**
+ Sets the parameters that will be sent in the multipart POST request.
+ */
- (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;
+
+/**
+ 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;
-// Set the data and return the response
-- (NSData *)send:(NSError **)error;
-- (NSHTTPURLResponse *)response;
-
@end
diff --git a/src/common/mac/HTTPMultipartUpload.m b/src/common/mac/HTTPMultipartUpload.m
index a3677f25..7fc474b8 100644
--- a/src/common/mac/HTTPMultipartUpload.m
+++ b/src/common/mac/HTTPMultipartUpload.m
@@ -28,67 +28,10 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import "HTTPMultipartUpload.h"
-#import "GTMDefines.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.
-static 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
-}
+#import "GTMDefines.h"
+#import "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 **out_response,
- NSError **out_error) {
-#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 wait_semaphone = dispatch_semaphore_create(0);
- [[[NSURLSession sharedSession]
- dataTaskWithRequest:req
- completionHandler:^(NSData *data,
- NSURLResponse *resp,
- NSError *err) {
- if (out_error)
- error = [err retain];
- if (out_response)
- response = [resp retain];
- if (err == nil)
- result = [data retain];
- dispatch_semaphore_signal(wait_semaphone);
- }] resume];
- dispatch_semaphore_wait(wait_semaphone, DISPATCH_TIME_FOREVER);
- dispatch_release(wait_semaphone);
- if (out_error)
- *out_error = [error autorelease];
- if (out_response)
- *out_response = [response autorelease];
- return [result autorelease];
-#else
- return [NSURLConnection sendSynchronousRequest:req
- returningResponse:out_response
- error:out_error];
-#endif
-}
@interface HTTPMultipartUpload(PrivateMethods)
- (NSString *)multipartBoundary;
// Each of the following methods will append the starting multipart boundary,
@@ -111,33 +54,24 @@ static NSData *SendSynchronousNSURLRequest(NSURLRequest *req,
//=============================================================================
- (NSData *)formDataForKey:(NSString *)key value:(NSString *)value {
+ NSMutableData* data = [NSMutableData data];
+ [self appendBoundaryData:data];
+
NSString *escaped = PercentEncodeNSString(key);
NSString *fmt =
- @"--%@\r\nContent-Disposition: form-data; name=\"%@\"\r\n\r\n%@\r\n";
+ @"Content-Disposition: form-data; name=\"%@\"\r\n\r\n%@\r\n";
NSString *form = [NSString stringWithFormat:fmt, boundary_, escaped, value];
- return [form dataUsingEncoding:NSUTF8StringEncoding];
-}
-
-//=============================================================================
-- (NSData *)formDataForFileContents:(NSData *)contents name:(NSString *)name {
- NSMutableData *data = [NSMutableData data];
- NSString *escaped = PercentEncodeNSString(name);
- NSString *fmt = @"--%@\r\nContent-Disposition: form-data; name=\"%@\"; "
- "filename=\"minidump.dmp\"\r\nContent-Type: application/octet-stream\r\n\r\n";
- NSString *pre = [NSString stringWithFormat:fmt, boundary_, escaped];
-
- [data appendData:[pre dataUsingEncoding:NSUTF8StringEncoding]];
- [data appendData:contents];
-
+ [data appendData:[form dataUsingEncoding:NSUTF8StringEncoding]];
return data;
}
//=============================================================================
-- (NSData *)formDataForFile:(NSString *)file name:(NSString *)name {
- NSData *contents = [NSData dataWithContentsOfFile:file];
+- (void)appendBoundaryData: (NSMutableData*)data {
+ NSString *fmt = @"--%@\r\n";
+ NSString *pre = [NSString stringWithFormat:fmt, boundary_];
- return [self formDataForFileContents:contents name:name];
+ [data appendData:[pre dataUsingEncoding:NSUTF8StringEncoding]];
}
//=============================================================================
@@ -145,8 +79,7 @@ static NSData *SendSynchronousNSURLRequest(NSURLRequest *req,
#pragma mark || Public ||
//=============================================================================
- (id)initWithURL:(NSURL *)url {
- if ((self = [super init])) {
- url_ = [url copy];
+ if ((self = [super initWithURL:url])) {
boundary_ = [[self multipartBoundary] retain];
files_ = [[NSMutableDictionary alloc] init];
}
@@ -156,21 +89,14 @@ static NSData *SendSynchronousNSURLRequest(NSURLRequest *req,
//=============================================================================
- (void)dealloc {
- [url_ release];
[parameters_ release];
[files_ release];
[boundary_ release];
- [response_ release];
[super dealloc];
}
//=============================================================================
-- (NSURL *)URL {
- return url_;
-}
-
-//=============================================================================
- (void)setParameters:(NSDictionary *)parameters {
if (parameters != parameters_) {
[parameters_ release];
@@ -199,17 +125,20 @@ static NSData *SendSynchronousNSURLRequest(NSURLRequest *req,
}
//=============================================================================
-- (NSData *)send:(NSError **)error {
- NSMutableURLRequest *req =
- [[NSMutableURLRequest alloc]
- initWithURL:url_ cachePolicy:NSURLRequestUseProtocolCachePolicy
- timeoutInterval:60.0];
+- (NSString*)HTTPMethod {
+ return @"POST";
+}
+
+//=============================================================================
+- (NSString*)contentType {
+ return [NSString stringWithFormat:@"multipart/form-data; boundary=%@",
+ boundary_];
+}
+//=============================================================================
+- (NSData*)bodyData {
NSMutableData *postBody = [NSMutableData data];
- [req setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",
- boundary_] forHTTPHeaderField:@"Content-type"];
-
// Add any parameters to the message
NSArray *parameterKeys = [parameters_ allKeys];
NSString *key;
@@ -224,44 +153,19 @@ static NSData *SendSynchronousNSURLRequest(NSURLRequest *req,
// Add any files to the message
NSArray *fileNames = [files_ allKeys];
for (NSString *name in fileNames) {
+ // First append boundary
+ [self appendBoundaryData:postBody];
+ // Then the formdata
id fileOrData = [files_ objectForKey:name];
- 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 name:name];
- else
- fileData = [self formDataForFile:fileOrData name:name];
-
- [postBody appendData:fileData];
+ [HTTPRequest appendFileToBodyData:postBody
+ withName:name
+ withFileOrData:fileOrData];
}
NSString *epilogue = [NSString stringWithFormat:@"\r\n--%@--\r\n", boundary_];
[postBody appendData:[epilogue dataUsingEncoding:NSUTF8StringEncoding]];
- [req setHTTPBody:postBody];
- [req setHTTPMethod:@"POST"];
-
- [response_ release];
- response_ = nil;
-
- NSData *data = nil;
- if ([[req URL] isFileURL]) {
- [[req HTTPBody] writeToURL:[req URL] options:0 error:error];
- } else {
- NSURLResponse *response = nil;
- data = SendSynchronousNSURLRequest(req, &response, error);
- response_ = (NSHTTPURLResponse *)[response retain];
- }
- [req release];
-
- return data;
-}
-
-//=============================================================================
-- (NSHTTPURLResponse *)response {
- return response_;
+ return postBody;
}
@end
diff --git a/src/tools/mac/symupload/HTTPGetRequest.h b/src/tools/mac/symupload/HTTPGetRequest.h
new file mode 100644
index 00000000..0da08474
--- /dev/null
+++ b/src/tools/mac/symupload/HTTPGetRequest.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2019, 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/tools/mac/symupload/HTTPGetRequest.m b/src/tools/mac/symupload/HTTPGetRequest.m
new file mode 100644
index 00000000..a3a252ab
--- /dev/null
+++ b/src/tools/mac/symupload/HTTPGetRequest.m
@@ -0,0 +1,39 @@
+// Copyright (c) 2019, 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/tools/mac/symupload/HTTPPutRequest.h b/src/tools/mac/symupload/HTTPPutRequest.h
new file mode 100644
index 00000000..f316212b
--- /dev/null
+++ b/src/tools/mac/symupload/HTTPPutRequest.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2019, 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/tools/mac/symupload/HTTPPutRequest.m b/src/tools/mac/symupload/HTTPPutRequest.m
new file mode 100644
index 00000000..b64caae5
--- /dev/null
+++ b/src/tools/mac/symupload/HTTPPutRequest.m
@@ -0,0 +1,62 @@
+// Copyright (c) 2019, 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/tools/mac/symupload/HTTPRequest.h b/src/tools/mac/symupload/HTTPRequest.h
new file mode 100644
index 00000000..ef2f86bc
--- /dev/null
+++ b/src/tools/mac/symupload/HTTPRequest.h
@@ -0,0 +1,73 @@
+// Copyright (c) 2019, 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/tools/mac/symupload/HTTPRequest.m b/src/tools/mac/symupload/HTTPRequest.m
new file mode 100644
index 00000000..9cafe13e
--- /dev/null
+++ b/src/tools/mac/symupload/HTTPRequest.m
@@ -0,0 +1,214 @@
+// Copyright (c) 2019, 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"
+
+#import "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/tools/mac/symupload/HTTPSimplePostRequest.h b/src/tools/mac/symupload/HTTPSimplePostRequest.h
new file mode 100644
index 00000000..4b542b45
--- /dev/null
+++ b/src/tools/mac/symupload/HTTPSimplePostRequest.h
@@ -0,0 +1,57 @@
+// Copyright (c) 2019, 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/tools/mac/symupload/HTTPSimplePostRequest.m b/src/tools/mac/symupload/HTTPSimplePostRequest.m
new file mode 100644
index 00000000..ef5ef334
--- /dev/null
+++ b/src/tools/mac/symupload/HTTPSimplePostRequest.m
@@ -0,0 +1,69 @@
+// Copyright (c) 2019, 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/tools/mac/symupload/SymbolCollectorClient.h b/src/tools/mac/symupload/SymbolCollectorClient.h
new file mode 100644
index 00000000..ef2029e4
--- /dev/null
+++ b/src/tools/mac/symupload/SymbolCollectorClient.h
@@ -0,0 +1,100 @@
+// Copyright (c) 2019, 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 CreateUploadURL 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 CompleteUpload call.
+ */
+typedef NS_ENUM(NSInteger, CompleteUploadResult) {
+ CompleteUploadResultOk,
+ CompleteUploadResultDuplicateData,
+ CompleteUploadResultError
+};
+
+/**
+ Possible return statuses from a sym-upload-v2 server to a CheckSymbolStatus
+ 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;
+
+/**
+ Call the CheckSymbolstatus API on the server.
+ */
++ (SymbolStatus)CheckSymbolStatus:(NSString*)APIURL
+ withAPIKey:(NSString*)APIKey
+ withDebugFile:(NSString*)debugFile
+ withDebugID:(NSString*)debugID;
+
+/**
+ Call the CreateUploadURL API on the server.
+ */
++ (UploadURLResponse*)CreateUploadURL:(NSString*)APIURL
+ withAPIKey:(NSString*)APIKey;
+
+/**
+ Call the CompleteUpload API on the server.
+ */
++ (CompleteUploadResult)CompleteUpload:(NSString*)APIURL
+ withAPIKey:(NSString*)APIKey
+ withUploadKey:(NSString*)uploadKey
+ withDebugFile:(NSString*)debugFile
+ withDebugID:(NSString*)debugID;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/src/tools/mac/symupload/SymbolCollectorClient.m b/src/tools/mac/symupload/SymbolCollectorClient.m
new file mode 100644
index 00000000..38103ccb
--- /dev/null
+++ b/src/tools/mac/symupload/SymbolCollectorClient.m
@@ -0,0 +1,247 @@
+// Copyright (c) 2019, 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)CheckSymbolStatus:(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 *)CreateUploadURL:(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)CompleteUpload:(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 nil;
+ }
+ NSString* completeResult = [result
+ substringWithRange:[completeResultMatches[0]
+ rangeAtIndex:1]];
+ [result release];
+
+ return ([completeResult isEqualToString:@"DUPLICATE_DATA"]) ?
+ CompleteUploadResultDuplicateData :
+ CompleteUploadResultOk;
+}
+@end
diff --git a/src/tools/mac/symupload/symupload.m b/src/tools/mac/symupload/symupload.m
index a7cce7b0..a87dd4ea 100644
--- a/src/tools/mac/symupload/symupload.m
+++ b/src/tools/mac/symupload/symupload.m
@@ -43,11 +43,22 @@
#include <unistd.h>
#include <Foundation/Foundation.h>
+
#include "HTTPMultipartUpload.h"
+#include "HTTPPutRequest.h"
+#include "SymbolCollectorClient.h"
+
+typedef enum {
+ SymUploadProtocolV1,
+ SymUploadProtocolV2
+} SymUploadProtocol;
typedef struct {
NSString *symbolsPath;
NSString *uploadURLStr;
+ SymUploadProtocol symUploadProtocol;
+ NSString* apiKey;
+ BOOL force;
BOOL success;
} Options;
@@ -84,15 +95,12 @@ static NSArray *ModuleDataForSymbolFile(NSString *file) {
}
//=============================================================================
-static void Start(Options *options) {
+static void StartSymUploadProtocolV1(Options* options,
+ NSArray* moduleParts,
+ NSString* compactedID) {
NSURL *url = [NSURL URLWithString:options->uploadURLStr];
HTTPMultipartUpload *ul = [[HTTPMultipartUpload alloc] initWithURL:url];
NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
- NSArray *moduleParts = ModuleDataForSymbolFile(options->symbolsPath);
- NSMutableString *compactedID =
- [NSMutableString stringWithString:[moduleParts objectAtIndex:3]];
- [compactedID replaceOccurrencesOfString:@"-" withString:@"" options:0
- range:NSMakeRange(0, [compactedID length])];
// Add parameters
[parameters setObject:compactedID forKey:@"debug_identifier"];
@@ -136,12 +144,105 @@ static void Start(Options *options) {
}
//=============================================================================
+static void StartSymUploadProtocolV2(Options* options,
+ NSString* debugFile,
+ NSString* debugID) {
+ if (!options->force) {
+ SymbolStatus symbolStatus = [SymbolCollectorClient
+ CheckSymbolStatus:options->uploadURLStr
+ withAPIKey:options->apiKey
+ withDebugFile:debugFile
+ withDebugID:debugID];
+ if (symbolStatus == SymbolStatusFound) {
+ fprintf(stdout, "Symbol file already exists, upload aborted."
+ " Use \"-f\" to overwrite.\n");
+ options->success = YES;
+ return;
+ } else if (symbolStatus == SymbolStatusUnknown) {
+ fprintf(stdout, "Failed to get check for existing symbol.\n");
+ return;
+ }
+ }
+
+ UploadURLResponse* URLResponse = [SymbolCollectorClient
+ CreateUploadURL:options->uploadURLStr
+ withAPIKey:options->apiKey];
+ if (URLResponse == nil) {
+ return;
+ }
+
+ NSURL* uploadURL = [NSURL URLWithString:[URLResponse uploadURL]];
+ HTTPPutRequest* putRequest = [[HTTPPutRequest alloc]
+ initWithURL:uploadURL];
+ [putRequest setFile:options->symbolsPath];
+
+ NSError *error = nil;
+ NSData* data = [putRequest send:&error];
+ NSString *result = [[NSString alloc] initWithData:data
+ encoding:NSUTF8StringEncoding];
+ int responseCode = [[putRequest response] statusCode];
+ [putRequest release];
+
+ if (error || responseCode != 200) {
+ fprintf(stdout, "Failed to upload symbol file.\n");
+ fprintf(stdout, "Response code: %d\n", responseCode);
+ fprintf(stdout, "Response:\n");
+ fprintf(stdout, "%s\n", [result UTF8String]);
+ return;
+ }
+
+ CompleteUploadResult completeUploadResult = [SymbolCollectorClient
+ CompleteUpload:options->uploadURLStr
+ withAPIKey:options->apiKey
+ withUploadKey:[URLResponse uploadKey]
+ withDebugFile:debugFile
+ withDebugID:debugID];
+ [URLResponse release];
+ if (completeUploadResult == CompleteUploadResultError) {
+ fprintf(stdout, "Failed to complete upload.\n");
+ return;
+ } else if (completeUploadResult == CompleteUploadResultDuplicateData) {
+ fprintf(stdout, "Uploaded file checksum matched existing file checksum,"
+ " no change necessary.\n");
+ } else {
+ fprintf(stdout, "Successfully sent the symbol file.\n");
+ }
+ options->success = YES;
+}
+
+//=============================================================================
+static void Start(Options *options) {
+ NSArray *moduleParts = ModuleDataForSymbolFile(options->symbolsPath);
+ NSMutableString *compactedID =
+ [NSMutableString stringWithString:[moduleParts objectAtIndex:3]];
+ [compactedID replaceOccurrencesOfString:@"-" withString:@"" options:0
+ range:NSMakeRange(0, [compactedID length])];
+
+ if (options->symUploadProtocol == SymUploadProtocolV1) {
+ StartSymUploadProtocolV1(options, moduleParts, compactedID);
+ } else if (options->symUploadProtocol == SymUploadProtocolV2) {
+ StartSymUploadProtocolV2(options,
+ [moduleParts objectAtIndex:4],
+ compactedID);
+ }
+}
+
+//=============================================================================
static void
Usage(int argc, const char *argv[]) {
fprintf(stderr, "Submit symbol information.\n");
- fprintf(stderr, "Usage: %s <symbols> <upload-URL>\n", argv[0]);
- fprintf(stderr, "<symbols> should be created by using the dump_syms tool.\n");
- fprintf(stderr, "<upload-URL> is the destination for the upload\n");
+ fprintf(stderr, "Usage: %s [options] <symbol-file> <upload-URL>\n", argv[0]);
+ fprintf(stderr, "<symbol-file> should be created by using the dump_syms "
+ "tool.\n");
+ fprintf(stderr, "<upload-URL> is the destination for the upload.\n");
+ fprintf(stderr, "Options:\n");
+ fprintf(stderr, "\t-p <protocol>: protocol to use for upload, accepts "
+ "[\"sym-upload-v1\", \"sym-upload-v2\"]. Default is "
+ "\"sym-upload-v1\".\n");
+ fprintf(stderr, "\t-k <api-key>: secret for authentication with upload "
+ "server. [Only in sym-upload-v2 protocol mode]\n");
+ fprintf(stderr, "\t-f: Overwrite symbol file on server if already present. "
+ "[Only in sym-upload-v2 protocol mode]\n");
fprintf(stderr, "\t-h: Usage\n");
fprintf(stderr, "\t-?: Usage\n");
}
@@ -149,11 +250,33 @@ Usage(int argc, const char *argv[]) {
//=============================================================================
static void
SetupOptions(int argc, const char *argv[], Options *options) {
+ // Set default value of symUploadProtocol.
+ options->symUploadProtocol = SymUploadProtocolV1;
+
extern int optind;
char ch;
- while ((ch = getopt(argc, (char * const *)argv, "h?")) != -1) {
+ while ((ch = getopt(argc, (char * const *)argv, "p:k:hf?")) != -1) {
switch (ch) {
+ case 'p':
+ if (strcmp(optarg, "sym-upload-v2") == 0) {
+ options->symUploadProtocol = SymUploadProtocolV2;
+ break;
+ } else if (strcmp(optarg, "sym-upload-v1") == 0) {
+ // This is already the default but leave in case that changes.
+ options->symUploadProtocol = SymUploadProtocolV1;
+ break;
+ }
+ Usage(argc, argv);
+ exit(0);
+ break;
+ case 'k':
+ options->apiKey = [NSString stringWithCString:optarg
+ encoding:NSASCIIStringEncoding];
+ break;
+ case 'f':
+ options->force = YES;
+ break;
default:
Usage(argc, argv);
exit(0);
diff --git a/src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj b/src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj
index a6a78dc5..edf7b1a0 100644
--- a/src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj
+++ b/src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj
@@ -7,6 +7,11 @@
objects = {
/* Begin PBXBuildFile section */
+ 5B6060BD222716FC0015F0A0 /* HTTPRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B6060BC222716FC0015F0A0 /* HTTPRequest.m */; };
+ 5B6060C02227201B0015F0A0 /* HTTPPutRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B6060BF2227201B0015F0A0 /* HTTPPutRequest.m */; };
+ 5B6060C7222735E50015F0A0 /* HTTPGetRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B6060C6222735E50015F0A0 /* HTTPGetRequest.m */; };
+ 5B6060CA2227374E0015F0A0 /* HTTPSimplePostRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B6060C92227374E0015F0A0 /* HTTPSimplePostRequest.m */; };
+ 5B6060D022273BDA0015F0A0 /* SymbolCollectorClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B6060CF22273BDA0015F0A0 /* SymbolCollectorClient.m */; };
8B31022C11F0CEBD00FCF3E4 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; };
8DD76F9A0486AA7600D96B5E /* symupload.m in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* symupload.m */; settings = {ATTRIBUTES = (); }; };
8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; };
@@ -30,14 +35,25 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
- 08FB7796FE84155DC02AAC07 /* symupload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = symupload.m; sourceTree = "<group>"; };
+ 08FB7796FE84155DC02AAC07 /* symupload.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = symupload.m; sourceTree = "<group>"; tabWidth = 2; };
08FB779EFE84155DC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
+ 5B6060BB222716FC0015F0A0 /* HTTPRequest.h */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = HTTPRequest.h; sourceTree = "<group>"; tabWidth = 2; };
+ 5B6060BC222716FC0015F0A0 /* HTTPRequest.m */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = HTTPRequest.m; sourceTree = "<group>"; tabWidth = 2; };
+ 5B6060BE2227201B0015F0A0 /* HTTPPutRequest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HTTPPutRequest.h; sourceTree = "<group>"; };
+ 5B6060BF2227201B0015F0A0 /* HTTPPutRequest.m */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = HTTPPutRequest.m; sourceTree = "<group>"; tabWidth = 2; };
+ 5B6060C22227303A0015F0A0 /* util.h */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = util.h; sourceTree = "<group>"; tabWidth = 2; };
+ 5B6060C5222735E50015F0A0 /* HTTPGetRequest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HTTPGetRequest.h; sourceTree = "<group>"; };
+ 5B6060C6222735E50015F0A0 /* HTTPGetRequest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HTTPGetRequest.m; sourceTree = "<group>"; };
+ 5B6060C82227374E0015F0A0 /* HTTPSimplePostRequest.h */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = HTTPSimplePostRequest.h; sourceTree = "<group>"; tabWidth = 2; };
+ 5B6060C92227374E0015F0A0 /* HTTPSimplePostRequest.m */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = HTTPSimplePostRequest.m; sourceTree = "<group>"; tabWidth = 2; };
+ 5B6060CE22273BDA0015F0A0 /* SymbolCollectorClient.h */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = SymbolCollectorClient.h; sourceTree = "<group>"; tabWidth = 2; };
+ 5B6060CF22273BDA0015F0A0 /* SymbolCollectorClient.m */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = SymbolCollectorClient.m; sourceTree = "<group>"; tabWidth = 2; };
8B31022B11F0CE6900FCF3E4 /* Breakpad.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Breakpad.xcconfig; path = ../../../common/mac/Breakpad.xcconfig; sourceTree = SOURCE_ROOT; };
8B3102B611F0D5CE00FCF3E4 /* BreakpadDebug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = BreakpadDebug.xcconfig; path = ../../../common/mac/BreakpadDebug.xcconfig; sourceTree = SOURCE_ROOT; };
8B3102B711F0D5CE00FCF3E4 /* BreakpadRelease.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = BreakpadRelease.xcconfig; path = ../../../common/mac/BreakpadRelease.xcconfig; sourceTree = SOURCE_ROOT; };
8DD76FA10486AA7600D96B5E /* symupload */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = symupload; sourceTree = BUILT_PRODUCTS_DIR; };
- 9BD833680B03E4080055103E /* HTTPMultipartUpload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTTPMultipartUpload.h; path = ../../../common/mac/HTTPMultipartUpload.h; sourceTree = "<group>"; };
- 9BD833690B03E4080055103E /* HTTPMultipartUpload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HTTPMultipartUpload.m; path = ../../../common/mac/HTTPMultipartUpload.m; sourceTree = "<group>"; };
+ 9BD833680B03E4080055103E /* HTTPMultipartUpload.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = HTTPMultipartUpload.h; path = ../../../common/mac/HTTPMultipartUpload.h; sourceTree = "<group>"; tabWidth = 2; };
+ 9BD833690B03E4080055103E /* HTTPMultipartUpload.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; name = HTTPMultipartUpload.m; path = ../../../common/mac/HTTPMultipartUpload.m; sourceTree = "<group>"; tabWidth = 2; };
9BD835FB0B0544950055103E /* minidump_upload */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = minidump_upload; sourceTree = BUILT_PRODUCTS_DIR; };
9BD836000B0544BA0055103E /* minidump_upload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = minidump_upload.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
@@ -65,6 +81,17 @@
08FB7794FE84155DC02AAC07 /* symupload */ = {
isa = PBXGroup;
children = (
+ 5B6060CE22273BDA0015F0A0 /* SymbolCollectorClient.h */,
+ 5B6060CF22273BDA0015F0A0 /* SymbolCollectorClient.m */,
+ 5B6060C82227374E0015F0A0 /* HTTPSimplePostRequest.h */,
+ 5B6060C92227374E0015F0A0 /* HTTPSimplePostRequest.m */,
+ 5B6060C5222735E50015F0A0 /* HTTPGetRequest.h */,
+ 5B6060C6222735E50015F0A0 /* HTTPGetRequest.m */,
+ 5B6060C22227303A0015F0A0 /* util.h */,
+ 5B6060BE2227201B0015F0A0 /* HTTPPutRequest.h */,
+ 5B6060BF2227201B0015F0A0 /* HTTPPutRequest.m */,
+ 5B6060BB222716FC0015F0A0 /* HTTPRequest.h */,
+ 5B6060BC222716FC0015F0A0 /* HTTPRequest.m */,
8B31022B11F0CE6900FCF3E4 /* Breakpad.xcconfig */,
8B3102B611F0D5CE00FCF3E4 /* BreakpadDebug.xcconfig */,
8B3102B711F0D5CE00FCF3E4 /* BreakpadRelease.xcconfig */,
@@ -137,9 +164,15 @@
/* Begin PBXProject section */
08FB7793FE84155DC02AAC07 /* Project object */ = {
isa = PBXProject;
+ attributes = {
+ };
buildConfigurationList = 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "symupload" */;
compatibilityVersion = "Xcode 3.1";
+ developmentRegion = en;
hasScannedForEncodings = 1;
+ knownRegions = (
+ en,
+ );
mainGroup = 08FB7794FE84155DC02AAC07 /* symupload */;
projectDirPath = "";
projectRoot = "";
@@ -156,6 +189,11 @@
buildActionMask = 2147483647;
files = (
8DD76F9A0486AA7600D96B5E /* symupload.m in Sources */,
+ 5B6060CA2227374E0015F0A0 /* HTTPSimplePostRequest.m in Sources */,
+ 5B6060D022273BDA0015F0A0 /* SymbolCollectorClient.m in Sources */,
+ 5B6060C7222735E50015F0A0 /* HTTPGetRequest.m in Sources */,
+ 5B6060C02227201B0015F0A0 /* HTTPPutRequest.m in Sources */,
+ 5B6060BD222716FC0015F0A0 /* HTTPRequest.m in Sources */,
9BD8336B0B03E4080055103E /* HTTPMultipartUpload.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
diff --git a/src/tools/mac/symupload/util.h b/src/tools/mac/symupload/util.h
new file mode 100644
index 00000000..67112868
--- /dev/null
+++ b/src/tools/mac/symupload/util.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2019, 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 util_h
+#define 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.
+static 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
+}
+
+#endif /* util_h */