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>
This commit is contained in:
Nelson Billing
2020-07-29 16:28:25 -07:00
parent 28d7cbdd42
commit a740aa2625
17 changed files with 426 additions and 404 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
}

View File

@@ -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;
}