1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#if !defined(__has_feature) || !__has_feature(objc_arc) 6#error "This file requires ARC support." 7#endif 8 9#import "remoting/ios/host_refresh.h" 10 11#import "remoting/ios/authorize.h" 12#import "remoting/ios/host.h" 13#import "remoting/ios/utility.h" 14 15namespace { 16NSString* kDefaultErrorMessage = @"The Host list refresh is not available at " 17 @"this time. Please try again later."; 18} // namespace 19 20@interface HostRefresh (Private) 21- (void)authentication:(GTMOAuth2Authentication*)auth 22 request:(NSMutableURLRequest*)request 23 error:(NSError*)error; 24- (void)formatErrorMessage:(NSString*)error; 25- (void)notifyDelegate; 26@end 27 28// Logic flow begins with refreshHostList, and continues until an error occurs, 29// or the host list is returned to the delegate 30@implementation HostRefresh 31 32@synthesize jsonData = _jsonData; 33@synthesize errorMessage = _errorMessage; 34@synthesize delegate = _delegate; 35 36// Override default constructor and initialize internals 37- (id)init { 38 self = [super init]; 39 if (self) { 40 _jsonData = [[NSMutableData alloc] init]; 41 } 42 return self; 43} 44 45// Begin the authentication and authorization process. Begin the process by 46// creating an oAuth2 request to google api's including the needed scopes to 47// fetch the users host list. 48- (void)refreshHostList:(GTMOAuth2Authentication*)authReq 49 delegate:(id<HostRefreshDelegate>)delegate { 50 51 CHECK(_delegate == nil); // Do not reuse an instance of this class 52 53 _delegate = delegate; 54 55 [Authorize beginRequest:authReq 56 delegate:self 57 didFinishSelector:@selector(authentication:request:error:)]; 58} 59 60// Handle completion of the authorization process. Append service credentials 61// for jabber. If an error occurred, notify user. 62- (void)authentication:(NSObject*)auth 63 request:(NSMutableURLRequest*)request 64 error:(NSError*)error { 65 if (error != nil) { 66 [self formatErrorMessage:error.localizedDescription]; 67 } else { 68 // Add credentials for service 69 [Authorize appendCredentials:request]; 70 71 // Begin connection, the returned reference is not useful right now and 72 // marked as __unused 73 __unused NSURLConnection* connection = 74 [[NSURLConnection alloc] initWithRequest:request delegate:self]; 75 } 76} 77 78// @protocol NSURLConnectionDelegate, handle any error during connection 79- (void)connection:(NSURLConnection*)connection 80 didFailWithError:(NSError*)error { 81 [self formatErrorMessage:[error localizedDescription]]; 82 83 [self notifyDelegate]; 84} 85 86// @protocol NSURLConnectionDataDelegate, may be called async multiple times. 87// Each call appends the new data to the known data until completed. 88- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data { 89 [_jsonData appendData:data]; 90} 91 92// @protocol NSURLConnectionDataDelegate 93// Ensure connection succeeded: HTTP 200 OK 94- (void)connection:(NSURLConnection*)connection 95 didReceiveResponse:(NSURLResponse*)response { 96 NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response; 97 if ([response respondsToSelector:@selector(allHeaderFields)]) { 98 NSNumber* responseCode = 99 [[NSNumber alloc] initWithInteger:[httpResponse statusCode]]; 100 if (responseCode.intValue != 200) { 101 [self formatErrorMessage:[NSString 102 stringWithFormat:@"HTTP STATUS CODE: %d", 103 [httpResponse statusCode]]]; 104 } 105 } 106} 107 108// @protocol NSURLConnectionDataDelegate handle a completed connection, parse 109// received data, and return host list to delegate 110- (void)connectionDidFinishLoading:(NSURLConnection*)connection { 111 [self notifyDelegate]; 112} 113 114// Store a formatted error message to return later 115- (void)formatErrorMessage:(NSString*)error { 116 _errorMessage = kDefaultErrorMessage; 117 if (error != nil && error.length > 0) { 118 _errorMessage = [_errorMessage 119 stringByAppendingString:[@" " stringByAppendingString:error]]; 120 } 121} 122 123// The connection has finished, call to delegate 124- (void)notifyDelegate { 125 if (_jsonData.length == 0 && _errorMessage == nil) { 126 [self formatErrorMessage:nil]; 127 } 128 129 [_delegate hostListRefresh:[Host parseListFromJSON:_jsonData] 130 errorMessage:_errorMessage]; 131} 132@end 133