diff --git a/Source/ARTAuth.m b/Source/ARTAuth.m index ba771520c..690c2c34b 100644 --- a/Source/ARTAuth.m +++ b/Source/ARTAuth.m @@ -260,6 +260,7 @@ - (NSMutableURLRequest *)buildRequest:(ARTAuthOptions *)options withParams:(ARTT NSURL *url = [self buildURL:options withParams:params]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; request.HTTPMethod = options.authMethod; + [request setTimeoutInterval:_options.httpRequestTimeout]; // HTTP Header Fields if ([options isMethodPOST]) { @@ -370,7 +371,7 @@ - (void)requestToken:(ARTTokenParams *)tokenParams ARTLogDebug(self.logger, @"RS:%p using authUrl (%@ %@)", _rest, request.HTTPMethod, request.URL); - task = [_rest executeRequest:request withAuthOption:ARTAuthenticationOff wrapperSDKAgents:nil completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { + task = [_rest executeExternalRequest:request completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { if (error) { checkerCallback(nil, error); } else { @@ -508,7 +509,7 @@ - (void)handleAuthUrlResponse:(NSHTTPURLResponse *)response [request setValue:[encoder mimeType] forHTTPHeaderField:@"Accept"]; [request setValue:[encoder mimeType] forHTTPHeaderField:@"Content-Type"]; - return [_rest executeRequest:request withAuthOption:ARTAuthenticationOff wrapperSDKAgents:nil completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { + return [_rest executeAblyRequest:request withAuthOption:ARTAuthenticationOff wrapperSDKAgents:nil completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { if (error) { callback(nil, error); } else { diff --git a/Source/ARTHTTPPaginatedResponse.m b/Source/ARTHTTPPaginatedResponse.m index ca2ef69bf..5ecd5f8b4 100644 --- a/Source/ARTHTTPPaginatedResponse.m +++ b/Source/ARTHTTPPaginatedResponse.m @@ -93,7 +93,7 @@ + (void)executePaginated:(ARTRestInternal *)rest callback:(ARTHTTPPaginatedCallback)callback { ARTLogDebug(logger, @"HTTP Paginated request: %@", request); - [rest executeRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:wrapperSDKAgents completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { + [rest executeAblyRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:wrapperSDKAgents completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { if (error && ![error.domain isEqualToString:ARTAblyErrorDomain]) { callback(nil, [ARTErrorInfo createFromNSError:error]); return; diff --git a/Source/ARTPaginatedResult.m b/Source/ARTPaginatedResult.m index f55428ea1..d0dee3568 100644 --- a/Source/ARTPaginatedResult.m +++ b/Source/ARTPaginatedResult.m @@ -147,7 +147,7 @@ - (void)next:(void (^)(ARTPaginatedResult *_Nullable result, ARTErrorInfo *_ + (void)executePaginated:(ARTRestInternal *)rest withRequest:(NSMutableURLRequest *)request andResponseProcessor:(ARTPaginatedResultResponseProcessor)responseProcessor wrapperSDKAgents:(nullable NSStringDictionary *)wrapperSDKAgents logger:(ARTInternalLog *)logger callback:(void (^)(ARTPaginatedResult *_Nullable result, ARTErrorInfo *_Nullable error))callback { ARTLogDebug(logger, @"Paginated request: %@", request); - [rest executeRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:wrapperSDKAgents completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { + [rest executeAblyRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:wrapperSDKAgents completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { if (error) { callback(nil, [ARTErrorInfo createFromNSError:error]); } else { diff --git a/Source/ARTPushActivationStateMachine.m b/Source/ARTPushActivationStateMachine.m index f9e44b5cc..f3de57bfe 100644 --- a/Source/ARTPushActivationStateMachine.m +++ b/Source/ARTPushActivationStateMachine.m @@ -197,7 +197,7 @@ - (void)deviceRegistration:(ARTErrorInfo *)error { [request setValue:[[self->_rest defaultEncoder] mimeType] forHTTPHeaderField:@"Content-Type"]; ARTLogDebug(self->_logger, @"%@: device registration with request %@", NSStringFromClass(self.class), request); - [self->_rest executeRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:nil completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { + [self->_rest executeAblyRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:nil completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { if (error) { ARTLogError(self->_logger, @"%@: device registration failed (%@)", NSStringFromClass(self.class), error.localizedDescription); [self sendEvent:[ARTPushActivationEventGettingDeviceRegistrationFailed newWithError:[ARTErrorInfo createFromNSError:error]]]; @@ -263,7 +263,7 @@ - (void)deviceUpdateRegistration:(ARTErrorInfo *)error { [request setDeviceAuthentication:local]; ARTLogDebug(_logger, @"%@: update device with request %@", NSStringFromClass(self.class), request); - [_rest executeRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:nil completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { + [_rest executeAblyRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:nil completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { if (error) { ARTLogError(self->_logger, @"%@: update device failed (%@)", NSStringFromClass(self.class), error.localizedDescription); [self sendEvent:[ARTPushActivationEventSyncRegistrationFailed newWithError:[ARTErrorInfo createFromNSError:error]]]; @@ -311,7 +311,7 @@ - (void)syncDevice { [request setDeviceAuthentication:local]; ARTLogDebug(self->_logger, @"%@: sync device with request %@", NSStringFromClass(self.class), request); - [self->_rest executeRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:nil completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { + [self->_rest executeAblyRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:nil completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { if (error) { ARTLogError(self->_logger, @"%@: device registration failed (%@)", NSStringFromClass(self.class), error.localizedDescription); [self sendEvent:[ARTPushActivationEventSyncRegistrationFailed newWithError:[ARTErrorInfo createFromNSError:error]]]; @@ -366,7 +366,7 @@ - (void)deviceUnregistration:(ARTErrorInfo *)error { [request setDeviceAuthentication:local]; ARTLogDebug(_logger, @"%@: device deregistration with request %@", NSStringFromClass(self.class), request); - [_rest executeRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:nil completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { + [_rest executeAblyRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:nil completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { if (error) { // RSH3d2c1: ignore unauthorized or invalid credentials errors if (response.statusCode == 401 || error.code == 40005) { diff --git a/Source/ARTPushAdmin.m b/Source/ARTPushAdmin.m index 5d5591ac4..81b110e44 100644 --- a/Source/ARTPushAdmin.m +++ b/Source/ARTPushAdmin.m @@ -84,7 +84,7 @@ - (void)publish:(ARTPushRecipient *)recipient data:(ARTJsonObject *)data wrapper [request setValue:[[self->_rest defaultEncoder] mimeType] forHTTPHeaderField:@"Content-Type"]; ARTLogDebug(self->_logger, @"push notification to a single device %@", request); - [self->_rest executeRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:wrapperSDKAgents completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { + [self->_rest executeAblyRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:wrapperSDKAgents completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { if (error) { ARTLogError(self->_logger, @"%@: push notification to a single device failed (%@)", NSStringFromClass(self.class), error.localizedDescription); if (callback) callback([ARTErrorInfo createFromNSError:error]); diff --git a/Source/ARTPushChannel.m b/Source/ARTPushChannel.m index 6fb88c5e1..95bc551fe 100644 --- a/Source/ARTPushChannel.m +++ b/Source/ARTPushChannel.m @@ -130,7 +130,7 @@ - (void)subscribeDeviceWithWrapperSDKAgents:(nullable NSStringDictionary *)wrapp [request setDeviceAuthentication:deviceId localDevice:device]; ARTLogDebug(self->_logger, @"subscribe notifications for device %@ in channel %@", deviceId, self->_channel.name); - [self->_rest executeRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:wrapperSDKAgents completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { + [self->_rest executeAblyRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:wrapperSDKAgents completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { if (error) { ARTLogError(self->_logger, @"%@: subscribe notifications for device %@ in channel %@ failed (%@)", NSStringFromClass(self.class), deviceId, self->_channel.name, error.localizedDescription); } @@ -164,7 +164,7 @@ - (void)subscribeClientWithWrapperSDKAgents:(nullable NSStringDictionary *)wrapp [request setValue:[[self->_rest defaultEncoder] mimeType] forHTTPHeaderField:@"Content-Type"]; ARTLogDebug(self->_logger, @"subscribe notifications for clientId %@ in channel %@", clientId, self->_channel.name); - [self->_rest executeRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:wrapperSDKAgents completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { + [self->_rest executeAblyRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:wrapperSDKAgents completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { if (error) { ARTLogError(self->_logger, @"%@: subscribe notifications for clientId %@ in channel %@ failed (%@)", NSStringFromClass(self.class), clientId, self->_channel.name, error.localizedDescription); } @@ -201,7 +201,7 @@ - (void)unsubscribeDeviceWithWrapperSDKAgents:(nullable NSStringDictionary *)wra [request setDeviceAuthentication:deviceId localDevice:device]; ARTLogDebug(self->_logger, @"unsubscribe notifications for device %@ in channel %@", deviceId, self->_channel.name); - [self->_rest executeRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:wrapperSDKAgents completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { + [self->_rest executeAblyRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:wrapperSDKAgents completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { if (error) { ARTLogError(self->_logger, @"%@: unsubscribe notifications for device %@ in channel %@ failed (%@)", NSStringFromClass(self.class), deviceId, self->_channel.name, error.localizedDescription); } @@ -236,7 +236,7 @@ - (void)unsubscribeClientWithWrapperSDKAgents:(nullable NSStringDictionary *)wra request.HTTPMethod = @"DELETE"; ARTLogDebug(self->_logger, @"unsubscribe notifications for clientId %@ in channel %@", clientId, self->_channel.name); - [self->_rest executeRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:wrapperSDKAgents completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { + [self->_rest executeAblyRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:wrapperSDKAgents completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { if (error) { ARTLogError(self->_logger, @"%@: unsubscribe notifications for clientId %@ in channel %@ failed (%@)", NSStringFromClass(self.class), clientId, self->_channel.name, error.localizedDescription); } diff --git a/Source/ARTPushChannelSubscriptions.m b/Source/ARTPushChannelSubscriptions.m index c250ecafe..9dba08979 100644 --- a/Source/ARTPushChannelSubscriptions.m +++ b/Source/ARTPushChannelSubscriptions.m @@ -91,7 +91,7 @@ - (void)save:(ARTPushChannelSubscription *)channelSubscription wrapperSDKAgents: [request setDeviceAuthentication:channelSubscription.deviceId localDevice:local]; ARTLogDebug(self->_logger, @"save channel subscription with request %@", request); - [self->_rest executeRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:wrapperSDKAgents completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { + [self->_rest executeAblyRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:wrapperSDKAgents completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { if (response.statusCode == 200 /*Ok*/ || response.statusCode == 201 /*Created*/) { ARTLogDebug(self->_logger, @"channel subscription saved successfully"); callback(nil); @@ -209,7 +209,7 @@ - (void)_removeWhere:(NSStringDictionary *)params wrapperSDKAgents:(nullable NSS #endif ARTLogDebug(_logger, @"remove channel subscription with request %@", request); - [_rest executeRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:wrapperSDKAgents completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { + [_rest executeAblyRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:wrapperSDKAgents completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { if (response.statusCode == 200 /*Ok*/ || response.statusCode == 204 /*not returning any content*/) { ARTLogDebug(self->_logger, @"%@: channel subscription removed successfully", NSStringFromClass(self.class)); callback(nil); diff --git a/Source/ARTPushDeviceRegistrations.m b/Source/ARTPushDeviceRegistrations.m index 623e92316..3454e5e30 100644 --- a/Source/ARTPushDeviceRegistrations.m +++ b/Source/ARTPushDeviceRegistrations.m @@ -92,7 +92,7 @@ - (void)save:(ARTDeviceDetails *)deviceDetails wrapperSDKAgents:(nullable NSStri [request setDeviceAuthentication:deviceDetails.id localDevice:local logger:self->_logger]; ARTLogDebug(self->_logger, @"save device with request %@", request); - [self->_rest executeRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:wrapperSDKAgents completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { + [self->_rest executeAblyRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:wrapperSDKAgents completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { if (response.statusCode == 200 /*OK*/) { NSError *decodeError = nil; ARTDeviceDetails *deviceDetails = [[self->_rest defaultEncoder] decodeDeviceDetails:data error:&decodeError]; @@ -140,7 +140,7 @@ - (void)get:(ARTDeviceId *)deviceId wrapperSDKAgents:(nullable NSStringDictionar [request setDeviceAuthentication:deviceId localDevice:local logger:self->_logger]; ARTLogDebug(self->_logger, @"get device with request %@", request); - [self->_rest executeRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:wrapperSDKAgents completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { + [self->_rest executeAblyRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:wrapperSDKAgents completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { if (response.statusCode == 200 /*OK*/) { NSError *decodeError = nil; ARTDeviceDetails *device = [self->_rest.encoders[response.MIMEType] decodeDeviceDetails:data error:&decodeError]; @@ -213,7 +213,7 @@ - (void)remove:(NSString *)deviceId wrapperSDKAgents:(nullable NSStringDictionar [request setValue:[[self->_rest defaultEncoder] mimeType] forHTTPHeaderField:@"Content-Type"]; ARTLogDebug(self->_logger, @"remove device with request %@", request); - [self->_rest executeRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:wrapperSDKAgents completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { + [self->_rest executeAblyRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:wrapperSDKAgents completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { if (response.statusCode == 200 /*Ok*/ || response.statusCode == 204 /*not returning any content*/) { ARTLogDebug(self->_logger, @"%@: save device successfully", NSStringFromClass(self.class)); callback(nil); @@ -258,7 +258,7 @@ - (void)removeWhere:(NSStringDictionary *)params wrapperSDKAgents:(nullable NSSt [request setDeviceAuthentication:[params objectForKey:@"deviceId"] localDevice:local]; ARTLogDebug(self->_logger, @"remove devices with request %@", request); - [self->_rest executeRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:wrapperSDKAgents completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { + [self->_rest executeAblyRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:wrapperSDKAgents completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { if (response.statusCode == 200 /*Ok*/ || response.statusCode == 204 /*not returning any content*/) { ARTLogDebug(self->_logger, @"%@: remove devices successfully", NSStringFromClass(self.class)); callback(nil); diff --git a/Source/ARTRest.m b/Source/ARTRest.m index b17792a3e..35d4862c4 100644 --- a/Source/ARTRest.m +++ b/Source/ARTRest.m @@ -244,41 +244,41 @@ - (NSString *)description { return [NSString stringWithFormat:@"%@ - \n\t %@;", [super description], info]; } -- (NSObject *)executeRequest:(NSMutableURLRequest *)request - withAuthOption:(ARTAuthentication)authOption - wrapperSDKAgents:(nullable NSDictionary *)wrapperSDKAgents - completion:(ARTURLRequestCallback)callback { +- (NSObject *)executeAblyRequest:(NSMutableURLRequest *)request + withAuthOption:(ARTAuthentication)authOption + wrapperSDKAgents:(nullable NSDictionary *)wrapperSDKAgents + completion:(ARTURLRequestCallback)callback { request.URL = [NSURL URLWithString:request.URL.relativeString relativeToURL:self.baseUrl]; switch (authOption) { case ARTAuthenticationOff: - return [self executeRequest:request wrapperSDKAgents:wrapperSDKAgents completion:callback]; + return [self executeAblyRequest:request wrapperSDKAgents:wrapperSDKAgents completion:callback]; case ARTAuthenticationOn: _tokenErrorRetries = 0; - return [self executeRequestWithAuthentication:request withMethod:self.auth.method force:NO wrapperSDKAgents:wrapperSDKAgents completion:callback]; + return [self executeAblyRequestWithAuthentication:request withMethod:self.auth.method force:NO wrapperSDKAgents:wrapperSDKAgents completion:callback]; case ARTAuthenticationNewToken: _tokenErrorRetries = 0; - return [self executeRequestWithAuthentication:request withMethod:self.auth.method force:YES wrapperSDKAgents:wrapperSDKAgents completion:callback]; + return [self executeAblyRequestWithAuthentication:request withMethod:self.auth.method force:YES wrapperSDKAgents:wrapperSDKAgents completion:callback]; case ARTAuthenticationTokenRetry: _tokenErrorRetries = _tokenErrorRetries + 1; - return [self executeRequestWithAuthentication:request withMethod:self.auth.method force:YES wrapperSDKAgents:wrapperSDKAgents completion:callback]; + return [self executeAblyRequestWithAuthentication:request withMethod:self.auth.method force:YES wrapperSDKAgents:wrapperSDKAgents completion:callback]; case ARTAuthenticationUseBasic: - return [self executeRequestWithAuthentication:request withMethod:ARTAuthMethodBasic wrapperSDKAgents:wrapperSDKAgents completion:callback]; + return [self executeAblyRequestWithAuthentication:request withMethod:ARTAuthMethodBasic wrapperSDKAgents:wrapperSDKAgents completion:callback]; } } -- (NSObject *)executeRequestWithAuthentication:(NSMutableURLRequest *)request - withMethod:(ARTAuthMethod)method - wrapperSDKAgents:(nullable NSDictionary *)wrapperSDKAgents - completion:(ARTURLRequestCallback)callback { - return [self executeRequestWithAuthentication:request withMethod:method force:NO wrapperSDKAgents:wrapperSDKAgents completion:callback]; +- (NSObject *)executeAblyRequestWithAuthentication:(NSMutableURLRequest *)request + withMethod:(ARTAuthMethod)method + wrapperSDKAgents:(nullable NSDictionary *)wrapperSDKAgents + completion:(ARTURLRequestCallback)callback { + return [self executeAblyRequestWithAuthentication:request withMethod:method force:NO wrapperSDKAgents:wrapperSDKAgents completion:callback]; } -- (NSObject *)executeRequestWithAuthentication:(NSMutableURLRequest *)request - withMethod:(ARTAuthMethod)method - force:(BOOL)force - wrapperSDKAgents:(nullable NSDictionary *)wrapperSDKAgents - completion:(ARTURLRequestCallback)callback { +- (NSObject *)executeAblyRequestWithAuthentication:(NSMutableURLRequest *)request + withMethod:(ARTAuthMethod)method + force:(BOOL)force + wrapperSDKAgents:(nullable NSDictionary *)wrapperSDKAgents + completion:(ARTURLRequestCallback)callback { ARTLogDebug(self.logger, @"RS:%p calculating authorization %lu", self, (unsigned long)method); __block NSObject *task; @@ -287,7 +287,7 @@ - (NSString *)description { NSString *authorization = [self prepareBasicAuthorisationHeader:self.options.key]; [request setValue:authorization forHTTPHeaderField:@"Authorization"]; ARTLogVerbose(self.logger, @"RS:%p ARTRest: %@", self, authorization); - task = [self executeRequest:request wrapperSDKAgents:wrapperSDKAgents completion:callback]; + task = [self executeAblyRequest:request wrapperSDKAgents:wrapperSDKAgents completion:callback]; } else { if (!force && [self.auth tokenRemainsValid]) { @@ -295,7 +295,7 @@ - (NSString *)description { NSString *authorization = [self prepareTokenAuthorisationHeader:self.auth.tokenDetails.token]; ARTLogVerbose(self.logger, @"RS:%p ARTRestInternal reusing token: authorization bearer in Base64 %@", self, authorization); [request setValue:authorization forHTTPHeaderField:@"Authorization"]; - task = [self executeRequest:request wrapperSDKAgents:wrapperSDKAgents completion:callback]; + task = [self executeAblyRequest:request wrapperSDKAgents:wrapperSDKAgents completion:callback]; } else { // New Token @@ -308,17 +308,42 @@ - (NSString *)description { NSString *authorization = [self prepareTokenAuthorisationHeader:tokenDetails.token]; ARTLogVerbose(self.logger, @"RS:%p ARTRestInternal reissuing token: authorization bearer %@", self, authorization); [request setValue:authorization forHTTPHeaderField:@"Authorization"]; - task = [self executeRequest:request wrapperSDKAgents:wrapperSDKAgents completion:callback]; + task = [self executeAblyRequest:request wrapperSDKAgents:wrapperSDKAgents completion:callback]; }]; } } return task; } -- (NSObject *)executeRequest:(NSURLRequest *)request - wrapperSDKAgents:(nullable NSDictionary *)wrapperSDKAgents - completion:(ARTURLRequestCallback)callback { - return [self executeRequest:request fallbacks:nil retries:0 originalRequestId:nil wrapperSDKAgents:wrapperSDKAgents completion:callback]; +- (nullable NSObject *)executeExternalRequest:(NSURLRequest *)request completion:(nullable ARTURLRequestCallback)callback { + ARTLogDebug(self.logger, @"RS:%p executing request %@", self, request); + + NSObject *task = [self.httpExecutor executeRequest:request completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { + if (response.statusCode >= 400) { + if (!error) { + // Return error with HTTP StatusCode if ARTErrorStatusCode does not exist + error = [ARTErrorInfo createWithCode:response.statusCode * 100 + status:response.statusCode + message:[[NSString alloc] initWithData:data ?: [NSData data] encoding:NSUTF8StringEncoding]]; + } + } + + if (callback) { + if (error != nil) { + callback(response, data, error); + } else { + callback(response, data, nil); + } + } + }]; + + return task; +} + +- (NSObject *)executeAblyRequest:(NSURLRequest *)request + wrapperSDKAgents:(nullable NSDictionary *)wrapperSDKAgents + completion:(ARTURLRequestCallback)callback { + return [self executeAblyRequest:request fallbacks:nil retries:0 originalRequestId:nil wrapperSDKAgents:wrapperSDKAgents completion:callback]; } - (NSString *)agentIdentifierWithWrapperSDKAgents:(nullable NSDictionary *)wrapperSDKAgents { @@ -335,20 +360,135 @@ - (NSString *)agentIdentifierWithWrapperSDKAgents:(nullable NSDictionary *)handleAblyRestRequestCompletion:(NSURLRequest *)request + response:(NSHTTPURLResponse *)response + data:(NSData *)data + error:(NSError *)error + requestId:(nullable NSString *)requestId + fallbacks:(ARTFallback *)fallbacks + retries:(NSUInteger)retries + originalRequestId:(nullable NSString *)originalRequestId + wrapperSDKAgents:(nullable NSDictionary *)wrapperSDKAgents + callback:(ARTURLRequestCallback)callback { + __block ARTFallback *blockFallbacks = fallbacks; + + if (error == nil && data != nil && data.length != 0) { + NSString *contentType = [response.allHeaderFields objectForKey:@"Content-Type"]; + + BOOL validContentType = NO; + for (NSString *mimeType in [self->_encoders.allValues valueForKeyPath:@"mimeType"]) { + if ([contentType containsString:mimeType]) { + validContentType = YES; + break; + } + } + + if (!validContentType) { + NSString *plain = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + // Construct artificial error + error = [ARTErrorInfo createWithCode:response.statusCode * 100 + status:response.statusCode + message:[plain art_shortString] requestId:requestId]; + data = nil; // Discard data; format is unreliable. + ARTLogError(self.logger, @"Request %@ failed with %@", request, error); + } + } + + if (response.statusCode >= 400) { + if (data) { + NSError *decodeError = nil; + ARTErrorInfo *dataError = [self->_encoders[response.MIMEType] decodeErrorInfo:data + statusCode:response.statusCode + error:&decodeError]; + if ([self shouldRenewToken:&dataError] && [request isKindOfClass:[NSMutableURLRequest class]]) { + ARTLogDebug(self.logger, @"RS:%p retry request %@", self, request); + // Make a single attempt to reissue the token and resend the request + if (self->_tokenErrorRetries < 1) { + return [self executeAblyRequest:(NSMutableURLRequest *)request + withAuthOption:ARTAuthenticationTokenRetry + wrapperSDKAgents:wrapperSDKAgents + completion:callback]; + } + } + if (dataError) { + error = dataError; + } + else if (decodeError) { + error = decodeError; + } + } + if (!error) { + // Return error with HTTP StatusCode if ARTErrorStatusCode does not exist + error = [ARTErrorInfo createWithCode:response.statusCode * 100 + status:response.statusCode + message:[[NSString alloc] initWithData:data ?: [NSData data] encoding:NSUTF8StringEncoding] + requestId:requestId]; + } + + } else { + // Response Status Code < 400 and no errors + if (error == nil && self.currentFallbackHost != nil) { + ARTLogDebug(self.logger, @"RS:%p switching `prioritizedHost` to fallback host %@", self, self.currentFallbackHost); + self.prioritizedHost = self.currentFallbackHost; + } + } + + if (retries < self->_options.httpMaxRetryCount && [self shouldRetryWithFallback:request response:response error:error]) { + if (!blockFallbacks) { + NSArray *hosts = [ARTFallbackHosts hostsFromOptions:self->_options]; + blockFallbacks = [[ARTFallback alloc] initWithFallbackHosts:hosts shuffleArray:self->_options.testOptions.shuffleArray]; + } + if (blockFallbacks) { + NSString *host = [blockFallbacks popFallbackHost]; + if (host != nil) { + ARTLogDebug(self.logger, @"RS:%p host is down; retrying request at %@", self, host); + + self.currentFallbackHost = host; + NSMutableURLRequest *newRequest = [request mutableCopy]; + [newRequest setValue:host forHTTPHeaderField:@"Host"]; + newRequest.URL = [NSURL copyFromURL:request.URL withHost:host]; + return [self executeAblyRequest:newRequest + fallbacks:blockFallbacks + retries:retries + 1 + originalRequestId:originalRequestId + wrapperSDKAgents:wrapperSDKAgents + completion:callback]; + } + } + } + if (callback) { + if (error != nil) { + if ([error isKindOfClass:[ARTErrorInfo class]]) { + callback(response, data, error); + } else { + callback(response, data, [NSError copyFromError:error withRequestId:requestId]); + } + } else { + callback(response, data, nil); + } + } + return nil; +} + /** originalRequestId is used only for fallback requests. It should never be used to execute request by yourself, it's passed from within below method. */ -- (NSObject *)executeRequest:(NSURLRequest *)request - fallbacks:(ARTFallback *)fallbacks - retries:(NSUInteger)retries - originalRequestId:(nullable NSString *)originalRequestId - wrapperSDKAgents:(nullable NSDictionary *)wrapperSDKAgents - completion:(ARTURLRequestCallback)callback { +- (NSObject *)executeAblyRequest:(NSURLRequest *)request + fallbacks:(ARTFallback *)fallbacks + retries:(NSUInteger)retries + originalRequestId:(nullable NSString *)originalRequestId + wrapperSDKAgents:(nullable NSDictionary *)wrapperSDKAgents + completion:(ARTURLRequestCallback)callback { NSString *requestId = nil; - __block ARTFallback *blockFallbacks = fallbacks; if ([request isKindOfClass:[NSMutableURLRequest class]]) { NSMutableURLRequest *mutableRequest = (NSMutableURLRequest *)request; + [mutableRequest setAcceptHeader:self.defaultEncoder encoders:self.encoders]; [mutableRequest setTimeoutInterval:_options.httpRequestTimeout]; // Only set X-Ably-Version if it's not already set (allows override for specific methods like stats) @@ -373,7 +513,6 @@ - (NSString *)agentIdentifierWithWrapperSDKAgents:(nullable NSDictionary *task; - task = [self.httpExecutor executeRequest:request completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { - // Error messages in plaintext and HTML format (only if the URL request is different than `options.authUrl` and we don't have an error already) - if (error == nil && data != nil && data.length != 0 && ![request.URL.host isEqualToString:[self.options.authUrl host]]) { - NSString *contentType = [response.allHeaderFields objectForKey:@"Content-Type"]; - - BOOL validContentType = NO; - for (NSString *mimeType in [self->_encoders.allValues valueForKeyPath:@"mimeType"]) { - if ([contentType containsString:mimeType]) { - validContentType = YES; - break; - } - } - - if (!validContentType) { - NSString *plain = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; - // Construct artificial error - error = [ARTErrorInfo createWithCode:response.statusCode * 100 - status:response.statusCode - message:[plain art_shortString] requestId:requestId]; - data = nil; // Discard data; format is unreliable. - ARTLogError(self.logger, @"Request %@ failed with %@", request, error); - } - } - - if (response.statusCode >= 400) { - if (data) { - NSError *decodeError = nil; - ARTErrorInfo *dataError = [self->_encoders[response.MIMEType] decodeErrorInfo:data - statusCode:response.statusCode - error:&decodeError]; - if ([self shouldRenewToken:&dataError] && [request isKindOfClass:[NSMutableURLRequest class]]) { - ARTLogDebug(self.logger, @"RS:%p retry request %@", self, request); - // Make a single attempt to reissue the token and resend the request - if (self->_tokenErrorRetries < 1) { - task = [self executeRequest:(NSMutableURLRequest *)request withAuthOption:ARTAuthenticationTokenRetry wrapperSDKAgents:wrapperSDKAgents completion:callback]; - return; - } - } - if (dataError) { - error = dataError; - } - else if (decodeError) { - error = decodeError; - } - } - if (!error) { - // Return error with HTTP StatusCode if ARTErrorStatusCode does not exist - error = [ARTErrorInfo createWithCode:response.statusCode * 100 - status:response.statusCode - message:[[NSString alloc] initWithData:data ?: [NSData data] encoding:NSUTF8StringEncoding] - requestId:requestId]; - } - - } else { - // Response Status Code < 400 and no errors - if (error == nil && self.currentFallbackHost != nil) { - ARTLogDebug(self.logger, @"RS:%p switching `prioritizedHost` to fallback host %@", self, self.currentFallbackHost); - self.prioritizedHost = self.currentFallbackHost; - } - } - - if (retries < self->_options.httpMaxRetryCount && [self shouldRetryWithFallback:request response:response error:error]) { - if (!blockFallbacks) { - NSArray *hosts = [ARTFallbackHosts hostsFromOptions:self->_options]; - blockFallbacks = [[ARTFallback alloc] initWithFallbackHosts:hosts shuffleArray:self->_options.testOptions.shuffleArray]; - } - if (blockFallbacks) { - NSString *host = [blockFallbacks popFallbackHost]; - if (host != nil) { - ARTLogDebug(self.logger, @"RS:%p host is down; retrying request at %@", self, host); - - self.currentFallbackHost = host; - NSMutableURLRequest *newRequest = [request copy]; - [newRequest setValue:host forHTTPHeaderField:@"Host"]; - newRequest.URL = [NSURL copyFromURL:request.URL withHost:host]; - task = [self executeRequest:newRequest - fallbacks:blockFallbacks - retries:retries + 1 - originalRequestId:originalRequestId - wrapperSDKAgents:wrapperSDKAgents - completion:callback]; - return; - } - } - } - if (callback) { - if (error != nil) { - if ([error isKindOfClass:[ARTErrorInfo class]]) { - callback(response, data, error); - } else { - callback(response, data, [NSError copyFromError:error withRequestId:requestId]); - } - } else { - callback(response, data, nil); - } + + __block NSObject *task = [self.httpExecutor executeRequest:request completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { + NSObject *retryTask = [self handleAblyRestRequestCompletion:request + response:response + data:data + error:error + requestId:requestId + fallbacks:fallbacks + retries:retries + originalRequestId:originalRequestId + wrapperSDKAgents:wrapperSDKAgents + callback:callback]; + if (retryTask) { + task = retryTask; } }]; @@ -557,7 +613,7 @@ - (void)timeWithWrapperSDKAgents:(nullable NSStringDictionary *)wrapperSDKAgents NSString *accept = [[_encoders.allValues valueForKeyPath:@"mimeType"] componentsJoinedByString:@","]; [request setValue:accept forHTTPHeaderField:@"Accept"]; - return [self executeRequest:request withAuthOption:ARTAuthenticationOff wrapperSDKAgents:wrapperSDKAgents completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { + return [self executeAblyRequest:request withAuthOption:ARTAuthenticationOff wrapperSDKAgents:wrapperSDKAgents completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { if (error) { callback(nil, error); return; diff --git a/Source/ARTRestAnnotations.m b/Source/ARTRestAnnotations.m index 62db9ef48..346003cc6 100644 --- a/Source/ARTRestAnnotations.m +++ b/Source/ARTRestAnnotations.m @@ -202,10 +202,10 @@ - (void)publishAnnotation:(ARTOutboundAnnotation *)outboundAnnotation self->_channel.rest, self->_channel, self->_channel.name, [[NSString alloc] initWithData:encodedAnnotation encoding:NSUTF8StringEncoding]); - [self->_channel.rest executeRequest:request - withAuthOption:ARTAuthenticationOn - wrapperSDKAgents:nil - completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { + [self->_channel.rest executeAblyRequest:request + withAuthOption:ARTAuthenticationOn + wrapperSDKAgents:nil + completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { if (callback) { ARTErrorInfo *errorInfo = nil; if (error) { diff --git a/Source/ARTRestChannel.m b/Source/ARTRestChannel.m index 3b05c43bc..b6ac49015 100644 --- a/Source/ARTRestChannel.m +++ b/Source/ARTRestChannel.m @@ -260,7 +260,7 @@ - (void)status:(ARTChannelDetailsCallback)callback { ARTLogDebug(self.logger, @"RS:%p C:%p (%@) channel details request %@", self->_rest, self, self.name, request); - [self->_rest executeRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:nil completion:^(NSHTTPURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable error) { + [self->_rest executeAblyRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:nil completion:^(NSHTTPURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable error) { if (response.statusCode == 200 /*OK*/) { NSError *decodeError = nil; @@ -390,7 +390,7 @@ - (void)internalPostMessages:(id)data callback:(ARTCallback)callback { ARTLogDebug(self.logger, @"RS:%p C:%p (%@) post message %@", self->_rest, self, self.name, [[NSString alloc] initWithData:encodedMessage ?: [NSData data] encoding:NSUTF8StringEncoding]); - [self->_rest executeRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:nil completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { + [self->_rest executeAblyRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:nil completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { if (callback) { ARTErrorInfo *errorInfo; if (self->_rest.options.addRequestIds) { @@ -514,7 +514,7 @@ - (void)_updateMessage:(ARTMessage *)message NSString *logOperation = isDelete ? @"delete" : @"update"; ARTLogDebug(self.logger, @"RS:%p C:%p (%@) %@ message %@", self->_rest, self, self.name, logOperation, [[NSString alloc] initWithData:requestBodyData ?: [NSData data] encoding:NSUTF8StringEncoding]); - [self->_rest executeRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:wrapperSDKAgents completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { + [self->_rest executeAblyRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:wrapperSDKAgents completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { if (callback) { ARTErrorInfo *errorInfo; if (self->_rest.options.addRequestIds) { @@ -569,7 +569,7 @@ - (void)getMessageWithSerial:(NSString *)serial ARTLogDebug(self.logger, @"RS:%p C:%p (%@) get message with serial %@", self->_rest, self, self.name, serial); - [self->_rest executeRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:wrapperSDKAgents completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { + [self->_rest executeAblyRequest:request withAuthOption:ARTAuthenticationOn wrapperSDKAgents:wrapperSDKAgents completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) { if (error) { ARTErrorInfo *errorInfo; if (self->_rest.options.addRequestIds) { diff --git a/Source/PrivateHeaders/Ably/ARTRest+Private.h b/Source/PrivateHeaders/Ably/ARTRest+Private.h index 30bfe1728..2cbb66500 100644 --- a/Source/PrivateHeaders/Ably/ARTRest+Private.h +++ b/Source/PrivateHeaders/Ably/ARTRest+Private.h @@ -71,16 +71,19 @@ NS_ASSUME_NONNULL_BEGIN // MARK: ARTHTTPExecutor -- (nullable NSObject *)executeRequest:(NSURLRequest *)request - wrapperSDKAgents:(nullable NSDictionary *)wrapperSDKAgents - completion:(nullable ARTURLRequestCallback)callback; +- (nullable NSObject *)executeExternalRequest:(NSURLRequest *)request + completion:(nullable ARTURLRequestCallback)callback; // MARK: Internal -- (nullable NSObject *)executeRequest:(NSMutableURLRequest *)request - withAuthOption:(ARTAuthentication)authOption - wrapperSDKAgents:(nullable NSDictionary *)wrapperSDKAgents - completion:(ARTURLRequestCallback)callback; +- (nullable NSObject *)executeAblyRequest:(NSMutableURLRequest *)request + withAuthOption:(ARTAuthentication)authOption + wrapperSDKAgents:(nullable NSDictionary *)wrapperSDKAgents + completion:(ARTURLRequestCallback)callback; + +- (nullable NSObject *)executeAblyRequest:(NSURLRequest *)request + wrapperSDKAgents:(nullable NSDictionary *)wrapperSDKAgents + completion:(nullable ARTURLRequestCallback)callback; - (nullable NSObject *)internetIsUp:(void (^)(BOOL isUp))cb; diff --git a/Test/AblyTests/Tests/AuthTests.swift b/Test/AblyTests/Tests/AuthTests.swift index ad53c2653..c52fcbdd4 100644 --- a/Test/AblyTests/Tests/AuthTests.swift +++ b/Test/AblyTests/Tests/AuthTests.swift @@ -592,6 +592,7 @@ class AuthTests: XCTestCase { fail("ErrorInfo is nil"); done(); return } XCTAssertEqual(errorInfo.code, ARTErrorCode.authConfiguredProviderFailure.intValue) + XCTAssertTrue(errorInfo.description().contains("Invalid request: body param is required")) // see https://github.com/ably/ably-cocoa/issues/2135 done() } realtime.connect() diff --git a/Test/AblyTests/Tests/RealtimeClientConnectionTests.swift b/Test/AblyTests/Tests/RealtimeClientConnectionTests.swift index c7a8dbc68..e035253c1 100644 --- a/Test/AblyTests/Tests/RealtimeClientConnectionTests.swift +++ b/Test/AblyTests/Tests/RealtimeClientConnectionTests.swift @@ -5351,7 +5351,7 @@ class RealtimeClientConnectionTests: XCTestCase { "Accept": "application/json", "Content-Type": "application/json", ] - client.internal.rest.execute(request, withAuthOption: .on, wrapperSDKAgents: nil, completion: { _, _, err in + client.internal.rest.executeAblyRequest(request, withAuthOption: .on, wrapperSDKAgents: nil, completion: { _, _, err in if let err = err { fail("\(err)") } @@ -5377,7 +5377,7 @@ class RealtimeClientConnectionTests: XCTestCase { let request = NSMutableURLRequest(url: URL(string: "/channels/\(channel.name)/messages")!) request.httpMethod = "GET" request.allHTTPHeaderFields = ["Accept": "application/json"] - client.internal.rest.execute(request, withAuthOption: .on, wrapperSDKAgents: nil, completion: { _, data, err in + client.internal.rest.executeAblyRequest(request, withAuthOption: .on, wrapperSDKAgents: nil, completion: { _, data, err in if let err = err { fail("\(err)") done() @@ -5441,7 +5441,7 @@ class RealtimeClientConnectionTests: XCTestCase { "Accept": "application/json", "Content-Type": "application/json", ] - restPublishClient.internal.execute(request, withAuthOption: .on, wrapperSDKAgents: nil, completion: { _, _, err in + restPublishClient.internal.executeAblyRequest(request, withAuthOption: .on, wrapperSDKAgents: nil, completion: { _, _, err in if let err = err { fail("\(err)") } @@ -5507,7 +5507,7 @@ class RealtimeClientConnectionTests: XCTestCase { let request = NSMutableURLRequest(url: URL(string: "/channels/\(restPublishChannel.name)/messages")!) request.httpMethod = "GET" request.allHTTPHeaderFields = ["Accept": "application/json"] - restRetrieveClient.internal.execute(request, withAuthOption: .on, wrapperSDKAgents: nil, completion: { _, data, err in + restRetrieveClient.internal.executeAblyRequest(request, withAuthOption: .on, wrapperSDKAgents: nil, completion: { _, data, err in if let err = err { fail("\(err)") done() diff --git a/Test/AblyTests/Tests/RestClientTests.swift b/Test/AblyTests/Tests/RestClientTests.swift index 1f7ac5983..8d1002aba 100644 --- a/Test/AblyTests/Tests/RestClientTests.swift +++ b/Test/AblyTests/Tests/RestClientTests.swift @@ -1797,7 +1797,7 @@ class RestClientTests: XCTestCase { let request = URLRequest(url: URL(string: "https://www.example.com")!) waitUntil(timeout: testTimeout) { done in let rest = ARTRest(key: "xxxx:xxxx") - rest.internal.execute(request, wrapperSDKAgents:nil, completion: { response, _, error in + rest.internal.executeAblyRequest(request, wrapperSDKAgents:nil, completion: { response, _, error in guard let contentType = response?.allHeaderFields["Content-Type"] as? String else { fail("Response should have a Content-Type"); done(); return } diff --git a/Test/AblyTests/Tests/UtilitiesTests.swift b/Test/AblyTests/Tests/UtilitiesTests.swift index 30837dc62..7ab49c7af 100644 --- a/Test/AblyTests/Tests/UtilitiesTests.swift +++ b/Test/AblyTests/Tests/UtilitiesTests.swift @@ -257,9 +257,9 @@ class UtilitiesTests: XCTestCase { ] ) - let request = URLRequest(url: URL(string: "https://www.example.com")!) + let request = URLRequest(url: URL(string: "https://www.example.com")!) // this should be an Ably address, but we use random since the response is simulated waitUntil(timeout: testTimeout) { done in - rest.internal.execute(request, wrapperSDKAgents:nil, completion: { response, _, error in + rest.internal.executeAblyRequest(request, wrapperSDKAgents:nil, completion: { response, _, error in guard let error = error as? ARTErrorInfo else { fail("Should be ARTErrorInfo"); done(); return } @@ -292,9 +292,9 @@ class UtilitiesTests: XCTestCase { ] ) - let request = URLRequest(url: URL(string: "https://www.example.com")!) + let request = URLRequest(url: URL(string: "https://www.example.com")!) // this should be an Ably address, but we use random since the response is simulated waitUntil(timeout: testTimeout) { done in - rest.internal.execute(request, wrapperSDKAgents:nil, completion: { response, _, error in + rest.internal.executeAblyRequest(request, wrapperSDKAgents:nil, completion: { response, _, error in guard let error = error as? ARTErrorInfo else { fail("Should be ARTErrorInfo"); done(); return }