iOS 6 simulator, using GTLServicePlus after a network interruption results in: "-1003 A server with the specified hostname could not be found."

891 views
Skip to first unread message

Tyson

unread,
Oct 25, 2012, 5:05:55 PM10/25/12
to google-api-obj...@googlegroups.com
Hello,

I have an iOS app that gets data from GTL (Google+ display name and profile picture) and from GData (Google Photos).  During testing in the simulator I've encountered the following error and can't see what is causing it.

- (in the iPhone 6.0 simulator) request user info via GTLServicePlus
- turn off computer's wifi
- turn wifi back on
- (in the iPhone 6.0 simulator) request user info via GTLServicePlus again

The requests appear identical (see below), however the second request *always* returns a -1003 error.  This does not occur in iOS 5 simulator.  I am also making requests to GData via GDataServiceGooglePhotos, and the same thing occurs (always returns -1003 after network comes back).  Third and subsequent requests return no error and work properly.

Both service objects are authorized with a GTMOAuth2Authentication object.  I have tried creating new service objects after the network is restored (with the OAuth object from the keychain), but the same thing occurs.

Timing does not seem to be an issue: I can wait 30 seconds after the network comes back before issuing the second request, with the same result.

Here are two request/responses from the GTMHTTPDebugLogs:

First, before network outage:

plus.people.get

2012-10-25 20:02:40 +0000
Request: POST https://www.googleapis.com/rpc?prettyPrint=false
Request headers:
  Accept: application/json-rpc
  Authorization: Bearer _snip_
  Cache-Control: no-cache
  Content-Type: application/json-rpc; charset=utf-8
  User-Agent: [com.MY.APP.ID]/2.0.1 google-api-objc-client/2.0 iPhone_Simulator/6.0 (gzip)

Request body: (100 bytes)
{
  "method" : "plus.people.get",
  "id" : "gtl_5",
  "jsonrpc" : "2.0",
  "params" : {
    "userId" : "me"
  },
  "apiVersion" : "v1"
}

Response: status 200
Response headers:
  Cache-Control: no-cache, no-store, max-age=0, must-revalidate
  Content-Encoding: gzip
  Content-Length: 342
  Content-Type: application/json; charset=UTF-8
  Date: Thu, 25 Oct 2012 20:02:39 GMT
  Expires: Fri, 01 Jan 1990 00:00:00 GMT
  Pragma: no-cache
  Server: GSE
  X-Content-Type-Options: nosniff
  X-Frame-Options: SAMEORIGIN
  X-XSS-Protection: 1; mode=block

Response body: (479 bytes)
{
… 
}
-----------------------------------------------------------


Second, after the network returns:

plus.people.get

2012-10-25 20:02:58 +0000
Request: POST https://www.googleapis.com/rpc?prettyPrint=false
Request headers:
  Accept: application/json-rpc
  Authorization: Bearer _snip_
  Cache-Control: no-cache
  Content-Type: application/json-rpc; charset=utf-8
  User-Agent: [com.MY.APP.ID]/2.0.1 google-api-objc-client/2.0 iPhone_Simulator/6.0 (gzip)

Request body: (100 bytes)
{
  "method" : "plus.people.get",
  "id" : "gtl_7",
  "jsonrpc" : "2.0",
  "params" : {
    "userId" : "me"
  },
  "apiVersion" : "v1"
}

Error: Error Domain=NSURLErrorDomain Code=-1003 "A server with the specified hostname could not be found." UserInfo=0x1575eb30 {NSErrorFailingURLStringKey=https://www.googleapis.com/rpc?prettyPrint=false, NSErrorFailingURLKey=https://www.googleapis.com/rpc?prettyPrint=false, NSLocalizedDescription=A server with the specified hostname could not be found., NSUnderlyingError=0x157797f0 "A server with the specified hostname could not be found."}
-----------------------------------------------------------
 
 

The code making the requests looks like this.  Here _service and _plusService are objects of type GDataServiceGooglePhotos and GTLServicePlus, respectively.  To reiterate, this same code is called before and after network interruption.  First time, no error; second time, both requests return "A server with the specified hostname could not be found." error.  Subsequent requests return no error.

- (void)fetchUserData
{
    // get number of albums
    NSURL *feedURL = [GDataServiceGooglePhotos photoFeedURLForUserID:kGDataServiceDefaultUser
                                                             albumID:nil
                                                           albumName:nil
                                                             photoID:nil
                                                                kind:nil
                                                              access:nil];
    
    GDataServiceTicket *ticket;
    ticket = [_service fetchFeedWithURL:feedURL completionHandler:^(GDataServiceTicket *ticket, GDataFeedBase *feed, NSError *error) {
        if ( error )
        {
            NSLog( @"Getting user's feed for getting user data, fetch error: %s\n", [[error localizedDescription] UTF8String] );
        }
        else
        {
            // feed should be all photo albums
            _numberOfAlbums = [[feed entries] count];
        }
    }];

    
    // get a user display name and profile picture
    
    GTLQueryPlus *profileQuery = [GTLQueryPlus queryForPeopleGetWithUserId:@"me"];
    profileQuery.completionBlock = ^(GTLServiceTicket *ticket, id object, NSError *error) {
        if (error == nil) {
...
        } else {
            // Error getting user data
            NSLog( @"Error getting user data: %@", [error localizedDescription] );
        }
    };

    GTLServiceTicket* plusTicket = [_plusService executeQuery:profileQuery
                           completionHandler:^(GTLServiceTicket *ticket, id result, NSError *error) {
                               if ( error != nil )  {
                                   NSLog( @"_plusService Error: %@", [error localizedDescription] );
                               }
                           }];    
}



Thanks for looking.

Tyson
 

Tyson

unread,
Oct 25, 2012, 5:37:40 PM10/25/12
to google-api-obj...@googlegroups.com
This also occurs on the device (iPhone 4S running iOS 6.0).


Greg Robbins

unread,
Oct 26, 2012, 1:59:43 PM10/26/12
to google-api-obj...@googlegroups.com
I presume this is an error propagated to the library from the NSURLConnection callback, so it would be an iOS networking issue rather than a library issue. 

I have not seen similar reports, and offhand I cannot think of a reasonable workaround for this problem.

Tyson

unread,
Nov 1, 2012, 7:28:14 PM11/1/12
to google-api-obj...@googlegroups.com

Thanks Greg, I will follow up with Apple on the networking issue.  As a workaround, I am trying to use the retry mechanism.  That is, calling:


setIsServiceRetryEnabled:YES

setServiceRetrySelector:@selector(...)


on my GDataServiceGooglePhotos object.  This allows me to catch the -1003 error and retry the request, which seems reasonable since the retrying manually seems to work. The retry selector does appear to catch it, but I am now hitting another problem, and I think this time it's actually related to the library ;-).


By calling setShouldCacheResponseData:YES we can tell the GTMHTTPFetcher to catch 304 responses, and use locally cached responses so that I will just see them as 200 responses. I could be wrong, but it appears that the retry mechanism breaks this functionality. In GTMHTTPFetchHistory updateRequest:isHTTPGet:we check if the request has an ETag corresponding to kGTMIfNoneMatchHeader, and if not, we add one like so:


        // We'll only add an ETag if there's no ETag specified in the user's

        // request

        NSString *specifiedETag = [request valueForHTTPHeaderField:kGTMIfNoneMatchHeader];

        if (specifiedETag == nil) {

          // No ETag: extract the previous ETag for this request from the

          // fetch history, and add it to the request

          NSString *cachedETag = [self cachedETagForRequest:request];


          if (cachedETag != nil) {

            [request addValue:cachedETag forHTTPHeaderField:kGTMIfNoneMatchHeader];

          }

        } else {

          // Has an ETag: remove any stored response in the fetch history

          // for this request, as the If-None-Match header could lead to

          // a 304 Not Modified, and we want that error delivered to the

          // user since they explicitly specified the ETag

          [self removeCachedDataForRequest:request];

        }


But if there is an ETag, we remove the cached data for the request.  Since we're re-using the same request when we retry, we remove the cached data.  So I'm not 100% sure, but I think the flow goes something like this:


- I issue a request to GDataServiceGooglePhotos

- request has no ETag, so try getting one from cached responses (as above) and send it along

- the request fails with -1003, but I catch this with my retrySelector, and tell it to retry

- now the request does have an ETag, so the cached data is removed (again as above), and the request is sent out

- the second response now comes back with 304

- we check the cache, there is no cached data for this request (we just cleared it)

- this causes the 304 error to propagate all the way back to me, which I don't want


If I comment out this: [self removeCachedDataForRequest:request];, everything works fine for my particular case, but obviously this is not a valid fix for the general case.



T.

Greg Robbins

unread,
Nov 1, 2012, 8:20:54 PM11/1/12
to google-api-obj...@googlegroups.com
Perhaps as a workaround you can use the retry selector to clear the ETag from the If-none-match header of the request.

The old Objective-C GData library isn't being further developed, so it's unlikely this case will be fixed in that library.

Tyson

unread,
Nov 1, 2012, 8:41:02 PM11/1/12
to google-api-obj...@googlegroups.com
Thanks Greg, I will try that.

Is there a new Objective C API for getting at Picasa photos that I should be using instead of GData?


T.

Greg Robbins

unread,
Nov 1, 2012, 8:47:18 PM11/1/12
to google-api-obj...@googlegroups.com
Photos functionality is being migrated to Google+, but I'm not sure what support there is currently for photos in the Google+ API.


Reply all
Reply to author
Forward
0 new messages