I have a REST API which is secured by digest. I want to download my JSON response, but first I've to authenticate against the rest api.
I'm doing my Requests with sendAsynchronousRequest:queue:completionHandler:. But I don't know how to handle the digest authentication. I thought with the delegate method didReceiveAuthenticationChallenge of NSURLConnectionDelegate this should be possible? I've declared in the .h file the NSURLConnectionDelegate and added in the implementation the method. But nothing happens. Any advice how to handle this with "sendAsynchronousRequest:queue:completionHandler:" ?
NSURL *url = [NSURL URLWithString:#"http://restapi/"];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:urlRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
if ([data length] > 0 && error == nil)
[self receivedData:data];
else
NSLog(#"error");
}];
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
NSLog(#"did get auth challenge"); }
The connection:didReceiveAuthenticationChallenge: will only be called if you specify your instance as the delegate of the connection. To do so you'll need to use a different method to start the request, e.g.:
NSURL *url = [NSURL URLWithString:#"http://restapi/"];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
NSURLConnection *connection = [NSURLConnection connectionWithRequest:urlRequest delegate:self]
You will need to implement further delegate methods in order to receive the response.
Note that connection:didReceiveAuthenticationChallenge: is deprecated in favor of other delegate methods (see this page).
Have a look at this question chain set might be this can help:
Authentication with NSURLConnection sendAsynchronousRequest with completion handler
Related
In my application, I am performing POST using NSURLSession.
Steps followed:
Setting Header
Setting HTTPBody
Making POST request using NSURLSession.
The code is:
NSDictionary *parameters = #{ #"searchTerm": #"shampoo", #"sort": #"Most Reviewed" };
NSError *error = nil;
NSData *postData = [NSJSONSerialization dataWithJSONObject:parameters options:NSJSONWritingPrettyPrinted error:&error];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"SomeURL"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:10.0];
[request setHTTPMethod:#"POST"];
[request setAllHTTPHeaderFields:headers];
request.HTTPBody = postData;
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(#"%#", error);
} else {
NSLog(#"Pass");
}
}];
[dataTask resume];
Now in custom NSURLProtocol class:
(BOOL)canInitWithRequest:(NSURLRequest *)request {
if ([request.HTTPMethod isEqualToString:#"POST"]) {
//here request.HTTPMethod is coming nil
//Whereas my requirement is to get request.HTTPMethod which got request parameter.
return YES;
}
return NO;
}
Thanks in advance.
IIRC, body data objects get transparently converted into streaming-style bodies by the URL loading system before they reach you. If you need to read the data:
Open the HTTPBodyStream object
Read the body data from it
There is one caveat: the stream may not be rewindable, so don't pass that request object on to any other code that would need to access the body afterwards. Unfortunately, there is no mechanism for requesting a new body stream, either (see the README file from the CustomHTTPProtocol sample code project on Apple's website for other limitations).
I have written a REST service that serves up some data. It is passcode protected.
I am trying to write a background process that will grab the data and stuff it into a sqlLite db I have in the app.
I did this initially without authentication using :
- (void) callWebService {
dispatch_sync(kBgQueue, ^{
NSData* data = [NSData dataWithContentsOfURL:
scoularDirectoryURL];
[self performSelectorOnMainThread:#selector(fetchedData:) withObject:data waitUntilDone:YES];
});
}
This worked fine but I don't think I can add authentication to that. If I can I would just use that.
What I am looking for is a nice, simple explanation of NSURLSession using user/password authentication.
I think your question is vague and underspecified. That said, here's one solution, from here:
-(void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)( NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
{
if (_sessionFailureCount == 0) {
NSURLCredential *cred = [NSURLCredential credentialWithUser:self.userName password:self.password persistence:NSURLCredentialPersistenceNone];
completionHandler(NSURLSessionAuthChallengeUseCredential, cred);
} else {
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
}
_sessionFailureCount++;
}
I strongly recommend that you read and re-read the Apple docs on this.
For me the following code works:
NSString *userName=#"user:";
NSString *userPassword=#"password";
NSString *authStr= [userName stringByAppendingString:userPassword];
NSString *url=#"http://000.00.0.0:0000/service.json";
NSData *authData = [authStr dataUsingEncoding:NSUTF8StringEncoding];
NSString *authValue = [NSString stringWithFormat: #"Basic %#",[authData base64EncodedStringWithOptions:0]];
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
[request setValue:authValue forHTTPHeaderField:#"Authorization"];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response,
NSData *data, NSError *connectionError)
NSDictionary *theDictionary = [NSJSONSerialization JSONObjectWithData:data
options:0
error:NULL];
NSDictionary *host = [theDictionary objectForKey : #"host"];
// json nested
self.label.text = [host objectForKey:#"key1"];
self.label.text = [host objectForKey:#"key2"];
regards
I have two request starting one after the other. Starting request like this
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"http://www.google.com"]];
NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:60];
NSURLConnection * connection = [[NSURLConnection alloc]
initWithRequest:request
delegate:self startImmediately:NO];
[connection scheduleInRunLoop:[NSRunLoop mainRunLoop]
forMode:NSDefaultRunLoopMode];
[connection start];
and another request starting like this.
NSURL *url1 = [NSURL URLWithString:[NSString stringWithFormat:#"http://www.apple.com"]];
NSURLRequest *request1 = [NSURLRequest requestWithURL:url1 cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:60];
NSURLConnection *connection1 = [[NSURLConnection alloc] initWithRequest:request1 delegate:self];
[connection1 release];
How can i differentiate between these two in delegate method?
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{}
Don't want to keep any extra class variable for this purpose.
It's Simple :
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
if (connection == connection1)
{
//It's for connection1.
}
else if (connection == connection2)
{
//It's for connection2.
}
}
You can go through this Beautiful SO Question : Managing multiple asynchronous NSURLConnection connections
take your NSURLConnection objects in .h file and check in your delegate method as Markus has suggested.
or
Subclass your NSURLConnection and then you can add tag property to the connection class while creating, in you delegate methods check for appropriate tag. You can find working tutorial here.
I have a Mac application that is supposed to fetch Twitter followers and friends for a given username and then, in turn, ask Twitter for the user NAMES for each of those returned UserIDs. As you can see below, I have a method that will call the Twitter API to get friends/followers (which works fine). It is the userNameForUserID:delegate: method that is causing me problems. I used to do these requests synchronously and return the NSString for the username right then. That (now commented out) line always broke, so I tried doing it with an NSURLConnection asynchronously. Still doesn't work. I don't understand why
[[NSString alloc] initWithContentsOfURL:...] works for the fetchFollowers... method, but not when I do it the EXACT SAME way in the other...
I put a break point on the line that used to alloc init the NSString with contents of URL, and when I step into it, it doesn't break, return, throw an exception, crash...nothing. It's as if that line just got stepped over (but my application is still blocked.
Any ideas? Much appreciated!
NSString * const GET_FOLLOWERS = #"https://api.twitter.com/1/followers/ids.json?cursor=-1&screen_name=";
NSString * const GET_FRIENDS = #"https://api.twitter.com/1/friends/ids.json?cursor=-1&screen_name=";
NSString * const GET_USER_INFO = #"https://api.twitter.com/1/users/show.json?user_id=";
#implementation TwitterAPI
+ (void)userNameForUserID:(NSNumber *)userID delegate:(id<UserNameDelegate>)delegate
{
NSURL *url = [NSURL URLWithString:[GET_USER_INFO stringByAppendingString:[userID stringValue]]];
// NSString *JSON = [[NSString alloc] initWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&error];
NSURLRequest *req = [NSURLRequest requestWithURL:url];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:req queue:queue completionHandler:^(NSURLResponse *urlResponse, NSData *data, NSError *error) {
[delegate addUserNameToArray:data];
}];
}
+ (NSArray *)fetchFollowersWithUserName:(NSString *)userName
{
NSURL *url = [NSURL URLWithString:[GET_FOLLOWERS stringByAppendingString:userName]];
NSArray *followerIDs;
NSString *JSON = [[NSString alloc] initWithContentsOfURL:url encoding:NSASCIIStringEncoding error:nil];
if ([JSON rangeOfString:#"error"].location == NSNotFound)
followerIDs = [[JSON JSONValue] valueForKey:#"ids"];
return followerIDs;
}
I am getting the leak at this line in below code" NSData *returnData = [NSURLConnection ..........."
NSURL *finalURL = [NSURL URLWithString:curl];
NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:finalURL
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:10];
[theRequest setHTTPMethod:#"GET"];
NSData *returnData = [NSURLConnection sendSynchronousRequest:theRequest returningResponse:nil error:nil];
BOOL enabled = [self getAutoGenerateObject:returnData];
return enabled;
please help me out of this problem.
Thank You,
Madan Mohan
You will need to release the returnData. That's why in Apple's examples in 'URL Loading Programming Guide / Using NSURLConnection', the returnData is assigned to an iVar and release in dealloc or connectionDidFinishLoading in the case of Asynchronous communication.
Depending what operation you are performing in you method getAutoGeneratedObject, but in theory it can take ownership there.
You could also mark returnData as autoreleased, but that is not always recommended especially if the response data is large.
NSURL *finalURL = [NSURL URLWithString:curl];
NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:finalURL
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:10];
[theRequest setHTTPMethod:#"GET"];
NSData *returnData = [NSURLConnection sendSynchronousRequest:theRequest returningResponse:nil error:nil];
BOOL enabled = [self getAutoGenerateObject:returnData];
[returnData release];
return enabled;