AFNetworking 2.0 - unexpected NSURLErrorDomain error -1012 - afnetworking

We ran into the following issue with our app that uses AFNetworking 2.0.
When using AFHTTPRequestOperationManager's GET method, we got an error NSURLErrorDomain code -1012. The request used HTTPS and the server does not require user authentication. The request never reached the server by the way.
We have run several tests and this is the first time the error was produced and we are wondering how this error can get produced because it does not seem relevant.
Setup of AFHTTPRequestOperationManager :
httpOperationManager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:
[NSURL URLWithString: HTTPS_URL)]];
httpOperationManager.responseSerializer =
[AFXMLParserResponseSerializer serializer];
[[AFNetworkActivityIndicatorManager sharedManager] setEnabled: YES];
GET REQUEST
AFHTTPRequestOperation *op =[httpOperationManager GET:
[NSString stringWithFormat:SOME_PATH]
parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject) {
//code to setup NSXMLParser ...
}
failure: ^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"error %#", [error localizedDescription]);
}];

I think you already solved the problem, but if you are trying to authenticate in a server that doesn't have a valid certificate you have to set YES for property allowInvalidCertificates in your AFHTTPRequestOperationManager object:
[yourManager.requestSerializer setAuthorizationHeaderFieldWithUsername:#"your_username" password:#"your_password"];
[yourManager.securityPolicy setAllowInvalidCertificates:YES];
Also, as #a1phanumeric said, it can be necessary to include this line:
[yourManager.securityPolicy setValidatesDomainName:NO];
Cheers.

NSURLErrorDomain -1012 is NSURLErrorUserCancelledAuthentication. (See the error code list and search for -1012.)
You state, "the server does not require user authentication". But this error would not be called if that were true.
Possible causes:
Your server is erroneously requesting authorization (a server bug)
The URL formed with HTTPS_URL and SOME_PATH is not what you expect, and some other server is requesting authorization
Some intermediary (like a proxy server, or an access point) is requiring authorization.
Some debugging tips:
Set breakpoints inside the AFNetworking implementation to see which URL is being hit
Configure AFHTTPRequestOperationLogger so you can see the actual request body and response in your console log
Make the same request with curl or Advanced Rest Client and observe the server's response
Side note: I think [NSString stringWithFormat:SOME_PATH] is pointless - why not just use SOME_PATH?

Related

How to handle the response for Feedly Authentication?

Feedly API Documentation
I'm trying to take advantage of Feedly APIs in my testing iOS app, but unfortunately it seems too great a confusion to me, a newbie to coding in general.
I encountered a problem at the very beginning.
The first step required is the Authentication, as shown in the link above. So I write the code below:
NSDictionary *queryParams = #{#"response_type" : #"code",
#"client_id" : clientID, //some NSString
#"redirect_uri" : redirectURL, //#"https%3A%2F%2Flocalhost/"
#"scope" : #"https://cloud.feedly.com/subscriptions"
};
AFHTTPClient *httpClient = [AFHTTPClient clientWithBaseURL:[NSURL URLWithString:#"https://developer.feedly.com/"]];
[httpClient getPath:#"/v3/auth"
parameters:queryParams
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"response: %#", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"HTTP Requset Operation Error! %#", error);
}];
It appeared that I succeeded in getting the response when I ran the code, since the response was logged. However, the output was like this:
<3c21444f 43545950 45206874 6d6c3e0a 3c68746d 6c206c61 6e673d22 656e223e 0a3c6865 61643e0a 20203c6d 65746120 68747470 2d657175 69763d22 436f6e74 656e742d 54797065 2220636f 6e74656e 743d2274 6578742f 68746d6c 3b206368 61727365 743d5554 462d3822 202f3e0a 20203c6d 65746120 68747470 2d657175 69763d22 436f6e74 656e742d 4c616e67 75616765 2220636f 6e74656e 743d2265 6e2d7573 22202f3e 0a20203c 6d657461 20687474 702d657 ......(the list goes on and on)>
I'm really clueless about what type this is and how I can use it. Is it the response mentioned in the documentation?
Here is the part related to handling the response:
Handling the response
The response will be sent to the redirect_uri specified in the request. If the user approves the access request, then the response contains an code and the state parameter (if included in the request). If the user does not approve the request the response contains an error message. All responses are returned to the web server on the query string, as shown below:
An error response:
https://your.redirect.uri/feedlyCallback?error=access_denied&state=state.passed.in
A code response
https://your.redirect.uri/feedlyCallback?code=AQAA7rJ7InAiOjEsImEiOiJmZWVk…&state=state.passed.in
What does it mean "All responses are returned to the web server on the query string" and how can I access the returned parameters?(This seems to be the part where I'm stumped)
Thanks for anyone who can lead me out of this mess and give me faith to continue coding.
Plus I'm really fuzzy about how to cope with these web service APIs and the whole url-query/response thing. I'd be vastly grateful if someone can name a book or some article from which I can learn something regarding the way this mechanism works.
The response will be sent to the redirect_uri specified in the request.
Check the response url:
https://your.redirect.uri/feedlyCallback?error=access_denied&state=state.passed.in
Notice the feedlyCallback? part and query strings error and state
I don't know what language you are using, but for PHP: you should create feedlyCallback.php and set php server to feed files without .php extension,
in php files, you can acces query strings with $_GET['error'] and $_GET['state']
Just google for things you have problems with. No idea what query stings mean? http://en.wikipedia.org/wiki/Query_string

AFNetworking API call status code

Is there a possibility that AFNetworking takes API status code in consideration as well?
Call returns 200 HTTP code that it is ok, but status code is 406 which indicates failure.
This results to AFNetworking success block being called, even though API call failed.
Is there a solution to this?
Code:
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSString *APICallURL = [NSString stringWithFormat:#"%#/%#", SERVER_URL, #"something.php"];
[manager GET:APICallURL parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
if (success) {
success();
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
if (failure) {
failure(error);
}
}];
X-API-Status-Code is a totally non-standard header (as any header starting with X-... actually, by definition).
That header is a proprietary way that your specific server chose to report the API status code. It could have picked any other proprietary header to do so, maybe calling it X-API-ReturnCodeor whatnot.
So I doubt that AFNetworking will ever support this natively.
But you can probably create your own AFURLResponseSerialization subclass and implement validateResponse, so that your code check for this proprietary header and act accordingly.
It will not reach failure block for any failure status code from server. With respect to AFNetworking, network call is successful with a error code from server.
It will reach failure block only when we are not able to successfully finish the network call, like
1) Time out error
2) Server down and not able to reach
3) Network loss etc
Solution is we should check the status code of network call in success block and identify error responses from server

Login form with AFNetworking 1.3

I am trying to login into a website through an HTML form using AFNetworking 1.3. I simply set my credentials and POST to the proper path. The problem is that I am not issued a cookie that states that I am logged in.
NSURL *baseURL = [NSURL URLWithString:#"https://mysite.edu"];
AFHTTPClient *client = [AFHTTPClient clientWithBaseURL:baseURL];
NSString *loginPath = #"/place/loginPage";
NSDictionary *loginParameters = #{#"sid" : #"username",
#"PIN" : #"12345678"};
NSMutableURLRequest *request = [client multipartFormRequestWithMethod:#"POST"
path:loginPath
parameters:loginParameters
constructingBodyWithBlock:nil];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"success: %#", operation.responseString);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"error: %#", operation.responseString);
}];
[operation start];
The web server is returning a webpage that states that I do not have cookies enabled:
This system requires the use of HTTP cookies to verify authorization information.
Our system has detected that your browser has disabled HTTP cookies, or does not support them.
Please refer to the Help page in your browser for more information on how to correctly configure your browser for use with this system.
However, if I iterate through my issued cookies, I find that the website has issued me cookies, but not a session cookie. Therefore my AFNetworking client really is accepting cookies? Is there a setting that I must adjust to allow session cookies to properly work with AFNetworking 1.3?
I have edited my HTTP request header to match working browsers such as Chrome.
[Is] my AFNetworking client really [] accepting cookies? Is there a setting that I must adjust to allow session cookies to properly work with AFNetworking 1.3?
AFNetworking has no cookie-specific configuration. Cookies are solely the responsibility of the Foundation URL Loading system.
Some possible solutions:
Install AFHTTPRequestOperationLogger and configure it with AFLoggerLevelDebug to see all HTTP headers. This will let you see what's actually getting sent and received in your Xcode console.
The server may be dropping the cookie, for example if it's a Ruby server with protect_from_forgery enabled. Check your server logs and this solution for information on disabling or sending the appropriate token.
You control how requests use cookies with -[NSMutableURLRequest setHTTPShouldHandleCookies]. Make sure this is set to YES (the default.)
Other apps can alter the Cookie Accept Policy, so make sure -[NSHTTPCookieStorage cookieAcceptPolicy] is returning NSHTTPCookieAcceptPolicyAlways (or NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain if you need it.)
Since I came here while searching for a working solution for AFNetworking 2.0, not knowing that AFHTTPClient was removed from the Framework, I will post the new way to establish this connection here:
AFHTTPRequestOperationManager *manager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:[NSURL URLWithString:#"http://examplewebsite.com"]];
[manager setRequestSerializer:[AFHTTPRequestSerializer serializer]];
[manager.requestSerializer setAuthorizationHeaderFieldWithUsername:#"userName" password:#"password"];

User Login With AFNetworking

I am building my first iOS app.
I have got the backend code done, but I am struggling with the Objective-C part of it.
I have a signup / login page.
But I don't know how to send that data to my server using Objective C.
I have read that AFNetworking is good, but I was wondering how I could use that for user login .
I have downloaded and added AFNetworking to my XCode Project and set up headers.
AFHTTPClient *client = [AFHTTPClient clientWithBaseURL:[NSURL URLWithString:#"http://examplewebsite.com]];
[client setDefaultHeader:#"key" value:#"value"];
[client setAuthorizationHeaderWithUsername:#"username" password:#"password"];
[client setAuthorizationHeaderWithToken:#"token"];
NSURLRequest *request = [client requestWithMethod:#"someMethod" path:#"somePath" parameters:nil];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
but I am still lost.
Since you're trying to login to your own API, you don't want setAuthorization stuff. That's for basic HTTP auth. Instead you want to use getPath:parameters:success:failure or the postPath version, depending on if your backend is expecting HTTP GET or HTTP POST.
Pass your userid / password in the parameters argument. You should set parameterEncoding to be the correct format. You're probably using HTTP Forms url encoding, or JSON. Whatever your backend expects.
You don't want to set the authorization headers in this case, since this is for "basic access HTTP authentication", which is a method for a HTTP user agent to provide a user name and password when making a request to a server.
You want to use your own API and interact with a restful server and therefore, I would recommend, that you subclass AFHTTPClient -> interact with an API, Web Service, or Application. - Take a look at the examples in the AFNetworking zip archive, if you have difficulties in subclassing AFHTTPClient.
Since you want to create an app with user login, the app needs to send these information to your server, and the server should return if the login was succesful or not.
This can be done like so - HTTP POST.
- (void)login {
// Login information from UITextFields
id params = #{
#"username": self.usernameField.text,
#"password": self.passwordField.text
};
//Call the AFHTTP subclass client, with post block. postPath = the path of the url, where the parameters should be posted.
[[theAuthAPIClient sharedClient] postPath:#"/login"
parameters:params
success:^(AFHTTPRequestOperation *operation, id responseObject) {
//handle succesful response from server.
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
// handle error - login failed
}
}];
}
You need to pass the parameters in the right format, depending on what format your server expects. This can be done by setting the right encoding in your AFHTTPClient subclass -> ParameterEncoding
Since I came here while searching for a working solution for AFNetworking 2.0, not knowing that AFHTTPClient was removed from the Framework, I will post the new way to establish this connection here:
AFHTTPRequestOperationManager *manager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:[NSURL URLWithString:#"http://examplewebsite.com"]];
[manager setRequestSerializer:[AFHTTPRequestSerializer serializer]];
[manager.requestSerializer setAuthorizationHeaderFieldWithUsername:#"userName" password:#"password"];

RestKit: How to resubmit failed request after re-authenticating?

The API I'm developing against requires me to present an authentication token in a custom HTTP header. This token expires every few minutes, and could happen while the user is still within the app as long as they have been idle long enough. When the token has expired I receive a 403 response but I only find out after attempting a request.
What's the best way to get RestKit to automatically reauthenticate and retry the request so I don't have to put in this logic everywhere I make a request? Responses to similar questions have suggested using the RKRequestDelegate protocol or the RKObjectLoaderDelegate protocol but unfortunately these are no longer part of RestKit (as of 0.20).
Any idea what the "correct" approach should be now? Should I be subclassing RKObjectManager and tacking on a retry to each of the request operations or should I provide a custom HTTPOperation or HTTPClient class or is there some better approach altogether? Thanks!
Catch it in Failure block , and check for the status code and re-do the authentication
RKObjectRequestOperation *requestOp = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:#[getObjResp]];
[requestOp setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
....
}
} failure:^(RKObjectRequestOperation *operation, NSError *error){
// Here your status code check
// Here your retry-code
}

Resources