aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/ios/Breakpad.h5
-rw-r--r--src/client/ios/Breakpad.mm35
-rw-r--r--src/client/mac/Breakpad.xcodeproj/project.pbxproj8
-rw-r--r--src/client/mac/sender/uploader.h10
-rw-r--r--src/client/mac/sender/uploader.mm (renamed from src/client/mac/sender/uploader.m)226
5 files changed, 178 insertions, 106 deletions
diff --git a/src/client/ios/Breakpad.h b/src/client/ios/Breakpad.h
index 685dea32..1483e860 100644
--- a/src/client/ios/Breakpad.h
+++ b/src/client/ios/Breakpad.h
@@ -196,6 +196,11 @@ bool BreakpadHasCrashReportToUpload(BreakpadRef ref);
// Upload next report to the server.
void BreakpadUploadNextReport(BreakpadRef ref);
+// Upload a file to the server. |data| is the content of the file to sent.
+// |server_parameters| is additional server parameters to send.
+void BreakpadUploadData(BreakpadRef ref, NSData *data,
+ NSDictionary *server_parameters);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/client/ios/Breakpad.mm b/src/client/ios/Breakpad.mm
index d2f5652f..0b9cabbb 100644
--- a/src/client/ios/Breakpad.mm
+++ b/src/client/ios/Breakpad.mm
@@ -152,6 +152,7 @@ class Breakpad {
void RemoveKeyValue(NSString *key);
NSString *NextCrashReportToUpload();
void UploadNextReport();
+ void UploadData(NSData *data, NSDictionary *server_parameters);
private:
Breakpad()
@@ -426,6 +427,25 @@ void Breakpad::UploadNextReport() {
}
//=============================================================================
+void Breakpad::UploadData(NSData *data, NSDictionary *server_parameters) {
+ NSMutableDictionary *config = [NSMutableDictionary dictionary];
+
+ SimpleStringDictionaryIterator it(*config_params_);
+ while (const KeyValueEntry *next = it.Next()) {
+ [config setValue:[NSString stringWithUTF8String:next->GetValue()]
+ forKey:[NSString stringWithUTF8String:next->GetKey()]];
+ }
+
+ Uploader *uploader =
+ [[[Uploader alloc] initWithConfig:config] autorelease];
+ for (NSString *key in server_parameters) {
+ [uploader addServerParameter:[server_parameters objectForKey:key]
+ forKey:key];
+ }
+ [uploader uploadData:data];
+}
+
+//=============================================================================
bool Breakpad::HandleMinidump(const char *dump_dir,
const char *minidump_id) {
DEBUGLOG(stderr, "Breakpad: a minidump has been created.\n");
@@ -681,3 +701,18 @@ void BreakpadUploadNextReport(BreakpadRef ref) {
fprintf(stderr, "BreakpadUploadNextReport() : error\n");
}
}
+
+//=============================================================================
+void BreakpadUploadData(BreakpadRef ref, NSData *data,
+ NSDictionary *server_parameters) {
+ try {
+ // Not called at exception time
+ Breakpad *breakpad = (Breakpad *)ref;
+
+ if (breakpad) {
+ breakpad->UploadData(data, server_parameters);
+ }
+ } catch(...) { // don't let exceptions leave this C API
+ fprintf(stderr, "BreakpadUploadData() : error\n");
+ }
+}
diff --git a/src/client/mac/Breakpad.xcodeproj/project.pbxproj b/src/client/mac/Breakpad.xcodeproj/project.pbxproj
index c927c7a7..848d4f52 100644
--- a/src/client/mac/Breakpad.xcodeproj/project.pbxproj
+++ b/src/client/mac/Breakpad.xcodeproj/project.pbxproj
@@ -38,8 +38,8 @@
163201D61443019E00C4DBF5 /* ConfigFile.h in Headers */ = {isa = PBXBuildFile; fileRef = 163201D41443019E00C4DBF5 /* ConfigFile.h */; };
163201D71443019E00C4DBF5 /* ConfigFile.mm in Sources */ = {isa = PBXBuildFile; fileRef = 163201D51443019E00C4DBF5 /* ConfigFile.mm */; };
163201E31443029300C4DBF5 /* ConfigFile.mm in Sources */ = {isa = PBXBuildFile; fileRef = 163201D51443019E00C4DBF5 /* ConfigFile.mm */; };
- 163202451443201300C4DBF5 /* uploader.m in Sources */ = {isa = PBXBuildFile; fileRef = 163202441443201300C4DBF5 /* uploader.m */; };
1632058314442E9000C4DBF5 /* BreakpadDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 1632058214442E9000C4DBF5 /* BreakpadDefines.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 16E02DB8147410F0008C604D /* uploader.mm in Sources */ = {isa = PBXBuildFile; fileRef = 16E02DB4147410D4008C604D /* uploader.mm */; };
3329D4ED0FA16D820007BBC5 /* Breakpad.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3329D4EC0FA16D820007BBC5 /* Breakpad.xib */; };
33880C800F9E097100817F82 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 33880C7E0F9E097100817F82 /* InfoPlist.strings */; };
4084699D0F5D9CF900FDCA37 /* crash_report_sender.icns in Resources */ = {isa = PBXBuildFile; fileRef = 4084699C0F5D9CF900FDCA37 /* crash_report_sender.icns */; };
@@ -552,8 +552,8 @@
163201D41443019E00C4DBF5 /* ConfigFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ConfigFile.h; path = crash_generation/ConfigFile.h; sourceTree = "<group>"; };
163201D51443019E00C4DBF5 /* ConfigFile.mm */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; name = ConfigFile.mm; path = crash_generation/ConfigFile.mm; sourceTree = "<group>"; };
163202431443201300C4DBF5 /* uploader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = uploader.h; path = sender/uploader.h; sourceTree = "<group>"; };
- 163202441443201300C4DBF5 /* uploader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = uploader.m; path = sender/uploader.m; sourceTree = "<group>"; };
1632058214442E9000C4DBF5 /* BreakpadDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BreakpadDefines.h; path = Framework/BreakpadDefines.h; sourceTree = "<group>"; };
+ 16E02DB4147410D4008C604D /* uploader.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = uploader.mm; path = sender/uploader.mm; sourceTree = "<group>"; };
32DBCF5E0370ADEE00C91783 /* Breakpad_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Breakpad_Prefix.pch; path = Framework/Breakpad_Prefix.pch; sourceTree = "<group>"; };
3329D4EC0FA16D820007BBC5 /* Breakpad.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Breakpad.xib; path = sender/Breakpad.xib; sourceTree = "<group>"; };
33880C7F0F9E097100817F82 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = sender/English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
@@ -998,8 +998,8 @@
F92C56A60ECE04B6009BE4BA /* sender */ = {
isa = PBXGroup;
children = (
+ 16E02DB4147410D4008C604D /* uploader.mm */,
163202431443201300C4DBF5 /* uploader.h */,
- 163202441443201300C4DBF5 /* uploader.m */,
F9B6309F100FF96B00D0F4AC /* goArrow.png */,
F92C56A70ECE04C5009BE4BA /* crash_report_sender.h */,
F92C56A80ECE04C5009BE4BA /* crash_report_sender.m */,
@@ -1741,7 +1741,7 @@
F9C44EA20EF09F93003AEBAA /* HTTPMultipartUpload.m in Sources */,
F92C56A90ECE04C5009BE4BA /* crash_report_sender.m in Sources */,
F9C44EE90EF0A3C1003AEBAA /* GTMLogger.m in Sources */,
- 163202451443201300C4DBF5 /* uploader.m in Sources */,
+ 16E02DB8147410F0008C604D /* uploader.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/src/client/mac/sender/uploader.h b/src/client/mac/sender/uploader.h
index af1c19fc..318165c9 100644
--- a/src/client/mac/sender/uploader.h
+++ b/src/client/mac/sender/uploader.h
@@ -44,7 +44,6 @@ extern NSString *const kDefaultServerType;
@interface Uploader : NSObject {
@private
- int configFile_; // File descriptor for config file
NSMutableDictionary *parameters_; // Key value pairs of data (STRONG)
NSData *minidumpContents_; // The data in the minidump (STRONG)
NSData *logFileData_; // An NSdata for the tar,
@@ -66,8 +65,17 @@ extern NSString *const kDefaultServerType;
- (id)initWithConfigFile:(const char *)configFile;
+- (id)initWithConfig:(NSDictionary *)config;
+
- (NSMutableDictionary *)parameters;
- (void)report;
+// Upload the given data to the crash server.
+- (void)uploadData:(NSData *)data name:(NSString *)name;
+
+// This method adds a key/value pair to the dictionary that
+// will be uploaded to the crash server.
+- (void)addServerParameter:(id)value forKey:(NSString *)key;
+
@end
diff --git a/src/client/mac/sender/uploader.m b/src/client/mac/sender/uploader.mm
index f215018e..0e084fb1 100644
--- a/src/client/mac/sender/uploader.m
+++ b/src/client/mac/sender/uploader.mm
@@ -52,12 +52,99 @@ NSString *const kDefaultServerType = @"google";
#pragma mark -
+namespace {
+// Read one line from the configuration file.
+NSString *readString(int fileId) {
+ NSMutableString *str = [NSMutableString stringWithCapacity:32];
+ char ch[2] = { 0 };
+
+ while (read(fileId, &ch[0], 1) == 1) {
+ if (ch[0] == '\n') {
+ // Break if this is the first newline after reading some other string
+ // data.
+ if ([str length])
+ break;
+ } else {
+ [str appendString:[NSString stringWithUTF8String:ch]];
+ }
+ }
+
+ return str;
+}
+
+//=============================================================================
+// Read |length| of binary data from the configuration file. This method will
+// returns |nil| in case of error.
+NSData *readData(int fileId, ssize_t length) {
+ NSMutableData *data = [NSMutableData dataWithLength:length];
+ char *bytes = (char *)[data bytes];
+
+ if (read(fileId, bytes, length) != length)
+ return nil;
+
+ return data;
+}
+
+//=============================================================================
+// Read the configuration from the config file.
+NSDictionary *readConfigurationData(const char *configFile) {
+ int fileId = open(configFile, O_RDONLY, 0600);
+ if (fileId == -1) {
+ GTMLoggerDebug(@"Couldn't open config file %s - %s",
+ configFile,
+ strerror(errno));
+ }
+
+ // we want to avoid a build-up of old config files even if they
+ // have been incorrectly written by the framework
+ if (unlink(configFile)) {
+ GTMLoggerDebug(@"Couldn't unlink config file %s - %s",
+ configFile,
+ strerror(errno));
+ }
+
+ if (fileId == -1) {
+ return nil;
+ }
+
+ NSMutableDictionary *config = [NSMutableDictionary dictionary];
+
+ while (1) {
+ NSString *key = readString(fileId);
+
+ if (![key length])
+ break;
+
+ // Read the data. Try to convert to a UTF-8 string, or just save
+ // the data
+ NSString *lenStr = readString(fileId);
+ ssize_t len = [lenStr intValue];
+ NSData *data = readData(fileId, len);
+ id value = [[NSString alloc] initWithData:data
+ encoding:NSUTF8StringEncoding];
+
+ [config setObject:(value ? value : data) forKey:key];
+ [value release];
+ }
+
+ close(fileId);
+ return config;
+}
+} // namespace
+
+#pragma mark -
+
@interface Uploader(PrivateMethods)
-- (NSString *)readString;
-- (NSData *)readData:(ssize_t)length;
-- (BOOL)readConfigurationData;
+// Update |parameters_| as well as the server parameters using |config|.
+- (void)translateConfigurationData:(NSDictionary *)config;
+
+// Read the minidump referenced in |parameters_| and update |minidumpContents_|
+// with its content.
- (BOOL)readMinidumpData;
+
+// Read the log files referenced in |parameters_| and update |logFileData_|
+// with their content.
- (BOOL)readLogFileData;
// Returns a unique client id (user-specific), creating a persistent
@@ -80,41 +167,24 @@ NSString *const kDefaultServerType = @"google";
// Accessor method for the URL parameter dictionary
- (NSMutableDictionary *)urlParameterDictionary;
-// This method adds a key/value pair to the dictionary that
-// will be uploaded to the crash server.
-- (void)addServerParameter:(id)value forKey:(NSString *)key;
-
// Records the uploaded crash ID to the log file.
- (void)logUploadWithID:(const char *)uploadID;
-
@end
@implementation Uploader
//=============================================================================
- (id)initWithConfigFile:(const char *)configFile {
- if ((self = [super init])) {
-
- configFile_ = open(configFile, O_RDONLY, 0600);
- if (configFile_ == -1) {
- GTMLoggerDebug(@"Couldn't open config file %s - %s",
- configFile,
- strerror(errno));
- }
-
- // we want to avoid a build-up of old config files even if they
- // have been incorrectly written by the framework
- if (unlink(configFile)) {
- GTMLoggerDebug(@"Couldn't unlink config file %s - %s",
- configFile,
- strerror(errno));
- }
+ NSDictionary *config = readConfigurationData(configFile);
+ if (!config)
+ return nil;
- if (configFile_ == -1) {
- [self release];
- return nil;
- }
+ return [self initWithConfig:config];
+}
+//=============================================================================
+- (id)initWithConfig:(NSDictionary *)config {
+ if ((self = [super init])) {
// Because the reporter is embedded in the framework (and many copies
// of the framework may exist) its not completely certain that the OS
// will obey the com.apple.PreferenceSync.ExcludeAllSyncKeys in our
@@ -126,68 +196,21 @@ NSString *const kDefaultServerType = @"google";
[self createServerParameterDictionaries];
- if (![self readConfigurationData]) {
- GTMLoggerDebug(@"uploader readConfigurationData failed");
- [self release];
- return nil;
- }
+ [self translateConfigurationData:config];
// Read the minidump into memory.
[self readMinidumpData];
[self readLogFileData];
-
}
return self;
}
//=============================================================================
-- (NSString *)readString {
- NSMutableString *str = [NSMutableString stringWithCapacity:32];
- char ch[2] = { 0 };
-
- while (read(configFile_, &ch[0], 1) == 1) {
- if (ch[0] == '\n') {
- // Break if this is the first newline after reading some other string
- // data.
- if ([str length])
- break;
- } else {
- [str appendString:[NSString stringWithUTF8String:ch]];
- }
- }
-
- return str;
-}
-
-//=============================================================================
-- (NSData *)readData:(ssize_t)length {
- NSMutableData *data = [NSMutableData dataWithLength:length];
- char *bytes = (char *)[data bytes];
-
- if (read(configFile_, bytes, length) != length)
- return nil;
-
- return data;
-}
-
-//=============================================================================
-- (BOOL)readConfigurationData {
+- (void)translateConfigurationData:(NSDictionary *)config {
parameters_ = [[NSMutableDictionary alloc] init];
- while (1) {
- NSString *key = [self readString];
-
- if (![key length])
- break;
-
- // Read the data. Try to convert to a UTF-8 string, or just save
- // the data
- NSString *lenStr = [self readString];
- ssize_t len = [lenStr intValue];
- NSData *data = [self readData:len];
- id value = [[NSString alloc] initWithData:data
- encoding:NSUTF8StringEncoding];
-
+ NSEnumerator *it = [config keyEnumerator];
+ while (NSString *key = [it nextObject]) {
// If the keyname is prefixed by BREAKPAD_SERVER_PARAMETER_PREFIX
// that indicates that it should be uploaded to the server along
// with the minidump, so we treat it specially.
@@ -195,29 +218,24 @@ NSString *const kDefaultServerType = @"google";
NSString *urlParameterKey =
[key substringFromIndex:[@BREAKPAD_SERVER_PARAMETER_PREFIX length]];
if ([urlParameterKey length]) {
- if (value) {
- [self addServerParameter:value
+ id value = [config objectForKey:key];
+ if ([value isKindOfClass:[NSString class]]) {
+ [self addServerParameter:(NSString *)value
forKey:urlParameterKey];
} else {
- [self addServerParameter:data
+ [self addServerParameter:(NSData *)value
forKey:urlParameterKey];
}
}
} else {
- [parameters_ setObject:(value ? value : data) forKey:key];
+ [parameters_ setObject:[config objectForKey:key] forKey:key];
}
- [value release];
}
// generate a unique client ID based on this host's MAC address
// then add a key/value pair for it
NSString *clientID = [self clientID];
[parameters_ setObject:clientID forKey:@"guid"];
-
- close(configFile_);
- configFile_ = -1;
-
- return YES;
}
// Per user per machine
@@ -528,21 +546,27 @@ NSString *const kDefaultServerType = @"google";
}
if (logFileData_) {
- HTTPMultipartUpload *logUpload =
- [[HTTPMultipartUpload alloc] initWithURL:url];
+ [self uploadData:logFileData_ name:@"log" url:url];
+ }
- [uploadParameters setObject:@"log" forKey:@"type"];
- [logUpload setParameters:uploadParameters];
- [logUpload addFileContents:logFileData_ name:@"log"];
+ [upload release];
+}
- NSError *error = nil;
- NSData *data = [logUpload send:&error];
- NSString *result = [[NSString alloc] initWithData:data
- encoding:NSUTF8StringEncoding];
- [result release];
- [logUpload release];
- }
+- (void)uploadData:(NSData *)data name:(NSString *)name {
+ NSURL *url = [NSURL URLWithString:[parameters_ objectForKey:@BREAKPAD_URL]];
+ NSMutableDictionary *uploadParameters = [NSMutableDictionary dictionary];
+
+ if (![self populateServerDictionary:uploadParameters])
+ return;
+
+ HTTPMultipartUpload *upload =
+ [[HTTPMultipartUpload alloc] initWithURL:url];
+
+ [uploadParameters setObject:name forKey:@"type"];
+ [upload setParameters:uploadParameters];
+ [upload addFileContents:data name:name];
+ [upload send:nil];
[upload release];
}