Include response data in 'request over websocket' failures.

This commit is contained in:
Matthew Chen 2018-05-30 10:03:14 -04:00
parent 43848a8fe7
commit 4342b04bd3
4 changed files with 45 additions and 32 deletions

View file

@ -125,7 +125,7 @@ public class ProfileFetcherJob: NSObject {
reject(error)
}
},
failure: { (_: NSInteger, error: Error) in
failure: { (_: NSInteger, _:Data?, error: Error) in
reject(error)
})
} else {

View file

@ -985,7 +985,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
deviceMessages:deviceMessages
success:successHandler];
}
failure:^(NSInteger statusCode, NSError *error) {
failure:^(NSInteger statusCode, NSData *_Nullable responseBody, NSError *error) {
[self messageSendDidFail:message
recipient:recipient
thread:thread
@ -994,6 +994,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
remainingAttempts:remainingAttempts
statusCode:statusCode
error:error
responseData:responseBody
success:successHandler
failure:failureHandler];
}];
@ -1009,6 +1010,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
failure:^(NSURLSessionDataTask *task, NSError *error) {
NSHTTPURLResponse *response = (NSHTTPURLResponse *)task.response;
NSInteger statusCode = response.statusCode;
NSData *_Nullable responseData = error.userInfo[AFNetworkingOperationFailingURLResponseDataErrorKey];
[self messageSendDidFail:message
recipient:recipient
@ -1018,6 +1020,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
remainingAttempts:remainingAttempts
statusCode:statusCode
error:error
responseData:responseData
success:successHandler
failure:failureHandler];
}];
@ -1067,7 +1070,8 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
deviceMessages:(NSArray<NSDictionary *> *)deviceMessages
remainingAttempts:(int)remainingAttempts
statusCode:(NSInteger)statusCode
error:(NSError *)error
error:(NSError *)responseError
responseData:(nullable NSData *)responseData
success:(void (^)(void))successHandler
failure:(RetryableFailureHandler)failureHandler
{
@ -1075,21 +1079,18 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
OWSAssert(recipient);
OWSAssert(thread);
OWSAssert(deviceMessages);
OWSAssert(error);
OWSAssert(responseError);
OWSAssert(successHandler);
OWSAssert(failureHandler);
DDLogInfo(@"%@ sending to recipient: %@, failed with error.", self.logTag, recipient.uniqueId);
[DDLog flushLog];
NSData *responseData = error.userInfo[AFNetworkingOperationFailingURLResponseDataErrorKey];
void (^retrySend)(void) = ^void() {
if (remainingAttempts <= 0) {
// Since we've already repeatedly failed to send to the messaging API,
// it's unlikely that repeating the whole process will succeed.
[error setIsRetryable:NO];
return failureHandler(error);
[responseError setIsRetryable:NO];
return failureHandler(responseError);
}
dispatch_async([OWSDispatch sendingQueue], ^{
@ -1130,32 +1131,39 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
}
case 409: {
// Mismatched devices
DDLogWarn(@"%@ Mismatch Devices for recipient: %@", self.logTag, recipient.uniqueId);
DDLogWarn(@"%@ Mismatched devices for recipient: %@", self.logTag, recipient.uniqueId);
NSError *error;
NSDictionary *serializedResponse =
[NSJSONSerialization JSONObjectWithData:responseData options:0 error:&error];
if (error) {
NSError *_Nullable error = nil;
NSDictionary *_Nullable responseJson = nil;
if (responseData) {
responseJson = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:&error];
}
if (error || !responseJson) {
OWSProdError([OWSAnalyticsEvents messageSenderErrorCouldNotParseMismatchedDevicesJson]);
[error setIsRetryable:YES];
return failureHandler(error);
}
[self handleMismatchedDevices:serializedResponse recipient:recipient completion:retrySend];
[self handleMismatchedDevicesWithResponseJson:responseJson recipient:recipient completion:retrySend];
break;
}
case 410: {
// Stale devices
DDLogWarn(@"%@ Stale devices for recipient: %@", self.logTag, recipient.uniqueId);
if (!responseData) {
NSError *_Nullable error = nil;
NSDictionary *_Nullable responseJson = nil;
if (responseData) {
responseJson = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:&error];
}
if (error || !responseJson) {
DDLogWarn(@"Stale devices but server didn't specify devices in response.");
NSError *error = OWSErrorMakeUnableToProcessServerResponseError();
[error setIsRetryable:YES];
return failureHandler(error);
}
[self handleStaleDevicesWithResponse:responseData recipientId:recipient.uniqueId completion:retrySend];
[self handleStaleDevicesWithResponseJson:responseJson recipientId:recipient.uniqueId completion:retrySend];
break;
}
default:
@ -1164,12 +1172,16 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
}
}
- (void)handleMismatchedDevices:(NSDictionary *)dictionary
recipient:(SignalRecipient *)recipient
completion:(void (^)(void))completionHandler
- (void)handleMismatchedDevicesWithResponseJson:(NSDictionary *)responseJson
recipient:(SignalRecipient *)recipient
completion:(void (^)(void))completionHandler
{
NSArray *extraDevices = [dictionary objectForKey:@"extraDevices"];
NSArray *missingDevices = [dictionary objectForKey:@"missingDevices"];
OWSAssert(responseJson);
OWSAssert(recipient);
OWSAssert(completionHandler);
NSArray *extraDevices = responseJson[@"extraDevices"];
NSArray *missingDevices = responseJson[@"missingDevices"];
if (missingDevices.count > 0) {
NSString *localNumber = [TSAccountManager localNumber];
@ -1442,13 +1454,12 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
}
// Called when the server indicates that the devices no longer exist - e.g. when the remote recipient has reinstalled.
- (void)handleStaleDevicesWithResponse:(NSData *)responseData
recipientId:(NSString *)identifier
completion:(void (^)(void))completionHandler
- (void)handleStaleDevicesWithResponseJson:(NSDictionary *)responseJson
recipientId:(NSString *)identifier
completion:(void (^)(void))completionHandler
{
dispatch_async([OWSDispatch sendingQueue], ^{
NSDictionary *serialization = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:nil];
NSArray *devices = serialization[@"staleDevices"];
NSArray *devices = responseJson[@"staleDevices"];
if (!([devices count] > 0)) {
return;

View file

@ -18,7 +18,7 @@ typedef NS_ENUM(NSUInteger, SocketManagerState) {
typedef void (^TSSocketMessageSuccess)(id _Nullable responseObject);
// statusCode is zero by default, if request never made or failed.
typedef void (^TSSocketMessageFailure)(NSInteger statusCode, NSError *error);
typedef void (^TSSocketMessageFailure)(NSInteger statusCode, NSData *_Nullable responseBody, NSError *error);
@class TSRequest;

View file

@ -102,10 +102,10 @@ NSString *const kNSNotification_SocketManagerStateDidChange = @"kNSNotification_
NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeMessageRequestFailed,
NSLocalizedString(@"ERROR_DESCRIPTION_REQUEST_FAILED", @"Error indicating that a socket request failed."));
[self didFailWithStatusCode:0 error:error];
[self didFailWithStatusCode:0 responseBody:nil error:error];
}
- (void)didFailWithStatusCode:(NSInteger)statusCode error:(NSError *)error
- (void)didFailWithStatusCode:(NSInteger)statusCode responseBody:(nullable NSData *)responseBody error:(NSError *)error
{
OWSAssert(error);
@ -117,12 +117,14 @@ NSString *const kNSNotification_SocketManagerStateDidChange = @"kNSNotification_
self.hasCompleted = YES;
}
DDLogError(@"%@ %s didFailWithStatusCode: %zd, %@", self.logTag, __PRETTY_FUNCTION__, statusCode, error);
OWSAssert(self.success);
OWSAssert(self.failure);
TSSocketMessageFailure failure = self.failure;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
failure(statusCode, error);
failure(statusCode, responseBody, error);
});
self.success = nil;
@ -606,7 +608,7 @@ NSString *const kNSNotification_SocketManagerStateDidChange = @"kNSNotification_
NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeMessageResponseFailed,
NSLocalizedString(
@"ERROR_DESCRIPTION_RESPONSE_FAILED", @"Error indicating that a socket response failed."));
[socketMessage didFailWithStatusCode:(NSInteger)responseStatus error:error];
[socketMessage didFailWithStatusCode:(NSInteger)responseStatus responseBody:responseBody error:error];
}
}