From 20c73dcdc3018a3cdade669b4c90b3ad640da137 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Thu, 17 Apr 2014 23:47:13 +0200 Subject: [PATCH] Send each crash report using an individual network request --- Classes/BITCrashManager.m | 107 ++++++++++++++++---------------------- 1 file changed, 46 insertions(+), 61 deletions(-) diff --git a/Classes/BITCrashManager.m b/Classes/BITCrashManager.m index 4d1bff75d1..c348826e14 100644 --- a/Classes/BITCrashManager.m +++ b/Classes/BITCrashManager.m @@ -204,26 +204,39 @@ NSString *const kBITCrashManagerStatus = @"BITCrashManagerStatus"; } } + +/** + * Remove a cached crash report + * + * @param filename The base filename of the crash report + */ +- (void)cleanCrashReportWithFilename:(NSString *)filename { + if (!filename) return; + + NSError *error = NULL; + + [_fileManager removeItemAtPath:filename error:&error]; + [_fileManager removeItemAtPath:[filename stringByAppendingString:@".data"] error:&error]; + [_fileManager removeItemAtPath:[filename stringByAppendingString:@".meta"] error:&error]; + + NSString *cacheFilename = [filename lastPathComponent]; + [self removeKeyFromKeychain:[NSString stringWithFormat:@"%@.%@", cacheFilename, kBITCrashMetaUserName]]; + [self removeKeyFromKeychain:[NSString stringWithFormat:@"%@.%@", cacheFilename, kBITCrashMetaUserEmail]]; + [self removeKeyFromKeychain:[NSString stringWithFormat:@"%@.%@", cacheFilename, kBITCrashMetaUserID]]; + + [_crashFiles removeObject:filename]; + [_approvedCrashReports removeObjectForKey:filename]; + + [self saveSettings]; +} + /** * Remove all crash reports and stored meta data for each from the file system and keychain */ - (void)cleanCrashReports { - NSError *error = NULL; - for (NSUInteger i=0; i < [_crashFiles count]; i++) { - [_fileManager removeItemAtPath:[_crashFiles objectAtIndex:i] error:&error]; - [_fileManager removeItemAtPath:[[_crashFiles objectAtIndex:i] stringByAppendingString:@".data"] error:&error]; - [_fileManager removeItemAtPath:[[_crashFiles objectAtIndex:i] stringByAppendingString:@".meta"] error:&error]; - - NSString *cacheFilename = [[_crashFiles objectAtIndex:i] lastPathComponent]; - [self removeKeyFromKeychain:[NSString stringWithFormat:@"%@.%@", cacheFilename, kBITCrashMetaUserName]]; - [self removeKeyFromKeychain:[NSString stringWithFormat:@"%@.%@", cacheFilename, kBITCrashMetaUserEmail]]; - [self removeKeyFromKeychain:[NSString stringWithFormat:@"%@.%@", cacheFilename, kBITCrashMetaUserID]]; + [self cleanCrashReportWithFilename:[_crashFiles objectAtIndex:i]]; } - [_crashFiles removeAllObjects]; - [_approvedCrashReports removeAllObjects]; - - [self saveSettings]; } @@ -242,7 +255,7 @@ NSString *const kBITCrashManagerStatus = @"BITCrashManagerStatus"; /** * Read the attachment data from the stored file * - * @param filename The crash report id + * @param filename The crash report file path * * @return an BITCrashAttachment instance or nil */ @@ -800,12 +813,13 @@ NSString *const kBITCrashManagerStatus = @"BITCrashManagerStatus"; */ - (void)sendCrashReports { NSError *error = NULL; - - NSMutableString *crashes = nil; - NSMutableArray *attachments = [NSMutableArray array]; + _crashIdenticalCurrentVersion = NO; for (NSUInteger i=0; i < [_crashFiles count]; i++) { + NSString *crashXML = nil; + BITCrashAttachment *attachment = nil; + NSString *filename = [_crashFiles objectAtIndex:i]; NSString *cacheFilename = [filename lastPathComponent]; NSData *crashData = [NSData dataWithContentsOfFile:filename]; @@ -816,13 +830,7 @@ NSString *const kBITCrashManagerStatus = @"BITCrashManagerStatus"; if (report == nil) { BITHockeyLog(@"WARNING: Could not parse crash report"); // we cannot do anything with this report, so delete it - [_fileManager removeItemAtPath:filename error:&error]; - [_fileManager removeItemAtPath:[NSString stringWithFormat:@"%@.data", filename] error:&error]; - [_fileManager removeItemAtPath:[NSString stringWithFormat:@"%@.meta", filename] error:&error]; - - [self removeKeyFromKeychain:[NSString stringWithFormat:@"%@.%@", cacheFilename, kBITCrashMetaUserName]]; - [self removeKeyFromKeychain:[NSString stringWithFormat:@"%@.%@", cacheFilename, kBITCrashMetaUserEmail]]; - [self removeKeyFromKeychain:[NSString stringWithFormat:@"%@.%@", cacheFilename, kBITCrashMetaUserID]]; + [self cleanCrashReportWithFilename:filename]; continue; } @@ -837,10 +845,6 @@ NSString *const kBITCrashManagerStatus = @"BITCrashManagerStatus"; _crashIdenticalCurrentVersion = YES; } - if (crashes == nil) { - crashes = [NSMutableString string]; - } - NSString *username = @""; NSString *useremail = @""; NSString *userid = @""; @@ -863,12 +867,7 @@ NSString *const kBITCrashManagerStatus = @"BITCrashManagerStatus"; userid = [self stringValueFromKeychainForKey:[NSString stringWithFormat:@"%@.%@", cacheFilename, kBITCrashMetaUserID]] ?: @""; applicationLog = [metaDict objectForKey:kBITCrashMetaApplicationLog] ?: @""; - BITCrashAttachment *attachment = [self attachmentForCrashReport:filename]; - if (attachment) { - NSDictionary *attachmentDict = @{KBITAttachmentDictIndex: @(i), - KBITAttachmentDictAttachment: attachment}; - [attachments addObject:attachmentDict]; - } + attachment = [self attachmentForCrashReport:filename]; } else { BITHockeyLog(@"ERROR: Reading crash meta data. %@", error); } @@ -877,7 +876,7 @@ NSString *const kBITCrashManagerStatus = @"BITCrashManagerStatus"; description = [NSString stringWithFormat:@"%@", applicationLog]; } - [crashes appendFormat:@"%s%@%@%@%@%@%@%@%@%@%@%@", + crashXML = [NSString stringWithFormat:@"%s%@%@%@%@%@%@%@%@%@%@%@", [[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleExecutable"] UTF8String], [self extractAppUUIDs:report], report.applicationInfo.applicationIdentifier, @@ -893,27 +892,18 @@ NSString *const kBITCrashManagerStatus = @"BITCrashManagerStatus"; installString, [description stringByReplacingOccurrencesOfString:@"]]>" withString:@"]]" @"]]>" options:NSLiteralSearch range:NSMakeRange(0,description.length)]]; - // store this crash report as user approved, so if it fails it will retry automatically [_approvedCrashReports setObject:[NSNumber numberWithBool:YES] forKey:filename]; + + BITHockeyLog(@"INFO: Sending crash reports:\n%@", crashXML); + [self sendCrashReportWithFilename:filename xml:crashXML attachment:attachment]; } else { // we cannot do anything with this report, so delete it - [_fileManager removeItemAtPath:filename error:&error]; - [_fileManager removeItemAtPath:[NSString stringWithFormat:@"%@.data", filename] error:&error]; - [_fileManager removeItemAtPath:[NSString stringWithFormat:@"%@.meta", filename] error:&error]; - - [self removeKeyFromKeychain:[NSString stringWithFormat:@"%@.%@", cacheFilename, kBITCrashMetaUserName]]; - [self removeKeyFromKeychain:[NSString stringWithFormat:@"%@.%@", cacheFilename, kBITCrashMetaUserEmail]]; - [self removeKeyFromKeychain:[NSString stringWithFormat:@"%@.%@", cacheFilename, kBITCrashMetaUserID]]; + [self cleanCrashReportWithFilename:filename]; } } [self saveSettings]; - - if (crashes != nil) { - BITHockeyLog(@"INFO: Sending crash reports:\n%@", crashes); - [self postXML:[NSString stringWithFormat:@"%@", crashes] attachments:attachments]; - } } @@ -953,7 +943,7 @@ NSString *const kBITCrashManagerStatus = @"BITCrashManagerStatus"; #pragma mark - Networking -- (NSURLRequest *)requestWithXML:(NSString*)xml attachments:(NSArray *)attachments { +- (NSURLRequest *)requestWithXML:(NSString*)xml attachment:(BITCrashAttachment *)attachment { NSString *postCrashPath = [NSString stringWithFormat:@"api/2/apps/%@/crashes", self.encodedAppIdentifier]; NSMutableURLRequest *request = [self.hockeyAppClient requestWithMethod:@"POST" @@ -988,14 +978,9 @@ NSString *const kBITCrashManagerStatus = @"BITCrashManagerStatus"; boundary:boundary filename:@"crash.xml"]]; - for (NSDictionary *dict in attachments) { - NSInteger index = [(NSNumber *)dict[KBITAttachmentDictIndex] integerValue]; - NSString *key = [NSString stringWithFormat:@"attachment%ld", (long)index]; - - BITCrashAttachment *attachment = (BITCrashAttachment *)dict[KBITAttachmentDictAttachment]; - + if (attachment) { [postBody appendData:[BITHockeyAppClient dataWithPostValue:attachment.attachmentData - forKey:key + forKey:@"attachment0" contentType:attachment.contentType boundary:boundary filename:attachment.filename]]; @@ -1015,9 +1000,9 @@ NSString *const kBITCrashManagerStatus = @"BITCrashManagerStatus"; * * @param xml The XML data that needs to be send to the server */ -- (void)postXML:(NSString*)xml attachments:(NSArray *)attachments { +- (void)sendCrashReportWithFilename:(NSString *)filename xml:(NSString*)xml attachment:(BITCrashAttachment *)attachment { - NSURLRequest* request = [self requestWithXML:xml attachments:attachments]; + NSURLRequest* request = [self requestWithXML:xml attachment:attachment]; __weak typeof (self) weakSelf = self; BITHTTPOperation *operation = [self.hockeyAppClient @@ -1038,7 +1023,7 @@ NSString *const kBITCrashManagerStatus = @"BITCrashManagerStatus"; } ]; } else if (statusCode >= 200 && statusCode < 400) { - [strongSelf cleanCrashReports]; + [strongSelf cleanCrashReportWithFilename:filename]; // HockeyApp uses PList XML format NSMutableDictionary *response = [NSPropertyListSerialization propertyListFromData:responseData @@ -1052,7 +1037,7 @@ NSString *const kBITCrashManagerStatus = @"BITCrashManagerStatus"; [strongSelf.delegate crashManagerDidFinishSendingCrashReport:self]; } } else if (statusCode == 400) { - [strongSelf cleanCrashReports]; + [strongSelf cleanCrashReportWithFilename:filename]; error = [NSError errorWithDomain:kBITCrashErrorDomain code:BITCrashAPIAppVersionRejected