Skip to content

Commit

Permalink
RSC15d (#383)
Browse files Browse the repository at this point in the history
  • Loading branch information
ricardopereira authored and tcard committed Apr 18, 2016
1 parent 812dbe4 commit 1b74461
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 19 deletions.
1 change: 0 additions & 1 deletion Source/ARTFallback.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,5 @@
returns a random fallback host, returns null when all hosts have been popped.
*/
-(NSString *) popFallbackHost;
+(bool) shouldTryFallback:(ARTHttpResponse *) response options:(ARTClientOptions *) options;

@end
36 changes: 18 additions & 18 deletions Source/ARTRest.m
Original file line number Diff line number Diff line change
Expand Up @@ -136,27 +136,30 @@ - (void)executeRequest:(NSMutableURLRequest *)request completion:(void (^)(NSHTT
// Send it again, requesting a new token (forward callback)
[self.logger debug:__FILE__ line:__LINE__ message:@"requesting new token"];
[self executeRequest:request withAuthOption:ARTAuthenticationNewToken completion:callback];
} else if (callback) {
return;
} else {
// Return error with HTTP StatusCode if ARTErrorStatusCode does not exist
if (!dataError) {
dataError = [NSError errorWithDomain:ARTAblyErrorDomain code:response.statusCode userInfo:@{NSLocalizedDescriptionKey:[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]}];
}
callback(nil, nil, dataError);
error = dataError;
}
return;
}
if (!blockFallbacks && [self shouldRetryWithFallback:request response:response error:error]) {
blockFallbacks = [[ARTFallback alloc] init];
}
if (error && blockFallbacks) {
NSString *host = [blockFallbacks popFallbackHost];
if (host != nil) {
NSMutableURLRequest *newRequest = [request copy];
NSURL *url = request.URL;
NSString *urlStr = [NSString stringWithFormat:@"%@://%@:%@%@?%@", url.scheme, host, url.port, url.path, (url.query ? url.query : @"")];
newRequest.URL = [NSURL URLWithString:urlStr];
[self executeRequest:newRequest completion:callback fallbacks:fallbacks];
return;
if ([self shouldRetryWithFallback:request response:response error:error]) {
if (!blockFallbacks && [request.URL.host isEqualToString:[ARTDefault restHost]]) {
blockFallbacks = [[ARTFallback alloc] init];
}
if (blockFallbacks) {
NSString *host = [blockFallbacks popFallbackHost];
if (host != nil) {
[self.logger debug:__FILE__ line:__LINE__ message:@"host is down; retrying request at %@", host];
NSMutableURLRequest *newRequest = [request copy];
NSURL *url = request.URL;
NSString *urlStr = [NSString stringWithFormat:@"%@://%@:%@%@?%@", url.scheme, host, url.port, url.path, (url.query ? url.query : @"")];
newRequest.URL = [NSURL URLWithString:urlStr];
[self executeRequest:newRequest completion:callback fallbacks:fallbacks];
return;
}
}
}
if (callback) {
Expand All @@ -167,9 +170,6 @@ - (void)executeRequest:(NSMutableURLRequest *)request completion:(void (^)(NSHTT
}

- (BOOL)shouldRetryWithFallback:(NSMutableURLRequest *)request response:(NSHTTPURLResponse *)response error:(NSError *)error {
if (![request.URL.host isEqualToString:[ARTDefault restHost]]) {
return NO;
}
if (response.statusCode >= 500 && response.statusCode <= 504) {
return YES;
}
Expand Down
67 changes: 67 additions & 0 deletions Spec/RestClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,73 @@ class RestClient: QuickSpec {

}

// RSC15
context("Host Fallback") {

// RSC15d
context("should use an alternative host when") {

for caseTest: NetworkAnswer in [.HostUnreachable,
.RequestTimeout(timeout: 0.1),
.HostInternalError(code: 501)] {
it("\(caseTest)") {
let options = ARTClientOptions(key: "xxxx:xxxx")
let client = ARTRest(options: options)
client.httpExecutor = testHTTPExecutor
testHTTPExecutor.http = MockHTTP(network: caseTest)
let channel = client.channels.get("test")

testHTTPExecutor.afterRequest = { _ in
if testHTTPExecutor.requests.count == 2 {
// Stop
testHTTPExecutor.http = nil
}
}

waitUntil(timeout: testTimeout) { done in
channel.publish(nil, data: "nil") { _ in
done()
}
}

expect(testHTTPExecutor.requests).to(haveCount(2))
if testHTTPExecutor.requests.count != 2 {
return
}
expect(NSRegularExpression.match(testHTTPExecutor.requests[0].URL!.absoluteString, pattern: "//rest.ably.io")).to(beTrue())
expect(NSRegularExpression.match(testHTTPExecutor.requests[1].URL!.absoluteString, pattern: "//[a-e].ably-realtime.com")).to(beTrue())
}
}

}

// RSC15d
it("should not use an alternative host when the client receives an bad request") {
let options = ARTClientOptions(key: "xxxx:xxxx")
let client = ARTRest(options: options)
client.httpExecutor = testHTTPExecutor
testHTTPExecutor.http = MockHTTP(network: .Host400BadRequest)
let channel = client.channels.get("test")

testHTTPExecutor.afterRequest = { _ in
if testHTTPExecutor.requests.count == 2 {
// Stop
testHTTPExecutor.http = nil
}
}

waitUntil(timeout: testTimeout) { done in
channel.publish(nil, data: "nil") { _ in
done()
}
}

expect(testHTTPExecutor.requests).to(haveCount(1))
expect(NSRegularExpression.match(testHTTPExecutor.requests[0].URL!.absoluteString, pattern: "//rest.ably.io")).to(beTrue())
}

}

} //RestClient
}
}
3 changes: 3 additions & 0 deletions Spec/TestUtilities.swift
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,7 @@ enum NetworkAnswer {
case HostUnreachable
case RequestTimeout(timeout: NSTimeInterval)
case HostInternalError(code: Int)
case Host400BadRequest
case Custom(response: NSHTTPURLResponse?, data: NSData?, error: NSError?)
}

Expand All @@ -524,6 +525,8 @@ class MockHTTP: ARTHttp {
}
case .HostInternalError(let code):
callback?(NSHTTPURLResponse(URL: NSURL(string: "http://ios.test.suite")!, statusCode: code, HTTPVersion: nil, headerFields: nil), nil, nil)
case .Host400BadRequest:
callback?(NSHTTPURLResponse(URL: NSURL(string: "http://ios.test.suite")!, statusCode: 400, HTTPVersion: nil, headerFields: nil), nil, nil)
case .Custom(let response, let data, let error):
callback?(response, data, error)
}
Expand Down

0 comments on commit 1b74461

Please sign in to comment.