Merge tag '2.31.0.37' into release/2.32.0

pull/1/head
Michael Kirk 7 years ago
commit 12b916ad36

@ -198,9 +198,9 @@ private
private func acknowledgeDelivery(envelope: SSKProtoEnvelope) {
let request: TSRequest
if let serverGuid = envelope.serverGuid, envelope.hasServerTimestamp {
if let serverGuid = envelope.serverGuid, envelope.hasServerTimestamp, serverGuid.count > 0, envelope.serverTimestamp > 0 {
request = OWSRequestFactory.acknowledgeMessageDeliveryRequest(withServerGuid: serverGuid, serverTimestamp: envelope.serverTimestamp)
} else if let source = envelope.source {
} else if let source = envelope.source, source.count > 0, envelope.timestamp > 0 {
request = OWSRequestFactory.acknowledgeMessageDeliveryRequest(withSource: source, timestamp: envelope.timestamp)
} else {
owsFailDebug("Cannot ACK message which has neither source, nor server GUID and timestamp.")

@ -137,6 +137,11 @@ NS_ASSUME_NONNULL_BEGIN
[Environment.shared.contactsManager requestSystemContactsOnce];
}]];
[items addObject:[OWSTableItem itemWithTitle:@"Cycle websockets"
actionBlock:^() {
[SSKEnvironment.shared.socketManager cycleSocket];
}]];
return [OWSTableSection sectionWithTitle:self.name items:items];
}

@ -17,7 +17,7 @@ extern uint32_t const OWSDevicePrimaryDeviceId;
- (BOOL)mayHaveLinkedDevices:(YapDatabaseConnection *)dbConnection;
- (void)setMayHaveLinkedDevices;
- (void)clearMayHaveLinkedDevicesIfNotSet;
- (void)clearMayHaveLinkedDevices;
- (BOOL)hasReceivedSyncMessageInLastSeconds:(NSTimeInterval)intervalSeconds;
- (void)setHasReceivedSyncMessage;

@ -62,17 +62,14 @@ NSString *const kOWSPrimaryStorage_MayHaveLinkedDevices = @"kTSStorageManager_Ma
// to avoid unnecessary message sends for sync messages until we learn
// of a linked device (e.g. through the device linking UI or by receiving
// a sync message, etc.).
- (void)clearMayHaveLinkedDevicesIfNotSet
- (void)clearMayHaveLinkedDevices
{
// Note that we write async to avoid opening transactions within transactions.
[OWSPrimaryStorage.sharedManager.newDatabaseConnection
asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
if (![transaction objectForKey:kOWSPrimaryStorage_MayHaveLinkedDevices
inCollection:kOWSPrimaryStorage_OWSDeviceCollection]) {
[transaction setObject:@(NO)
forKey:kOWSPrimaryStorage_MayHaveLinkedDevices
inCollection:kOWSPrimaryStorage_OWSDeviceCollection];
}
[transaction setObject:@(NO)
forKey:kOWSPrimaryStorage_MayHaveLinkedDevices
inCollection:kOWSPrimaryStorage_OWSDeviceCollection];
}];
}

@ -1093,8 +1093,10 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
[[requestMaker makeRequestObjc]
.then(^(OWSRequestMakerResult *result) {
dispatch_async([OWSDispatch sendingQueue], ^{
const BOOL wasSentByUD = result.wasSentByUD;
[self messageSendDidSucceed:messageSend deviceMessages:deviceMessages wasSentByUD:wasSentByUD];
[self messageSendDidSucceed:messageSend
deviceMessages:deviceMessages
wasSentByUD:result.wasSentByUD
wasSentByWebsocket:result.wasSentByWebsocket];
});
})
.catch(^(NSError *error) {
@ -1130,7 +1132,9 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
- (void)messageSendDidSucceed:(OWSMessageSend *)messageSend
deviceMessages:(NSArray<NSDictionary *> *)deviceMessages
wasSentByUD:(BOOL)wasSentByUD {
wasSentByUD:(BOOL)wasSentByUD
wasSentByWebsocket:(BOOL)wasSentByWebsocket
{
OWSAssertDebug(messageSend);
OWSAssertDebug(deviceMessages);
@ -1148,7 +1152,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
// to avoid unnecessary message sends for sync messages until we learn
// of a linked device (e.g. through the device linking UI or by receiving
// a sync message, etc.).
[OWSDeviceManager.sharedManager clearMayHaveLinkedDevicesIfNotSet];
[OWSDeviceManager.sharedManager clearMayHaveLinkedDevices];
}
dispatch_async([OWSDispatch sendingQueue], ^{

@ -23,11 +23,16 @@ public class RequestMakerResult: NSObject {
@objc
public let wasSentByUD: Bool
@objc
public let wasSentByWebsocket: Bool
@objc
public init(responseObject: Any?,
wasSentByUD: Bool) {
wasSentByUD: Bool,
wasSentByWebsocket: Bool) {
self.responseObject = responseObject
self.wasSentByUD = wasSentByUD
self.wasSentByWebsocket = wasSentByWebsocket
}
}
@ -114,12 +119,11 @@ public class RequestMaker: NSObject {
}
let isUDRequest: Bool = udAccessForRequest != nil
let request: TSRequest = requestFactoryBlock(udAccessForRequest?.udAccessKey)
let webSocketType: OWSWebSocketType = (isUDRequest ? .UD : .default)
let canMakeWebsocketRequests = (socketManager.canMakeRequests(of: webSocketType) && !skipWebsocket)
let canMakeWebsocketRequests = (socketManager.canMakeRequests() && !skipWebsocket && !isUDRequest)
if canMakeWebsocketRequests {
return Promise { resolver in
socketManager.make(request, webSocketType: webSocketType, success: { (responseObject: Any?) in
socketManager.make(request, success: { (responseObject: Any?) in
if self.udManager.isUDVerboseLoggingEnabled() {
if isUDRequest {
Logger.debug("UD websocket request '\(self.label)' succeeded.")
@ -130,7 +134,9 @@ public class RequestMaker: NSObject {
self.requestSucceeded(udAccess: udAccessForRequest)
resolver.fulfill(RequestMakerResult(responseObject: responseObject, wasSentByUD: isUDRequest))
resolver.fulfill(RequestMakerResult(responseObject: responseObject,
wasSentByUD: isUDRequest,
wasSentByWebsocket: true))
}) { (statusCode: Int, responseData: Data?, error: Error) in
resolver.reject(RequestMakerError.websocketRequestError(statusCode: statusCode, responseData: responseData, underlyingError: error))
}
@ -179,7 +185,9 @@ public class RequestMaker: NSObject {
self.requestSucceeded(udAccess: udAccessForRequest)
// Unwrap the network manager promise into a request maker promise.
return RequestMakerResult(responseObject: networkManagerResult.responseObject, wasSentByUD: isUDRequest)
return RequestMakerResult(responseObject: networkManagerResult.responseObject,
wasSentByUD: isUDRequest,
wasSentByWebsocket: false)
}.recover { (error: Error) -> Promise<RequestMakerResult> in
switch error {
case NetworkManagerError.taskError(let task, _):

@ -419,6 +419,8 @@ NS_ASSUME_NONNULL_BEGIN
// Don't bother with the default cookie store;
// these cookies are ephemeral.
//
// NOTE: TSNetworkManager now separately disables default cookie handling for all requests.
[request setHTTPShouldHandleCookies:NO];
return request;
@ -451,6 +453,8 @@ NS_ASSUME_NONNULL_BEGIN
// Don't bother with the default cookie store;
// these cookies are ephemeral.
//
// NOTE: TSNetworkManager now separately disables default cookie handling for all requests.
[request setHTTPShouldHandleCookies:NO];
// Set the cookie header.
OWSAssertDebug(request.allHTTPHeaderFields.count == 0);
@ -489,6 +493,8 @@ NS_ASSUME_NONNULL_BEGIN
// Add UD auth header.
[request setValue:[udAccessKey.keyData base64EncodedString] forHTTPHeaderField:@"Unidentified-Access-Key"];
request.isUDRequest = YES;
}
@end

@ -6,6 +6,7 @@
@interface TSRequest : NSMutableURLRequest
@property (nonatomic) BOOL isUDRequest;
@property (nonatomic) BOOL shouldHaveAuthorizationHeaders;
@property (atomic, nullable) NSString *authUsername;
@property (atomic, nullable) NSString *authPassword;

@ -25,12 +25,20 @@ BOOL IsNSErrorNetworkFailure(NSError *_Nullable error)
@interface TSNetworkManager ()
// This property should only be accessed on udSerialQueue.
@property (atomic, readonly) AFHTTPSessionManager *udSessionManager;
@property (atomic, readonly) dispatch_queue_t udSerialQueue;
typedef void (^failureBlock)(NSURLSessionDataTask *task, NSError *error);
@end
@implementation TSNetworkManager
@synthesize udSessionManager = _udSessionManager;
@synthesize udSerialQueue = _udSerialQueue;
#pragma mark Singleton implementation
+ (instancetype)sharedManager
@ -47,6 +55,8 @@ typedef void (^failureBlock)(NSURLSessionDataTask *task, NSError *error);
return self;
}
_udSerialQueue = dispatch_queue_create("org.whispersystems.networkManager.udQueue", DISPATCH_QUEUE_SERIAL);
OWSSingletonAssert();
return self;
@ -70,9 +80,15 @@ typedef void (^failureBlock)(NSURLSessionDataTask *task, NSError *error);
OWSAssertDebug(successBlock);
OWSAssertDebug(failureBlock);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self makeRequestSync:request completionQueue:completionQueue success:successBlock failure:failureBlock];
});
if (request.isUDRequest) {
dispatch_async(self.udSerialQueue, ^{
[self makeUDRequestSync:request success:successBlock failure:failureBlock];
});
} else {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self makeRequestSync:request completionQueue:completionQueue success:successBlock failure:failureBlock];
});
}
}
- (void)makeRequestSync:(TSRequest *)request
@ -84,11 +100,11 @@ typedef void (^failureBlock)(NSURLSessionDataTask *task, NSError *error);
OWSAssertDebug(successBlock);
OWSAssertDebug(failureBlock);
OWSLogInfo(@"Making request: %@", request);
OWSLogInfo(@"Making Non-UD request: %@", request);
// TODO: Remove this logging when the call connection issues have been resolved.
TSNetworkManagerSuccess success = ^(NSURLSessionDataTask *task, _Nullable id responseObject) {
OWSLogInfo(@"request succeeded : %@", request);
OWSLogInfo(@"Non-UD request succeeded : %@", request);
if (request.shouldHaveAuthorizationHeaders) {
[TSAccountManager.sharedInstance setIsDeregistered:NO];
@ -110,17 +126,71 @@ typedef void (^failureBlock)(NSURLSessionDataTask *task, NSError *error);
password:request.authPassword];
}
// Honor the request's preferences about default cookie handling.
//
// Default is YES.
sessionManager.requestSerializer.HTTPShouldHandleCookies = request.HTTPShouldHandleCookies;
// Honor the request's headers.
for (NSString *headerField in request.allHTTPHeaderFields) {
NSString *headerValue = request.allHTTPHeaderFields[headerField];
[sessionManager.requestSerializer setValue:headerValue forHTTPHeaderField:headerField];
}
[self performRequest:request sessionManager:sessionManager success:success failure:failure];
}
// This method should only be invoked on udSerialQueue.
- (AFHTTPSessionManager *)udSessionManager
{
if (!_udSessionManager) {
_udSessionManager = [OWSSignalService sharedInstance].signalServiceSessionManager;
_udSessionManager.completionQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// NOTE: We could enable HTTPShouldUsePipelining here.
}
return _udSessionManager;
}
- (void)makeUDRequestSync:(TSRequest *)request
success:(TSNetworkManagerSuccess)successBlock
failure:(TSNetworkManagerFailure)failureBlock
{
OWSAssertDebug(request);
OWSAssert(!request.shouldHaveAuthorizationHeaders);
OWSAssertDebug(successBlock);
OWSAssertDebug(failureBlock);
OWSLogInfo(@"Making UD request: %@", request);
TSNetworkManagerSuccess success = ^(NSURLSessionDataTask *task, _Nullable id responseObject) {
OWSLogInfo(@"UD request succeeded : %@", request);
successBlock(task, responseObject);
[OutageDetection.sharedManager reportConnectionSuccess];
};
TSNetworkManagerFailure failure = [TSNetworkManager errorPrettifyingForFailureBlock:failureBlock request:request];
AFHTTPSessionManager *sessionManager = self.udSessionManager;
// Honor the request's headers.
for (NSString *headerField in sessionManager.requestSerializer.HTTPRequestHeaders.allKeys.copy) {
[sessionManager.requestSerializer setValue:nil forHTTPHeaderField:headerField];
}
for (NSString *headerField in request.allHTTPHeaderFields) {
NSString *headerValue = request.allHTTPHeaderFields[headerField];
[sessionManager.requestSerializer setValue:headerValue forHTTPHeaderField:headerField];
}
[self performRequest:request sessionManager:sessionManager success:success failure:failure];
}
- (void)performRequest:(TSRequest *)request
sessionManager:(AFHTTPSessionManager *)sessionManager
success:(TSNetworkManagerSuccess)success
failure:(TSNetworkManagerFailure)failure
{
OWSAssertDebug(request);
OWSAssertDebug(sessionManager);
OWSAssertDebug(success);
OWSAssertDebug(failure);
if ([request.HTTPMethod isEqualToString:@"GET"]) {
[sessionManager GET:request.URL.absoluteString
parameters:request.parameters

@ -168,6 +168,8 @@ NSString *const kNSNotificationName_IsCensorshipCircumventionActiveDidChange =
sessionManager.securityPolicy = [OWSHTTPSecurityPolicy sharedPolicy];
sessionManager.requestSerializer = [AFJSONRequestSerializer serializer];
sessionManager.responseSerializer = [AFJSONResponseSerializer serializer];
// Disable default cookie handling for all requests.
sessionManager.requestSerializer.HTTPShouldHandleCookies = NO;
return sessionManager;
}
@ -186,6 +188,8 @@ NSString *const kNSNotificationName_IsCensorshipCircumventionActiveDidChange =
sessionManager.requestSerializer = [AFJSONRequestSerializer serializer];
[sessionManager.requestSerializer setValue:self.censorshipConfiguration.signalServiceReflectorHost forHTTPHeaderField:@"Host"];
sessionManager.responseSerializer = [AFJSONResponseSerializer serializer];
// Disable default cookie handling for all requests.
sessionManager.requestSerializer.HTTPShouldHandleCookies = NO;
return sessionManager;
}

@ -8,11 +8,6 @@ static void *OWSWebSocketStateObservationContext = &OWSWebSocketStateObservation
extern NSString *const kNSNotification_OWSWebSocketStateDidChange;
typedef NS_ENUM(NSUInteger, OWSWebSocketType) {
OWSWebSocketTypeDefault,
OWSWebSocketTypeUD,
};
typedef NS_ENUM(NSUInteger, OWSWebSocketState) {
OWSWebSocketStateClosed,
OWSWebSocketStateConnecting,
@ -29,8 +24,7 @@ typedef void (^TSSocketMessageFailure)(NSInteger statusCode, NSData *_Nullable r
@property (nonatomic, readonly) OWSWebSocketState state;
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithWebSocketType:(OWSWebSocketType)webSocketType NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_DESIGNATED_INITIALIZER;
// If the app is in the foreground, we'll try to open the socket unless it's already
// open or connecting.

@ -143,21 +143,9 @@ NSString *const kNSNotification_OWSWebSocketStateDidChange = @"kNSNotification_O
#pragma mark -
NSString *NSStringFromOWSWebSocketType(OWSWebSocketType type)
{
switch (type) {
case OWSWebSocketTypeDefault:
return @"Default";
case OWSWebSocketTypeUD:
return @"UD";
}
}
// OWSWebSocket's properties should only be accessed from the main thread.
@interface OWSWebSocket () <SRWebSocketDelegate>
@property (nonatomic) OWSWebSocketType webSocketType;
// This class has a few "tiers" of state.
//
// The first tier is the actual websocket and the timers used
@ -216,7 +204,7 @@ NSString *NSStringFromOWSWebSocketType(OWSWebSocketType type)
@implementation OWSWebSocket
- (instancetype)initWithWebSocketType:(OWSWebSocketType)webSocketType
- (instancetype)init
{
self = [super init];
@ -226,7 +214,6 @@ NSString *NSStringFromOWSWebSocketType(OWSWebSocketType type)
OWSAssertIsOnMainThread();
_webSocketType = webSocketType;
_state = OWSWebSocketStateClosed;
_socketMessageMap = [NSMutableDictionary new];
@ -573,12 +560,11 @@ NSString *NSStringFromOWSWebSocketType(OWSWebSocketType type)
[socketMessage didFailBeforeSending];
return;
}
OWSLogInfo(@"making request: %llu, %@: %@, jsonData.length: %zd, socketType: %@",
OWSLogInfo(@"making request: %llu, %@: %@, jsonData.length: %zd",
socketMessage.requestId,
request.HTTPMethod,
requestPath,
jsonData.length,
NSStringFromOWSWebSocketType(self.webSocketType));
jsonData.length);
const int64_t kSocketTimeoutSeconds = 10;
__weak TSSocketMessage *weakSocketMessage = socketMessage;
@ -650,7 +636,7 @@ NSString *NSStringFromOWSWebSocketType(OWSWebSocketType type)
[socketMessage didSucceedWithResponseObject:responseObject];
} else {
if (responseStatus == 403 && self.webSocketType == OWSWebSocketTypeDefault) {
if (responseStatus == 403) {
// This should be redundant with our check for the socket
// failing due to 403, but let's be thorough.
[self.tsAccountManager setIsDeregistered:YES];
@ -718,7 +704,7 @@ NSString *NSStringFromOWSWebSocketType(OWSWebSocketType type)
if ([error.domain isEqualToString:SRWebSocketErrorDomain] && error.code == 2132) {
NSNumber *_Nullable statusCode = error.userInfo[SRHTTPResponseErrorKey];
if (statusCode.unsignedIntegerValue == 403 && self.webSocketType == OWSWebSocketTypeDefault) {
if (statusCode.unsignedIntegerValue == 403) {
[self.tsAccountManager setIsDeregistered:YES];
}
}
@ -910,16 +896,9 @@ NSString *NSStringFromOWSWebSocketType(OWSWebSocketType type)
- (NSString *)webSocketAuthenticationString
{
switch (self.webSocketType) {
case OWSWebSocketTypeUD:
// UD socket is unauthenticated.
return @"";
case OWSWebSocketTypeDefault:
return
[NSString stringWithFormat:@"?login=%@&password=%@",
[[TSAccountManager localNumber] stringByReplacingOccurrencesOfString:@"+" withString:@"%2B"],
[TSAccountManager serverAuthToken]];
}
return [NSString stringWithFormat:@"?login=%@&password=%@",
[[TSAccountManager localNumber] stringByReplacingOccurrencesOfString:@"+" withString:@"%2B"],
[TSAccountManager serverAuthToken]];
}
#pragma mark - Socket LifeCycle
@ -1149,9 +1128,7 @@ NSString *NSStringFromOWSWebSocketType(OWSWebSocketType type)
{
OWSAssertIsOnMainThread();
if (self.webSocketType == OWSWebSocketTypeDefault) {
[self cycleSocket];
}
[self cycleSocket];
}
@end

@ -39,10 +39,9 @@ NS_ASSUME_NONNULL_BEGIN
#pragma mark - Message Sending
- (BOOL)canMakeRequestsOfType:(OWSWebSocketType)webSocketType;
- (BOOL)canMakeRequests;
- (void)makeRequest:(TSRequest *)request
webSocketType:(OWSWebSocketType)webSocketType
success:(TSSocketMessageSuccess)success
failure:(TSSocketMessageFailure)failure;

@ -9,8 +9,7 @@ NS_ASSUME_NONNULL_BEGIN
@interface TSSocketManager ()
@property (nonatomic) OWSWebSocket *websocketDefault;
@property (nonatomic) OWSWebSocket *websocketUD;
@property (nonatomic) OWSWebSocket *websocket;
@end
@ -28,8 +27,7 @@ NS_ASSUME_NONNULL_BEGIN
OWSAssertIsOnMainThread();
_websocketDefault = [[OWSWebSocket alloc] initWithWebSocketType:OWSWebSocketTypeDefault];
_websocketUD = [[OWSWebSocket alloc] initWithWebSocketType:OWSWebSocketTypeUD];
_websocket = [[OWSWebSocket alloc] init];
OWSSingletonAssert();
@ -48,51 +46,31 @@ NS_ASSUME_NONNULL_BEGIN
return SSKEnvironment.shared.socketManager;
}
- (OWSWebSocket *)webSocketOfType:(OWSWebSocketType)webSocketType
- (BOOL)canMakeRequests
{
switch (webSocketType) {
case OWSWebSocketTypeDefault:
return self.websocketDefault;
case OWSWebSocketTypeUD:
return self.websocketUD;
}
}
- (BOOL)canMakeRequestsOfType:(OWSWebSocketType)webSocketType
{
return [self webSocketOfType:webSocketType].canMakeRequests;
return self.websocket.canMakeRequests;
}
- (void)makeRequest:(TSRequest *)request
webSocketType:(OWSWebSocketType)webSocketType
success:(TSSocketMessageSuccess)success
failure:(TSSocketMessageFailure)failure
{
[[self webSocketOfType:webSocketType] makeRequest:request success:success failure:failure];
[self.websocket makeRequest:request success:success failure:failure];
}
- (void)requestSocketOpen
{
[self.websocketDefault requestSocketOpen];
[self.websocketUD requestSocketOpen];
[self.websocket requestSocketOpen];
}
- (void)cycleSocket
{
[self.websocketDefault cycleSocket];
[self.websocketUD cycleSocket];
[self.websocket cycleSocket];
}
- (OWSWebSocketState)highestSocketState
{
if (self.websocketDefault.state == OWSWebSocketStateOpen || self.websocketUD.state == OWSWebSocketStateOpen) {
return OWSWebSocketStateOpen;
} else if (self.websocketDefault.state == OWSWebSocketStateConnecting
|| self.websocketUD.state == OWSWebSocketStateConnecting) {
return OWSWebSocketStateConnecting;
} else {
return OWSWebSocketStateClosed;
}
return self.websocket.state;
}
@end

Loading…
Cancel
Save