Question

I'm setting a asynchronous post request with a document, containing hundreds of location points. I want to save this document in my couchdb.

For small documents, the request response returns in very short time, storing the document. When the document grows a bit more (still < ~200k) the response takes ages and then it returns with a timeout. I set the timeout for 120 seconds.

Am I missing some setting or doing an coding error?

- (void)post:(NSData*) requestBody {
    startTime = [NSDate date];
    NSURL* serverURL = [NSURL URLWithString: @"https://myUser:myPassword@myAcc.cloudant.com/myDB"];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:serverURL];
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
    [request setHTTPMethod:@"POST"];
    [request setTimeoutInterval:120.0];

    [request setHTTPBody:requestBody];


    [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
    {
        if (response != nil) {
            if ([response respondsToSelector:@selector(statusCode)])
            {
                int statusCode = [((NSHTTPURLResponse *)response) statusCode];
                NSLog(@"StatusCode returned was %i", statusCode);
            }
            NSLog(@"Response: %@",response);
        }

         if ([data length] >0 && error == nil)
         {
             NSLog(@"data: %@", data);
             // DO YOUR WORK HERE

         }
         else if ([data length] == 0 && error == nil)
         {
             NSLog(@"Nothing was downloaded.");
         }
         else if (error != nil){
             NSLog(@"Error = %@", error);
         }

     }];

EDIT: the problem with the timeout still remains. I logged in the progress in the didSendBodyData: and recognized, that bytes were sent. Not all, then the timeout occurs. With curl, the upload works just fine.

Additionally I recognized one thing in the log: When the request was successful, total and expected bytes were the same:

Total Bytes written: 161120
Expected Bytes to write: 161120

When the request failed:
Total Bytes written: 163840
Expected Bytes to write: 166839

Any other ideas?

- (void)post:(NSData*) requestBody {
    NSURL* serverURL = [NSURL URLWithString: @"https://mySpace.cloudant.com/myDb"];

    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:serverURL
                                             cachePolicy:NSURLRequestUseProtocolCachePolicy
                                         timeoutInterval:30.0];
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
    [request setHTTPMethod:@"POST"];
    [request setHTTPBody:requestBody];

    NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
    [connection start];
}

#pragma mark -
#pragma mark Connection Delegates
- (void) connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
    if ([challenge previousFailureCount] == 0) {
        NSLog(@"received authentication challenge");
        NSURLCredential *newCredential = [NSURLCredential credentialWithUser:@"myUser"
                                                                    password:@"myPwd"
                                                                 persistence:NSURLCredentialPersistenceForSession];
        NSLog(@"credential created");
        [[challenge sender] useCredential:newCredential forAuthenticationChallenge:challenge];
        NSLog(@"responded to authentication challenge");
    }
    else {
        NSLog(@"previous authentication failure");
    }
}
Was it helpful?

Solution

This appears to be a problem with the URL format. When using a low-level HTTP library, you have to manually add the basic authentication header - NSURLConnection and Basic HTTP Authentication in iOS shows how to do this. The timeout is then likely due to the device attempting to contact an invalid host.

You can test this by attempting to make the request directly with curl, i.e.:

curl -XPOST https://username.password@username.cloudant.com/db -H 'Content-Type:application/json' -d @test.json

where test.json contains the JSON which is timing out.

Using curl makes it easier to debug (you'll get to see the raw response) and also confirms whether or not it is a server-side problem or something library specific.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top