Merge branch 'mkirk/terminal-sending-failures'

pull/1/head
Michael Kirk 8 years ago
commit 694088ee98

@ -15,6 +15,13 @@ NS_ASSUME_NONNULL_BEGIN
@class TSThread; @class TSThread;
@protocol ContactsManagerProtocol; @protocol ContactsManagerProtocol;
/**
* Useful for when you *sometimes* want to retry before giving up and calling the failure handler
* but *sometimes* we don't want to retry when we know it's a terminal failure, so we allow the
* caller to indicate this with isRetryable=NO.
*/
typedef void (^RetryableFailureHandler)(NSError *_Nonnull error, BOOL isRetryable);
NS_SWIFT_NAME(MessageSender) NS_SWIFT_NAME(MessageSender)
@interface OWSMessageSender : NSObject { @interface OWSMessageSender : NSObject {

@ -79,7 +79,7 @@ typedef NS_ENUM(NSInteger, OWSSendMessageOperationState) {
- (void)attemptToSendMessage:(TSOutgoingMessage *)message - (void)attemptToSendMessage:(TSOutgoingMessage *)message
success:(void (^)())successHandler success:(void (^)())successHandler
failure:(void (^)(NSError *error))failureHandler; failure:(RetryableFailureHandler)failureHandler;
@end @end
@ -209,10 +209,17 @@ NSUInteger const OWSSendMessageOperationMaxRetries = 4;
- (void)tryWithRemainingRetries:(NSUInteger)remainingRetries - (void)tryWithRemainingRetries:(NSUInteger)remainingRetries
{ {
DDLogDebug(@"%@ remainingRetries: %lu", self.tag, remainingRetries); DDLogDebug(@"%@ remainingRetries: %lu", self.tag, (unsigned long)remainingRetries);
void (^retryableFailureHandler)(NSError *_Nonnull) = ^(NSError *_Nonnull error) { RetryableFailureHandler retryableFailureHandler = ^(NSError *_Nonnull error, BOOL isRetryable) {
DDLogInfo(@"%@ Sending failed.", self.tag); DDLogInfo(@"%@ Sending failed.", self.tag);
if (!isRetryable) {
DDLogInfo(@"%@ Skipping retry due to terminal error: %@", self.tag, error);
self.failureHandler(error);
return;
}
if (remainingRetries > 0) { if (remainingRetries > 0) {
[self tryWithRemainingRetries:remainingRetries - 1]; [self tryWithRemainingRetries:remainingRetries - 1];
} else { } else {
@ -349,12 +356,13 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
- (void)attemptToSendMessage:(TSOutgoingMessage *)message - (void)attemptToSendMessage:(TSOutgoingMessage *)message
success:(void (^)())successHandler success:(void (^)())successHandler
failure:(void (^)(NSError *error))failureHandler failure:(RetryableFailureHandler)failureHandler
{ {
DDLogDebug(@"%@ sending message: %@", self.tag, message.debugDescription); DDLogDebug(@"%@ sending message: %@", self.tag, message.debugDescription);
void (^markAndFailureHandler)(NSError *error) = ^(NSError *error) { RetryableFailureHandler markAndFailureHandler = ^(NSError *error, BOOL isRetryable) {
// TODO do we really want to mark this as failed if we're still retrying?
[self saveMessage:message withError:error]; [self saveMessage:message withError:error];
failureHandler(error); failureHandler(error, isRetryable);
}; };
[self ensureAnyAttachmentsUploaded:message [self ensureAnyAttachmentsUploaded:message
@ -366,7 +374,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
- (void)ensureAnyAttachmentsUploaded:(TSOutgoingMessage *)message - (void)ensureAnyAttachmentsUploaded:(TSOutgoingMessage *)message
success:(void (^)())successHandler success:(void (^)())successHandler
failure:(void (^)(NSError *error))failureHandler failure:(RetryableFailureHandler)failureHandler
{ {
if (!message.hasAttachments) { if (!message.hasAttachments) {
DDLogDebug(@"%@ No attachments for message: %@", self.tag, message); DDLogDebug(@"%@ No attachments for message: %@", self.tag, message);
@ -379,7 +387,8 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
if (!attachmentStream) { if (!attachmentStream) {
DDLogError(@"%@ Unable to find local saved attachment to upload.", self.tag); DDLogError(@"%@ Unable to find local saved attachment to upload.", self.tag);
NSError *error = OWSErrorMakeFailedToSendOutgoingMessageError(); NSError *error = OWSErrorMakeFailedToSendOutgoingMessageError();
return failureHandler(error); // Not finding local attachment is a terminal failure.
return failureHandler(error, NO);
} }
[self.uploadingService uploadAttachmentStream:attachmentStream [self.uploadingService uploadAttachmentStream:attachmentStream
@ -471,8 +480,15 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
// Normally marking as unsent is handled in sendMessage happy path, but beacuse we're skipping the common entry // Normally marking as unsent is handled in sendMessage happy path, but beacuse we're skipping the common entry
// point to message sending in order to send to a single recipient, we have to handle it ourselves. // point to message sending in order to send to a single recipient, we have to handle it ourselves.
void (^markAndFailureHandler)(NSError *error) = ^(NSError *error) { RetryableFailureHandler markAndFailureHandler = ^(NSError *error, BOOL isRetryable) {
[self saveMessage:message withError:error]; [self saveMessage:message withError:error];
if (isRetryable) {
// FIXME: Fixing this will require a larger refactor. In the meanwhile, we don't
// retry message sending from accepting key-changes in a group. (Except for the inner retry logic w/ the
// messages API)
DDLogWarn(@"%@ Skipping retry for group-message failure during %s.", self.tag, __PRETTY_FUNCTION__);
}
failureHandler(error); failureHandler(error);
}; };
@ -512,7 +528,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
- (void)deliverMessage:(TSOutgoingMessage *)message - (void)deliverMessage:(TSOutgoingMessage *)message
success:(void (^)())successHandler success:(void (^)())successHandler
failure:(void (^)(NSError *error))failureHandler failure:(RetryableFailureHandler)failureHandler
{ {
TSThread *thread = message.thread; TSThread *thread = message.thread;
@ -526,11 +542,13 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
if (recipients.count == 0) { if (recipients.count == 0) {
if (error) { if (error) {
failureHandler(error); // If not recipients were found, there's no reason to retry. It will just fail again.
failureHandler(error, NO);
return; return;
} else { } else {
DDLogError(@"%@ Unknown error finding contacts", self.tag); DDLogError(@"%@ Unknown error finding contacts", self.tag);
failureHandler(OWSErrorMakeFailedToSendOutgoingMessageError()); // If not recipients were found, there's no reason to retry. It will just fail again.
failureHandler(OWSErrorMakeFailedToSendOutgoingMessageError(), NO);
return; return;
} }
} }
@ -558,7 +576,8 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
if ([blockedPhoneNumbers containsObject:recipientContactId]) { if ([blockedPhoneNumbers containsObject:recipientContactId]) {
DDLogInfo(@"%@ skipping 1:1 send to blocked contact: %@", self.tag, recipientContactId); DDLogInfo(@"%@ skipping 1:1 send to blocked contact: %@", self.tag, recipientContactId);
NSError *error = OWSErrorMakeMessageSendFailedToBlocklistError(); NSError *error = OWSErrorMakeMessageSendFailedToBlocklistError();
failureHandler(error); // No need to retry - the user will continue to be blocked.
failureHandler(error, NO);
return; return;
} }
@ -575,7 +594,9 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
} }
DDLogError(@"%@ contact lookup failed with error: %@", self.tag, error); DDLogError(@"%@ contact lookup failed with error: %@", self.tag, error);
failureHandler(error); // No need to repeat trying to find a failure. Apart from repeatedly failing, it would also cause us
// to print redundant error messages.
failureHandler(error, NO);
return; return;
} }
} }
@ -583,7 +604,9 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
if (!recipient) { if (!recipient) {
NSError *error = OWSErrorMakeFailedToSendOutgoingMessageError(); NSError *error = OWSErrorMakeFailedToSendOutgoingMessageError();
DDLogWarn(@"recipient contact still not found after attempting lookup."); DDLogWarn(@"recipient contact still not found after attempting lookup.");
failureHandler(error); // No need to repeat trying to find a failure. Apart from repeatedly failing, it would also cause us to
// print redundant error messages.
failureHandler(error, NO);
return; return;
} }
@ -595,8 +618,12 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
failure:failureHandler]; failure:failureHandler];
} else { } else {
DDLogError(@"%@ Unexpected unhandlable message: %@", self.tag, message); DDLogError(@"%@ Unexpected unhandlable message: %@", self.tag, message);
// Neither a group nor contact thread? This should never happen.
OWSAssert(NO);
NSError *error = OWSErrorMakeFailedToSendOutgoingMessageError(); NSError *error = OWSErrorMakeFailedToSendOutgoingMessageError();
failureHandler(error); failureHandler(error, NO);
} }
}); });
} }
@ -616,7 +643,8 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
success:^{ success:^{
[futureSource trySetResult:@1]; [futureSource trySetResult:@1];
} }
failure:^(NSError *error) { failure:^(NSError *error, BOOL isRetryable) {
// FIXME what to do WRT retryable here?
[futureSource trySetFailure:error]; [futureSource trySetFailure:error];
}]; }];
@ -627,7 +655,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
message:(TSOutgoingMessage *)message message:(TSOutgoingMessage *)message
thread:(TSThread *)thread thread:(TSThread *)thread
success:(void (^)())successHandler success:(void (^)())successHandler
failure:(void (^)(NSError *error))failureHandler failure:(RetryableFailureHandler)failureHandler
{ {
[self saveGroupMessage:message inThread:thread]; [self saveGroupMessage:message inThread:thread];
NSMutableArray<TOCFuture *> *futures = [NSMutableArray array]; NSMutableArray<TOCFuture *> *futures = [NSMutableArray array];
@ -669,14 +697,16 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
if (failedFuture.hasFailed) { if (failedFuture.hasFailed) {
id failureResult = failedFuture.forceGetFailure; id failureResult = failedFuture.forceGetFailure;
if ([failureResult isKindOfClass:[NSError class]]) { if ([failureResult isKindOfClass:[NSError class]]) {
return failureHandler((NSError *)failureResult); // Generally we assume that failures are retryable
return failureHandler((NSError *)failureResult, YES);
} }
} }
} }
} }
DDLogWarn(@"%@ Unexpected generic failure: %@", self.tag, failure); DDLogWarn(@"%@ Unexpected generic failure: %@", self.tag, failure);
return failureHandler(OWSErrorMakeFailedToSendOutgoingMessageError()); OWSAssert(NO);
return failureHandler(OWSErrorMakeFailedToSendOutgoingMessageError(), YES);
}]; }];
} }
@ -696,7 +726,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
thread:(TSThread *)thread thread:(TSThread *)thread
attempts:(int)remainingAttempts attempts:(int)remainingAttempts
success:(void (^)())successHandler success:(void (^)())successHandler
failure:(void (^)(NSError *error))failureHandler failure:(RetryableFailureHandler)failureHandler
{ {
DDLogDebug(@"%@ sending message to service: %@", self.tag, message.debugDescription); DDLogDebug(@"%@ sending message to service: %@", self.tag, message.debugDescription);
@ -717,13 +747,15 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
}]; }];
DDLogError(@"%@ Message send failed due to repeated inability to update prekeys.", self.tag); DDLogError(@"%@ Message send failed due to repeated inability to update prekeys.", self.tag);
return failureHandler(OWSErrorMakeMessageSendDisabledDueToPreKeyUpdateFailuresError()); return failureHandler(OWSErrorMakeMessageSendDisabledDueToPreKeyUpdateFailuresError(), YES);
} }
if (remainingAttempts <= 0) { if (remainingAttempts <= 0) {
// We should always fail with a specific error. // We should always fail with a specific error.
DDLogError(@"%@ Unexpected generic failure.", self.tag); DDLogError(@"%@ Unexpected generic failure.", self.tag);
return failureHandler(OWSErrorMakeFailedToSendOutgoingMessageError()); OWSAssert(NO);
return failureHandler(OWSErrorMakeFailedToSendOutgoingMessageError(), YES);
} }
remainingAttempts -= 1; remainingAttempts -= 1;
@ -741,14 +773,18 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeUntrustedIdentityKey, NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeUntrustedIdentityKey,
NSLocalizedString(@"FAILED_SENDING_BECAUSE_UNTRUSTED_IDENTITY_KEY", NSLocalizedString(@"FAILED_SENDING_BECAUSE_UNTRUSTED_IDENTITY_KEY",
@"action sheet header when re-sending message which failed because of untrusted identity keys")); @"action sheet header when re-sending message which failed because of untrusted identity keys"));
return failureHandler(error); // Key will continue to be unaccepted, so no need to retry. It'll only cause us to hit the Pre-Key request
// rate limit
return failureHandler(error, NO);
} }
if ([exception.name isEqualToString:OWSMessageSenderRateLimitedException]) { if ([exception.name isEqualToString:OWSMessageSenderRateLimitedException]) {
NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeSignalServiceRateLimited, NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeSignalServiceRateLimited,
NSLocalizedString(@"FAILED_SENDING_BECAUSE_RATE_LIMIT", NSLocalizedString(@"FAILED_SENDING_BECAUSE_RATE_LIMIT",
@"action sheet header when re-sending message which failed because of too many attempts")); @"action sheet header when re-sending message which failed because of too many attempts"));
return failureHandler(error);
// We're already rate-limited. No need to exacerbate the problem.
return failureHandler(error, NO);
} }
if (remainingAttempts == 0) { if (remainingAttempts == 0) {
@ -756,7 +792,9 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
@"%@ Terminal failure to build any device messages. Giving up with exception:%@", self.tag, exception); @"%@ Terminal failure to build any device messages. Giving up with exception:%@", self.tag, exception);
[self processException:exception outgoingMessage:message inThread:thread]; [self processException:exception outgoingMessage:message inThread:thread];
NSError *error = OWSErrorMakeFailedToSendOutgoingMessageError(); NSError *error = OWSErrorMakeFailedToSendOutgoingMessageError();
return failureHandler(error); // Since we've already repeatedly failed to build messages, it's unlikely that repeating the whole process
// will succeed.
return failureHandler(error, NO);
} }
} }
@ -783,7 +821,9 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
void (^retrySend)() = ^void() { void (^retrySend)() = ^void() {
if (remainingAttempts <= 0) { if (remainingAttempts <= 0) {
return failureHandler(error); // Since we've already repeatedly failed to send to the messaging API,
// it's unlikely that repeating the whole process will succeed.
return failureHandler(error, NO);
} }
dispatch_async([OWSDispatch sendingQueue], ^{ dispatch_async([OWSDispatch sendingQueue], ^{
@ -801,12 +841,14 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
case 401: { case 401: {
DDLogWarn(@"%@ Unable to send due to invalid credentials. Did the user's client get de-authed by registering elsewhere?", self.tag); DDLogWarn(@"%@ Unable to send due to invalid credentials. Did the user's client get de-authed by registering elsewhere?", self.tag);
NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeSignalServiceFailure, NSLocalizedString(@"ERROR_DESCRIPTION_SENDING_UNAUTHORIZED", @"Error message when attempting to send message")); NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeSignalServiceFailure, NSLocalizedString(@"ERROR_DESCRIPTION_SENDING_UNAUTHORIZED", @"Error message when attempting to send message"));
return failureHandler(error); // No need to retry if we've been de-authed.
return failureHandler(error, NO);
} }
case 404: { case 404: {
[self unregisteredRecipient:recipient message:message thread:thread]; [self unregisteredRecipient:recipient message:message thread:thread];
NSError *error = OWSErrorMakeNoSuchSignalRecipientError(); NSError *error = OWSErrorMakeNoSuchSignalRecipientError();
return failureHandler(error); // No need to retry if the recipient is not registered.
return failureHandler(error, NO);
} }
case 409: { case 409: {
// Mismatched devices // Mismatched devices
@ -817,7 +859,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
[NSJSONSerialization JSONObjectWithData:responseData options:0 error:&error]; [NSJSONSerialization JSONObjectWithData:responseData options:0 error:&error];
if (error) { if (error) {
DDLogError(@"%@ Failed to serialize response of mismatched devices: %@", self.tag, error); DDLogError(@"%@ Failed to serialize response of mismatched devices: %@", self.tag, error);
return failureHandler(error); return failureHandler(error, YES);
} }
[self handleMismatchedDevices:serializedResponse recipient:recipient]; [self handleMismatchedDevices:serializedResponse recipient:recipient];
@ -831,7 +873,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
if (!responseData) { if (!responseData) {
DDLogWarn(@"Stale devices but server didn't specify devices in response."); DDLogWarn(@"Stale devices but server didn't specify devices in response.");
NSError *error = OWSErrorMakeUnableToProcessServerResponseError(); NSError *error = OWSErrorMakeUnableToProcessServerResponseError();
return failureHandler(error); return failureHandler(error, YES);
} }
[self handleStaleDevicesWithResponse:responseData recipientId:recipient.uniqueId]; [self handleStaleDevicesWithResponse:responseData recipientId:recipient.uniqueId];
@ -933,7 +975,12 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
success:^{ success:^{
DDLogInfo(@"Succesfully sent sync transcript."); DDLogInfo(@"Succesfully sent sync transcript.");
} }
failure:^(NSError *error) { failure:^(NSError *error, BOOL isRetryable) {
// FIXME: We don't yet honor the isRetryable flag here, since sendSyncTranscriptForMessage
// isn't yet wrapped in our retryable SendMessageOperation. Addressing this would require
// a refactor to the MessageSender. Note that we *do* however continue to respect the
// OWSMessageSenderRetryAttempts, which is an "inner" retry loop, encompassing only the
// messaging API.
DDLogInfo(@"Failed to send sync transcript:%@", error); DDLogInfo(@"Failed to send sync transcript:%@", error);
}]; }];
} }

@ -2,6 +2,8 @@
// Copyright (c) 2017 Open Whisper Systems. All rights reserved. // Copyright (c) 2017 Open Whisper Systems. All rights reserved.
// //
#import "OWSMessageSender.h"
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
@class TSOutgoingMessage; @class TSOutgoingMessage;
@ -20,7 +22,7 @@ extern NSString *const kAttachmentUploadAttachmentIDKey;
- (void)uploadAttachmentStream:(TSAttachmentStream *)attachmentStream - (void)uploadAttachmentStream:(TSAttachmentStream *)attachmentStream
message:(TSOutgoingMessage *)outgoingMessage message:(TSOutgoingMessage *)outgoingMessage
success:(void (^)())successHandler success:(void (^)())successHandler
failure:(void (^)(NSError *error))failureHandler; failure:(RetryableFailureHandler)failureHandler;
@end @end

@ -6,6 +6,7 @@
#import "Cryptography.h" #import "Cryptography.h"
#import "MIMETypeUtil.h" #import "MIMETypeUtil.h"
#import "OWSError.h" #import "OWSError.h"
#import "OWSMessageSender.h"
#import "TSAttachmentStream.h" #import "TSAttachmentStream.h"
#import "TSNetworkManager.h" #import "TSNetworkManager.h"
#import "TSOutgoingMessage.h" #import "TSOutgoingMessage.h"
@ -39,7 +40,7 @@ NSString *const kAttachmentUploadAttachmentIDKey = @"kAttachmentUploadAttachment
- (void)uploadAttachmentStream:(TSAttachmentStream *)attachmentStream - (void)uploadAttachmentStream:(TSAttachmentStream *)attachmentStream
message:(TSOutgoingMessage *)outgoingMessage message:(TSOutgoingMessage *)outgoingMessage
success:(void (^)())successHandler success:(void (^)())successHandler
failure:(void (^)(NSError *_Nonnull))failureHandler failure:(RetryableFailureHandler)failureHandler
{ {
if (attachmentStream.serverId) { if (attachmentStream.serverId) {
DDLogDebug(@"%@ Attachment previously uploaded.", self.tag); DDLogDebug(@"%@ Attachment previously uploaded.", self.tag);
@ -54,7 +55,7 @@ NSString *const kAttachmentUploadAttachmentIDKey = @"kAttachmentUploadAttachment
if (![responseObject isKindOfClass:[NSDictionary class]]) { if (![responseObject isKindOfClass:[NSDictionary class]]) {
DDLogError(@"%@ unexpected response from server: %@", self.tag, responseObject); DDLogError(@"%@ unexpected response from server: %@", self.tag, responseObject);
NSError *error = OWSErrorMakeUnableToProcessServerResponseError(); NSError *error = OWSErrorMakeUnableToProcessServerResponseError();
return failureHandler(error); return failureHandler(error, YES);
} }
NSDictionary *responseDict = (NSDictionary *)responseObject; NSDictionary *responseDict = (NSDictionary *)responseObject;
@ -65,7 +66,7 @@ NSString *const kAttachmentUploadAttachmentIDKey = @"kAttachmentUploadAttachment
NSData *attachmentData = [attachmentStream readDataFromFileWithError:&error]; NSData *attachmentData = [attachmentStream readDataFromFileWithError:&error];
if (error) { if (error) {
DDLogError(@"%@ Failed to read attachment data with error:%@", self.tag, error); DDLogError(@"%@ Failed to read attachment data with error:%@", self.tag, error);
return failureHandler(error); return failureHandler(error, YES);
} }
NSData *encryptionKey; NSData *encryptionKey;
@ -95,7 +96,7 @@ NSString *const kAttachmentUploadAttachmentIDKey = @"kAttachmentUploadAttachment
} }
failure:^(NSURLSessionDataTask *task, NSError *error) { failure:^(NSURLSessionDataTask *task, NSError *error) {
DDLogError(@"%@ Failed to allocate attachment with error: %@", self.tag, error); DDLogError(@"%@ Failed to allocate attachment with error: %@", self.tag, error);
failureHandler(error); failureHandler(error, YES);
}]; }];
} }
@ -104,7 +105,7 @@ NSString *const kAttachmentUploadAttachmentIDKey = @"kAttachmentUploadAttachment
location:(NSString *)location location:(NSString *)location
attachmentId:(NSString *)attachmentId attachmentId:(NSString *)attachmentId
success:(void (^)())successHandler success:(void (^)())successHandler
failure:(void (^)(NSError *error))failureHandler failure:(RetryableFailureHandler)failureHandler
{ {
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:location]]; NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:location]];
request.HTTPMethod = @"PUT"; request.HTTPMethod = @"PUT";
@ -126,7 +127,7 @@ NSString *const kAttachmentUploadAttachmentIDKey = @"kAttachmentUploadAttachment
OWSAssert([NSThread isMainThread]); OWSAssert([NSThread isMainThread]);
if (error) { if (error) {
[self fireProgressNotification:0 attachmentId:attachmentId]; [self fireProgressNotification:0 attachmentId:attachmentId];
return failureHandler(error); return failureHandler(error, YES);
} }
NSInteger statusCode = ((NSHTTPURLResponse *)response).statusCode; NSInteger statusCode = ((NSHTTPURLResponse *)response).statusCode;
@ -134,7 +135,7 @@ NSString *const kAttachmentUploadAttachmentIDKey = @"kAttachmentUploadAttachment
if (!isValidResponse) { if (!isValidResponse) {
DDLogError(@"%@ Unexpected server response: %d", self.tag, (int)statusCode); DDLogError(@"%@ Unexpected server response: %d", self.tag, (int)statusCode);
NSError *invalidResponseError = OWSErrorMakeUnableToProcessServerResponseError(); NSError *invalidResponseError = OWSErrorMakeUnableToProcessServerResponseError();
return failureHandler(invalidResponseError); return failureHandler(invalidResponseError, YES);
} }
successHandler(); successHandler();

Loading…
Cancel
Save