diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/client/ios/Breakpad.h | 5 | ||||
-rw-r--r-- | src/client/ios/Breakpad.mm | 35 | ||||
-rw-r--r-- | src/client/mac/Breakpad.xcodeproj/project.pbxproj | 8 | ||||
-rw-r--r-- | src/client/mac/sender/uploader.h | 10 | ||||
-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]; } |