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 15 namespace { 16 NSString* 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