Skip to content

Commit

Permalink
Fix: every realtime auth attempt should check if deadline is reached
Browse files Browse the repository at this point in the history
  • Loading branch information
ricardopereira committed Dec 8, 2016
1 parent b6d6f92 commit efa57ab
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 55 deletions.
57 changes: 4 additions & 53 deletions Source/ARTRealtime.m
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ - (void)transitionSideEffects:(ARTConnectionStateChange *)stateChange {
switch (stateChange.current) {
case ARTRealtimeConnecting: {
[self unlessStateChangesBefore:[ARTDefault realtimeRequestTimeout] do:^{
[weakSelf onConnectionTimeOut];
[[weakSelf getTransport] timeOut];
}];

if (!_reachability) {
Expand Down Expand Up @@ -450,24 +450,6 @@ - (void)transitionSideEffects:(ARTConnectionStateChange *)stateChange {
[self.connection emit:stateChange.current with:stateChange];
}

- (void)onConnectionTimeOut {
NSInteger errorCode;
if (self.auth.authorizing && (self.options.authUrl || self.options.authCallback)) {
errorCode = ARTCodeErrorAuthConfiguredProviderFailure;
}
else {
errorCode = ARTCodeErrorConnectionTimedOut;
}
switch (self.connection.state) {
case ARTRealtimeConnected:
[self transition:ARTRealtimeConnected withErrorInfo:[ARTErrorInfo createWithCode:errorCode status:ARTStateConnectionFailed message:@"timed out"]];
break;
default:
[self transition:ARTRealtimeDisconnected withErrorInfo:[ARTErrorInfo createWithCode:errorCode status:ARTStateConnectionFailed message:@"timed out"]];
break;
}
}

- (void)unlessStateChangesBefore:(NSTimeInterval)deadline do:(void(^)())callback {
// Defer until next event loop execution so that any event emitted in the current
// one doesn't cancel the timeout.
Expand Down Expand Up @@ -615,43 +597,12 @@ - (void)transportReconnectWithHost:(NSString *)host {
[self.transport connect];
}

- (void)transportReconnectWithTokenDetails:(ARTTokenDetails *)tokenDetails error:(NSError *)error {
if (error && (self.options.authUrl || self.options.authCallback)) {
[self.connection setErrorReason:[ARTErrorInfo createWithCode:ARTCodeErrorAuthConfiguredProviderFailure message:error.localizedDescription]];
return;
}
- (void)transportReconnectWithRenewedToken {
_renewingToken = true;
[_transport close];
_transport = [[_transportClass alloc] initWithRest:self.rest options:self.options resumeKey:_transport.resumeKey connectionSerial:_transport.connectionSerial];
_transport.delegate = self;
[_transport connectWithToken:tokenDetails.token error:error];
}

- (void)transportReconnectWithRenewedToken {
self.auth.delegate = nil;
@try {
_renewingToken = true;
__weak __typeof(self) weakSelf = self;
dispatch_block_t work = artDispatchScheduled([ARTDefault realtimeRequestTimeout], ^{
[weakSelf onConnectionTimeOut];
});
[self.auth authorize:nil options:self.options callback:^(ARTTokenDetails *tokenDetails, NSError *error) {
// Cancel scheduled work
artDispatchCancel(work);
// It's still valid?
switch ([[weakSelf connection] state]) {
case ARTRealtimeClosing:
case ARTRealtimeClosed:
return;
default:
break;
}
[[weakSelf getLogger] debug:__FILE__ line:__LINE__ message:@"R:%p WS:%p authorised: %@ error: %@", weakSelf, [weakSelf getTransport], tokenDetails, error];
[weakSelf transportReconnectWithTokenDetails:tokenDetails error:error];
}];
}
@finally {
self.auth.delegate = self;
}
[_transport connectForcingNewToken:true];
}

- (void)onAck:(ARTProtocolMessage *)message {
Expand Down
3 changes: 2 additions & 1 deletion Source/ARTRealtimeTransport.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ typedef NS_ENUM(NSUInteger, ARTRealtimeTransportState) {
- (void)receive:(ARTProtocolMessage *)msg;
- (void)connect;
- (void)connectWithToken:(NSString *)token;
- (void)connectWithToken:(NSString *)token error:(art_nullable NSError *)error;
- (void)connectForcingNewToken:(BOOL)forceNewToken;
- (void)timeOut;
- (void)sendClose;
- (void)sendPing;
- (void)close;
Expand Down
33 changes: 32 additions & 1 deletion Source/ARTWebSocketTransport.m
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#import "ARTEncoder.h"
#import "ARTDefault.h"
#import "ARTRealtimeTransport.h"
#import "ARTGCD.h"

enum {
ARTWsNeverConnected = -1,
Expand Down Expand Up @@ -108,11 +109,25 @@ - (void)connectForcingNewToken:(BOOL)forceNewToken {
}
else {
// New Token
// Transport instance couldn't exist anymore when `authorize` completes or reaches time out.
__weak __typeof(self) weakSelf = self;

dispatch_block_t work = artDispatchScheduled([ARTDefault realtimeRequestTimeout], ^{
[weakSelf timeOut];
});

// Deactivate use of `ARTAuthDelegate`: `authorize` should complete without waiting for a CONNECTED state.
id<ARTAuthDelegate> delegate = self.auth.delegate;
self.auth.delegate = nil;
@try {
__weak __typeof(self) weakSelf = self;
[self.auth authorize:nil options:options callback:^(ARTTokenDetails *tokenDetails, NSError *error) {
// Cancel scheduled work
artDispatchCancel(work);
// It's still valid?
if (_state != ARTRealtimeTransportStateOpening &&
_state != ARTRealtimeTransportStateOpened) {
return;
}
[[weakSelf logger] debug:__FILE__ line:__LINE__ message:@"R:%p WS:%p authorised: %@ error: %@", _delegate, self, tokenDetails, error];
if (error) {
[weakSelf handleAuthTokenError:error];
Expand All @@ -128,6 +143,22 @@ - (void)connectForcingNewToken:(BOOL)forceNewToken {
}
}

- (void)timeOut {
ARTErrorInfo *error;
if (self.auth.authorizing && (self.options.authUrl || self.options.authCallback)) {
error = [ARTErrorInfo createWithCode:ARTCodeErrorAuthConfiguredProviderFailure status:ARTStateConnectionFailed message:@"timed out"];
}
else {
error = [ARTErrorInfo createWithCode:ARTCodeErrorConnectionTimedOut status:ARTStateConnectionFailed message:@"timed out"];
}
if (_state == ARTRealtimeTransportStateOpened) {
[self.delegate realtimeTransportFailed:self withError:[[ARTRealtimeTransportError alloc] initWithError:error type:ARTRealtimeTransportErrorTypeAuth url:self.websocketURL]];
}
else {
[self.delegate realtimeTransportFailed:self withError:[[ARTRealtimeTransportError alloc] initWithError:error type:ARTRealtimeTransportErrorTypeAuth url:self.websocketURL]];
}
}

- (void)handleAuthTokenError:(NSError *)error {
[self.logger error:@"R:%p WS:%p ARTWebSocketTransport: token auth failed with %@", self.delegate, self, error.description];
if (error.code == 40102 /*incompatible credentials*/) {
Expand Down

0 comments on commit efa57ab

Please sign in to comment.