Add an API to Breakpad to upload custom file to the crash server.
On iOS, sending logs using the usual breakpad behavior is not possible, because tar is not available. This allow to use Breakpad to send any file to the crash server. R=mark@chromium.org Review URL: http://breakpad.appspot.com/327001 git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@885 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
parent
b2196565bd
commit
976930db64
5 changed files with 181 additions and 109 deletions
|
@ -196,6 +196,11 @@ bool BreakpadHasCrashReportToUpload(BreakpadRef ref);
|
||||||
// Upload next report to the server.
|
// Upload next report to the server.
|
||||||
void BreakpadUploadNextReport(BreakpadRef ref);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -152,6 +152,7 @@ class Breakpad {
|
||||||
void RemoveKeyValue(NSString *key);
|
void RemoveKeyValue(NSString *key);
|
||||||
NSString *NextCrashReportToUpload();
|
NSString *NextCrashReportToUpload();
|
||||||
void UploadNextReport();
|
void UploadNextReport();
|
||||||
|
void UploadData(NSData *data, NSDictionary *server_parameters);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Breakpad()
|
Breakpad()
|
||||||
|
@ -425,6 +426,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,
|
bool Breakpad::HandleMinidump(const char *dump_dir,
|
||||||
const char *minidump_id) {
|
const char *minidump_id) {
|
||||||
|
@ -681,3 +701,18 @@ void BreakpadUploadNextReport(BreakpadRef ref) {
|
||||||
fprintf(stderr, "BreakpadUploadNextReport() : error\n");
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -38,8 +38,8 @@
|
||||||
163201D61443019E00C4DBF5 /* ConfigFile.h in Headers */ = {isa = PBXBuildFile; fileRef = 163201D41443019E00C4DBF5 /* ConfigFile.h */; };
|
163201D61443019E00C4DBF5 /* ConfigFile.h in Headers */ = {isa = PBXBuildFile; fileRef = 163201D41443019E00C4DBF5 /* ConfigFile.h */; };
|
||||||
163201D71443019E00C4DBF5 /* ConfigFile.mm in Sources */ = {isa = PBXBuildFile; fileRef = 163201D51443019E00C4DBF5 /* ConfigFile.mm */; };
|
163201D71443019E00C4DBF5 /* ConfigFile.mm in Sources */ = {isa = PBXBuildFile; fileRef = 163201D51443019E00C4DBF5 /* ConfigFile.mm */; };
|
||||||
163201E31443029300C4DBF5 /* 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, ); }; };
|
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 */; };
|
3329D4ED0FA16D820007BBC5 /* Breakpad.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3329D4EC0FA16D820007BBC5 /* Breakpad.xib */; };
|
||||||
33880C800F9E097100817F82 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 33880C7E0F9E097100817F82 /* InfoPlist.strings */; };
|
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 */; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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 */ = {
|
F92C56A60ECE04B6009BE4BA /* sender */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
16E02DB4147410D4008C604D /* uploader.mm */,
|
||||||
163202431443201300C4DBF5 /* uploader.h */,
|
163202431443201300C4DBF5 /* uploader.h */,
|
||||||
163202441443201300C4DBF5 /* uploader.m */,
|
|
||||||
F9B6309F100FF96B00D0F4AC /* goArrow.png */,
|
F9B6309F100FF96B00D0F4AC /* goArrow.png */,
|
||||||
F92C56A70ECE04C5009BE4BA /* crash_report_sender.h */,
|
F92C56A70ECE04C5009BE4BA /* crash_report_sender.h */,
|
||||||
F92C56A80ECE04C5009BE4BA /* crash_report_sender.m */,
|
F92C56A80ECE04C5009BE4BA /* crash_report_sender.m */,
|
||||||
|
@ -1741,7 +1741,7 @@
|
||||||
F9C44EA20EF09F93003AEBAA /* HTTPMultipartUpload.m in Sources */,
|
F9C44EA20EF09F93003AEBAA /* HTTPMultipartUpload.m in Sources */,
|
||||||
F92C56A90ECE04C5009BE4BA /* crash_report_sender.m in Sources */,
|
F92C56A90ECE04C5009BE4BA /* crash_report_sender.m in Sources */,
|
||||||
F9C44EE90EF0A3C1003AEBAA /* GTMLogger.m in Sources */,
|
F9C44EE90EF0A3C1003AEBAA /* GTMLogger.m in Sources */,
|
||||||
163202451443201300C4DBF5 /* uploader.m in Sources */,
|
16E02DB8147410F0008C604D /* uploader.mm in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -44,7 +44,6 @@ extern NSString *const kDefaultServerType;
|
||||||
|
|
||||||
@interface Uploader : NSObject {
|
@interface Uploader : NSObject {
|
||||||
@private
|
@private
|
||||||
int configFile_; // File descriptor for config file
|
|
||||||
NSMutableDictionary *parameters_; // Key value pairs of data (STRONG)
|
NSMutableDictionary *parameters_; // Key value pairs of data (STRONG)
|
||||||
NSData *minidumpContents_; // The data in the minidump (STRONG)
|
NSData *minidumpContents_; // The data in the minidump (STRONG)
|
||||||
NSData *logFileData_; // An NSdata for the tar,
|
NSData *logFileData_; // An NSdata for the tar,
|
||||||
|
@ -66,8 +65,17 @@ extern NSString *const kDefaultServerType;
|
||||||
|
|
||||||
- (id)initWithConfigFile:(const char *)configFile;
|
- (id)initWithConfigFile:(const char *)configFile;
|
||||||
|
|
||||||
|
- (id)initWithConfig:(NSDictionary *)config;
|
||||||
|
|
||||||
- (NSMutableDictionary *)parameters;
|
- (NSMutableDictionary *)parameters;
|
||||||
|
|
||||||
- (void)report;
|
- (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
|
@end
|
||||||
|
|
|
@ -52,12 +52,99 @@ NSString *const kDefaultServerType = @"google";
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
|
|
||||||
@interface Uploader(PrivateMethods)
|
namespace {
|
||||||
- (NSString *)readString;
|
// Read one line from the configuration file.
|
||||||
- (NSData *)readData:(ssize_t)length;
|
NSString *readString(int fileId) {
|
||||||
|
NSMutableString *str = [NSMutableString stringWithCapacity:32];
|
||||||
|
char ch[2] = { 0 };
|
||||||
|
|
||||||
- (BOOL)readConfigurationData;
|
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)
|
||||||
|
|
||||||
|
// 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;
|
- (BOOL)readMinidumpData;
|
||||||
|
|
||||||
|
// Read the log files referenced in |parameters_| and update |logFileData_|
|
||||||
|
// with their content.
|
||||||
- (BOOL)readLogFileData;
|
- (BOOL)readLogFileData;
|
||||||
|
|
||||||
// Returns a unique client id (user-specific), creating a persistent
|
// 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
|
// Accessor method for the URL parameter dictionary
|
||||||
- (NSMutableDictionary *)urlParameterDictionary;
|
- (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.
|
// Records the uploaded crash ID to the log file.
|
||||||
- (void)logUploadWithID:(const char *)uploadID;
|
- (void)logUploadWithID:(const char *)uploadID;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation Uploader
|
@implementation Uploader
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
- (id)initWithConfigFile:(const char *)configFile {
|
- (id)initWithConfigFile:(const char *)configFile {
|
||||||
if ((self = [super init])) {
|
NSDictionary *config = readConfigurationData(configFile);
|
||||||
|
if (!config)
|
||||||
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));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (configFile_ == -1) {
|
|
||||||
[self release];
|
|
||||||
return nil;
|
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
|
// Because the reporter is embedded in the framework (and many copies
|
||||||
// of the framework may exist) its not completely certain that the OS
|
// of the framework may exist) its not completely certain that the OS
|
||||||
// will obey the com.apple.PreferenceSync.ExcludeAllSyncKeys in our
|
// will obey the com.apple.PreferenceSync.ExcludeAllSyncKeys in our
|
||||||
|
@ -126,68 +196,21 @@ NSString *const kDefaultServerType = @"google";
|
||||||
|
|
||||||
[self createServerParameterDictionaries];
|
[self createServerParameterDictionaries];
|
||||||
|
|
||||||
if (![self readConfigurationData]) {
|
[self translateConfigurationData:config];
|
||||||
GTMLoggerDebug(@"uploader readConfigurationData failed");
|
|
||||||
[self release];
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the minidump into memory.
|
// Read the minidump into memory.
|
||||||
[self readMinidumpData];
|
[self readMinidumpData];
|
||||||
[self readLogFileData];
|
[self readLogFileData];
|
||||||
|
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
- (NSString *)readString {
|
- (void)translateConfigurationData:(NSDictionary *)config {
|
||||||
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 {
|
|
||||||
parameters_ = [[NSMutableDictionary alloc] init];
|
parameters_ = [[NSMutableDictionary alloc] init];
|
||||||
|
|
||||||
while (1) {
|
NSEnumerator *it = [config keyEnumerator];
|
||||||
NSString *key = [self readString];
|
while (NSString *key = [it nextObject]) {
|
||||||
|
|
||||||
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];
|
|
||||||
|
|
||||||
// If the keyname is prefixed by BREAKPAD_SERVER_PARAMETER_PREFIX
|
// If the keyname is prefixed by BREAKPAD_SERVER_PARAMETER_PREFIX
|
||||||
// that indicates that it should be uploaded to the server along
|
// that indicates that it should be uploaded to the server along
|
||||||
// with the minidump, so we treat it specially.
|
// with the minidump, so we treat it specially.
|
||||||
|
@ -195,29 +218,24 @@ NSString *const kDefaultServerType = @"google";
|
||||||
NSString *urlParameterKey =
|
NSString *urlParameterKey =
|
||||||
[key substringFromIndex:[@BREAKPAD_SERVER_PARAMETER_PREFIX length]];
|
[key substringFromIndex:[@BREAKPAD_SERVER_PARAMETER_PREFIX length]];
|
||||||
if ([urlParameterKey length]) {
|
if ([urlParameterKey length]) {
|
||||||
if (value) {
|
id value = [config objectForKey:key];
|
||||||
[self addServerParameter:value
|
if ([value isKindOfClass:[NSString class]]) {
|
||||||
|
[self addServerParameter:(NSString *)value
|
||||||
forKey:urlParameterKey];
|
forKey:urlParameterKey];
|
||||||
} else {
|
} else {
|
||||||
[self addServerParameter:data
|
[self addServerParameter:(NSData *)value
|
||||||
forKey:urlParameterKey];
|
forKey:urlParameterKey];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} 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
|
// generate a unique client ID based on this host's MAC address
|
||||||
// then add a key/value pair for it
|
// then add a key/value pair for it
|
||||||
NSString *clientID = [self clientID];
|
NSString *clientID = [self clientID];
|
||||||
[parameters_ setObject:clientID forKey:@"guid"];
|
[parameters_ setObject:clientID forKey:@"guid"];
|
||||||
|
|
||||||
close(configFile_);
|
|
||||||
configFile_ = -1;
|
|
||||||
|
|
||||||
return YES;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Per user per machine
|
// Per user per machine
|
||||||
|
@ -528,24 +546,30 @@ NSString *const kDefaultServerType = @"google";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (logFileData_) {
|
if (logFileData_) {
|
||||||
HTTPMultipartUpload *logUpload =
|
[self uploadData:logFileData_ name:@"log" url:url];
|
||||||
[[HTTPMultipartUpload alloc] initWithURL:url];
|
|
||||||
|
|
||||||
[uploadParameters setObject:@"log" forKey:@"type"];
|
|
||||||
[logUpload setParameters:uploadParameters];
|
|
||||||
[logUpload addFileContents:logFileData_ name:@"log"];
|
|
||||||
|
|
||||||
NSError *error = nil;
|
|
||||||
NSData *data = [logUpload send:&error];
|
|
||||||
NSString *result = [[NSString alloc] initWithData:data
|
|
||||||
encoding:NSUTF8StringEncoding];
|
|
||||||
[result release];
|
|
||||||
[logUpload release];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[upload release];
|
[upload 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];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)logUploadWithID:(const char *)uploadID {
|
- (void)logUploadWithID:(const char *)uploadID {
|
||||||
NSString *minidumpDir =
|
NSString *minidumpDir =
|
||||||
[parameters_ objectForKey:@kReporterMinidumpDirectoryKey];
|
[parameters_ objectForKey:@kReporterMinidumpDirectoryKey];
|
Loading…
Reference in a new issue