NSURLConnection, NSURLAuthenticationChallenge failure response - ios

When trying to log in to my app with iOS7 I'm getting a failure response with some description. This is NSLog of NSURLAuthenticationChallenge failureResponse:
<NSHTTPURLResponse: 0xa383570> { URL: <URL> } { status code: 401,headers {
"Content-Length" = 1385;"Content-Type" = "text/html;charset=utf-8";
Date = "Fri, 13 Jun 2014 12:14:24 GMT";
Server = "Apache-Coyote/1.1";
"Www-Authenticate" = "Basic realm=\"booo\"";
"x-errorCode" = 02;
"x-errorDescription" = "com.idealination.core.server.client.http.ServerException:
Request failed: <URL> Status: CLIENT_ERROR_UNAUTHORIZED
Error: #Unauthorized :: Invalid userid or password.";
} }
and I need that last line to know what error do I get. But when I use iOS6 and iPhone 3gs I get only:
<NSHTTPURLResponse: 0x1c507ae0>
What should I do to get a response like using iOS7? And why I'm getting a different response?

You should not be looking for the last line, you should be looking for the HTTP Status Code, in this case 401.
if(urlResponse.statusCode == 401) { }
If you need to convert that into what the status code means as a string use
NSString *status = [NSHTTPURLResponse localizedStringForStatusCode:urlResponse.statusCode];

Related

NSURLSessionUploadTask response content data is null

Here's where I am so far with NSURLSessionUploadTask:
iOS application starts an NSURLSessionUploadTask using POST
server receives HTTP POST request
server reads content of the request so data is uploaded
server sends HTTP response to iOS consisting of the following:
HTTP/1.1 200 OK
Server: BaseHTTP/0.3 Python/2.7.10
Date: Fri, 30 Oct 2015 16:15:21 GMT
Content-Type: text/html
Content-Length: 96
<html><head><title>POST RESPONSE</title></head><body><p>The file was uploaded.</p></body></html>
iOS application receives response and NSLogs the response via NSURLSessionTaskDelegate -> URLSession:task:didCompleteWithError:
<NSHTTPURLResponse: 0x15d95110> { URL: http://10.157.239.129:42000/ } { status code: 200, headers {
"Content-Length" = 96;
"Content-Type" = "text/html";
Date = "Fri, 30 Oct 2015 16:15:21 GMT";
Server = "BaseHTTP/0.3 Python/2.7.10";
} }
however, when I try to NSLog the response content when the method NSURLSessionTaskDelegate: -> URLSession:dataTask:didReceiveData:
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data
{
// Called when data task has received some data (not applicable for straight upload?)
if (data != NULL)
{
NSLog(#"%s: %#", __PRETTY_FUNCTION__,[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
}
else
{
NSLog(#"%s: but no actual data received.", __PRETTY_FUNCTION__);
}
// If we are not in the "active" or foreground then log some background information to the console
if (UIApplication.sharedApplication.applicationState != UIApplicationStateActive)
{
[BackgroundTimeRemainingUtility NSLog];
}
}
is called I get this for output:
2015-10-30 12:15:22.648 NSURLSessionUploadTaskExample[215:7286] -[ViewController URLSession:dataTask:didReceiveData:]: (null)
what is odd about this is that the response should not have triggered the if statement block if the data is null!
I also have evidence that the response data WAS sent to the iOS application via Wireshark. Here's a packet capture of the HTTP response from the server:
Can anyone tell me why iOS appears to be losing the content in the HTTP response?
Because I was able to trace the HTTP 200 response from the server to the iOS application, I suspected the iOS application had a problem. I set a breakpoint at the line:
NSLog(#"%s: %#", __PRETTY_FUNCTION__,[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
and examined the data object with the debugger:
Each of the 96 bytes in the response content was getting to NSURLSessionTaskDelegate: -> URLSession:dataTask:didReceiveData: So the NSString decoding in the NSLog was at fault. Now things were making sense. I was sending a 96 byte ASCII response, not a 96 byte UTF8 response!
I replaced the NSString decoder with the following:
NSLog(#"%s: %#", __PRETTY_FUNCTION__,[[NSString alloc] initWithBytes:[data bytes] length:[data length] encoding: NSASCIIStringEncoding]);
Problem solved with the following output:
2015-11-02 10:04:47.086 NSURLSessionUploadTaskExample[561:363449] -[ViewController URLSession:dataTask:didReceiveData:]:<html><head><title>POST RESPONSE</title></head><body><p>The file was uploaded.</p></body></html>
I've also put a very basic NSURLSessionUploadTask example application and webserver on github here.

How to set Content-Type in AFNetworking?

I want to set "application/x-www-form-urlencoded" with post method
So ,I set request.requestSerializer.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") But When I set the request to the server the Content-Type is not change what happen?
this is error
{com.alamofire.serialization.response.error.response=<NSHTTPURLResponse: 0x7c166450> { URL: http://test.com } { status code: 404, headers {
Connection = "keep-alive";
"Content-Length" = 434;
"Content-Type" = "text/html";
Date = "Mon, 13 Jul 2015 11:18:18 GMT";
Server = "nginx/1.0.15";
} }, NSErrorFailingURLKey=http://text.com, NSLocalizedDescription=Request failed: not found (404),
this is my code:
var request = AFHTTPRequestOperationManager();
request.requestSerializer = AFHTTPRequestSerializer()
request.requestSerializer.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.POST(url, parameters: parameters, success: { (oper,obj) -> Void in
// do something
}) { (oper, error) -> Void in
// do something with error
}
It's exactly what the error says: your server is sending back a webpage (HTML) for a 400 status code, when you were expecting JSON.
A 400 status code is used a bad request, which is probably generated because you're sending URL-form-encoded text as application/json. What you really want is to use AFJSONRequestSerializer for your request serializer.
manager.requestSerializer = [AFJSONRequestSerializer serializer];
I am not doing any code of AFNetworking in Swift so I can't tell you code of that but you can get idea from objective-c code.
I hope it will help you.

AFNetworking 2 empty POST response but no errors

It's a very tricky problem:
I do a POST request (login) to a server.
The server will answer:
ok Status Code: 200 + JSON Data
error Status Code: 401 + plain/text
Code:
func login (id: String, password: String){
self.responseSerializer = AFJSONResponseSerializer()
self.responseSerializer.acceptableContentTypes = nil
self.responseSerializer.acceptableStatusCodes = NSIndexSet(index: 400)
//self.responseSerializer.acceptableStatusCodes = nil
var param = ["id": lbid, "password": password]
POST(APIURL.URL_LOGIN, parameters: param,
{ (operation : NSURLSessionDataTask!, response : AnyObject!) -> Void in
//var finalResponse : Dictionary = Dictionary<String, String>()
var tmp = response as String
self.defaults.setObject(tmp, forKey: "USERSSID")
self.defaults.setBool(true, forKey: "USERLOGGEDIN")
println("Success login")
}) { (operation : NSURLSessionDataTask!, error : NSError!) -> Void in
println(error)
}
}
It executes the failure blog and I get this error:
Code=-1011 "Request failed: no error (200)" UserInfo=0x7f9fa1534760 {com.alamofire.serialization.response.error.response=<NSHTTPURLResponse: 0x7f9fa15791e0> { URL: https://************ } { status code: 200, headers {
Connection = "Keep-Alive";
"Content-Length" = 107;
"Content-Type" = "application/json";
Date = "Wed, 04 Mar 2015 21:47:51 GMT";
"Keep-Alive" = "timeout=7, max=150";
Server = Apache;
"Set-Cookie" = "SID=************; expires=Mon, 02-Mar-2020 21:47:51 GMT; path=/;domain=.*********";}},NSErrorFailingURLKey=https://***********,com.alamofire.serialization.response.error.data=< CORRECT POST BODY>, NSLocalizedDescription=Request failed: no error (200)}
If I delete this code:
self.responseSerializer.acceptableStatusCodes = NSIndexSet(index: 400)
Then the app crashes. However the server responses with status code 200...
I don't know how to solve this issue.
Could you help me?
Here I get the correct body. But why not in the normal success blog?
EDIT:
self.responseSerializer.acceptableStatusCodes = NSIndexSet(index: 200)
=> App crashs
self.responseSerializer.acceptableStatusCodes = nil
=> App crashs
self.responseSerializer.acceptableStatusCodes = NSIndexSet(index: 401)
=> App doesn't crash, but executes failure block. Status code in error message is 200 and error data contains the correct POST response body.
=> I could extract the message from the error data... but it's such a simple task. It has to work correctly.
Can't use Alamofire because I want to use ssl certificats!
Final edit:
Don't no why, but the error disappeared by its own.
If you haven't already done so, check out Postman (a Google Chrome app). That's the best way to debug AFNetworking issues, by simulating the same request and making sure the data is coming through properly. A number of times, I've been fighting an issue to then use Postman and discover that it's something the server is doing.
I found something that said:
acceptableStatusCodes
The acceptable HTTP status codes for responses. When non-nil,
responses with status codes not contained by the set will result in an
error during validation.
In Objective C:
self.responseSerializer.acceptableStatusCodes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 100)];
The previous post was very useful to fix it. I was searching more and more but nothing was helped out. I tried of adding different codes and got tired ton's of times. Finally seen the above post, which was really solved the issue. I spent 2 days to find the solution.
Initially got the error with -1011 with 400 error. I solved by using the below:
manager.responseSerializer.acceptableStatusCodes = [NSIndexSet indexSetWithIndex:400];
Again got different error like this: "200 no error". I solved by using below code:
manager.responseSerializer.acceptableStatusCodes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 100)];
It works!! cool!!
Hence, I advice you you guys to add the set of below code:
manager.responseSerializer.acceptableStatusCodes = [NSIndexSet indexSetWithIndex:400];
manager.responseSerializer.acceptableStatusCodes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 100)];
Thanks Stackoverflow!!!!

How to use PromiseKit to handle header-only response?

I'm using PromiseKit in an IOS app to communicate with a Rails RESTful backend,
and there're some calls that return only header, say by executing head 200 on the backend.
What I've tried is:
I used [NSURLConnection POST:url formURLEncodedParameters:parameters] to post data to backend, the backend did receive the data and responded with a head 200 message, but PromiseKit is reporting the following exception:
2014-07-31 11:19:39.501 HelloPOS[13223:60b] Error
Domain=NSCocoaErrorDomain Code=3840 "The operation couldn’t be
completed. (Cocoa error 3840.)" (No value.) UserInfo=0xa4c5a90
{NSDebugDescription=No value., PMKURLErrorFailingDataKey={length = 1, capacity = 16, bytes = 0x20},
PMKURLErrorFailingURLResponseKey= { URL:
http://SOME_APP.SOME_HOST.com/api/v1/sales.json } { status code: 200,
headers {
"Cache-Control" = "max-age=0, private, must-revalidate";
Connection = "keep-alive";
"Content-Length" = 1;
"Content-Type" = "application/json";
Date = "Thu, 31 Jul 2014 03:19:25 GMT";
Etag = "\"7215ee9c7d9dc229d2921a40e899ec5f\"";
Server = "WEBrick/1.3.1 (Ruby/2.0.0/2014-05-08)";
Via = "1.1 vegur";
"X-Content-Type-Options" = nosniff;
"X-Frame-Options" = SAMEORIGIN;
"X-Request-Id" = "5a1c1aa1-4b42-41ea-8397-a5df8fa956bc";
"X-Runtime" = "0.013359";
"X-Xss-Protection" = "1; mode=block"; } }}
It's probably because header-only response has no body, and the error is caused
PS: I've changed the URL in the exception message
The problem is the server claims that the response has a JSON content of length 1 byte. But the response does not parse into JSON, so PromiseKit errors that promise.
PromiseKit doesn't provide a mechanism to ignore the response, but you could easily make your own promise here if you cannot fix the server to provide correct responses.
#import <OMGHTTPURLRQ.h>
- (PMKPromise *)myPromise:(id)args {
id rq = [OMGHTTPURLRQ POST:url:args];
id q = ;
return [PMKPromise new:^(PMKPromiseFulfiller fulfill, PMKPromiseRejecter reject){
[NSURLConnection sendAsynchronousRequest:rq queue:q completionHandler:^(id rsp, id data, NSError *urlError) {
if (urlError) {
reject(urlError)
} else {
fulfill(nil);
}
}];
}];
}
EDIT: PromiseKit now works around this specific situation, so you should no longer get this specific error.

Post on website works on simulator but not on device?

I want to use the web service in my app and upload post on the website, at first I used ASIFormRequest API, it worked on simulator but did not work on device, I asked a question here and someone told me to change the API and use the RestKit (Here is the link for my previous question)
Right now I'm using RestKit API and I got the same problem, I cannot post on the website by device, but It works when I use simulator. Although it doesn't allow me to post but I can login both by the simulator and the device.
Here is my code for POST:
- (IBAction)addLinkPressed:(UIButton *)sender {
[RKClient clientWithBaseURLString:#"http://MyWebsite.com"];
NSDictionary* params = [NSDictionary dictionaryWithObjectsAndKeys:
self.linkField.text, #"url",
self.linkTitleField.text, #"title",
self.linkSummaryField.text, #"summary",
nil];
[[RKClient sharedClient] post:#"/send_link.php" params:params delegate:self];
}
- (void)objectLoader:(RKObjectLoader*)objectLoader didFailWithError:(NSError*)error {
NSRange range = [[error localizedDescription] rangeOfString:#"-1012"];
if (range.length > 0){
//Do whatever here to handle authentication failures
}
RKLogError(#"Hit error: %#", error);
}
- (void)request:(RKRequest*)request didLoadResponse:(RKResponse*)response
{
if ([request isGET]) {
// Handling GET /foo.xml
if ([response isOK]) {
// Success! Let's take a look at the data
NSLog(#"Retrieved XML: %#", [response bodyAsString]);
}
} else if ([request isPOST]) {
// Handling POST /other.json
if ([response isJSON]) {
NSLog(#"Got a JSON response back from our POST!");
}
} else if ([request isDELETE]) {
// Handling DELETE /missing_resource.txt
if ([response isNotFound]) {
NSLog(#"The resource path '%#' was not found.", [request resourcePath]);
}
}
NSLog(#"HTTP status code: %d", response.statusCode);
NSLog(#"HTTP status message: %#", [response localizedStatusCodeString]);
NSLog(#"Header fields: %#", response.allHeaderFields);
NSLog(#"Body: %#", response.bodyAsString);
}
Here is the error that I receive for RestKit API:
2012-09-11 22:33:01.053 (NameOfMyApp)[16271:707] I restkit.support:RKCache.m:189 Invalidating cache at path: /var/mobile/Applications/897B1DEA-1767-4F5C-AC8F-1809075C5CA9/Library/Caches/RKClientRequestCache-(Mywebsite).com/SessionStore
2012-09-11 22:33:01.057 (NameOfMyApp)[16271:707] I restkit.network.reachability:RKReachabilityObserver.m:123 Reachability observer initialized with IP address: 0.0.0.0.
2012-09-11 22:33:01.075 (NameOfMyApp)[16271:707] I restkit.network.reachability:RKReachabilityObserver.m:391 Network availability has been determined for reachability observer <RKReachabilityObserver: 0x10066330 host=0.0.0.0
2012-09-11 22:33:01.075 (NameOfMyApp)[16271:707] I restkit.network.reachability:RKReachabilityObserver.m:391 Network availability has been determined for reachability observer <RKReachabilityObserver: 0x10066330 host=0.0.0.0 isReachabilityDetermined=YES isMonitoringLocalWiFi=NO reachabilityFlags=-R -----l->
2012-09-11 22:33:01.325 (NameOfMyApp)[16271:707] I restkit.network:RKRequest.m:689 Status Code: 200
2012-09-11 22:33:01.328 (NameOfMyApp)[16271:707] HTTP status code: 200
2012-09-11 22:33:01.332 (NameOfMyApp)[16271:707] HTTP status message: no error
2012-09-11 22:33:01.338 (NameOfMyApp)[16271:707] Header fields: {
"Cache-Control" = "no-store, no-cache, must-revalidate, post-check=0, pre-check=0";
Connection = "Keep-Alive";
"Content-Encoding" = gzip;
"Content-Length" = 4679;
"Content-Type" = "text/html";
Date = "Wed, 12 Sep 2012 03:33:02 GMT";
Expires = "Thu, 19 Nov 1981 08:52:00 GMT";
"Keep-Alive" = "timeout=5, max=100";
Pragma = "no-cache";
Server = Apache;
Vary = "Accept-Encoding";
}
2012-09-11 22:33:01.345 (NameOfMyApp)[16271:707] Body: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
Ater these code, it shows the HTML code of the address that I use for POST ( http://MyWebsite.com/send_link.php)
Any Idea how can would be appreciated, I really need help :(
I found the answer, In simulator it doesn't need to put http:// at the beginning of the url addresses, but on device, if I do not input http:// the website that I use their web service doesn't allow me to POST. Isn't that weird!
Thank you guys for your comments.
One more thing is, when I close the app and reopen it I have to do login, any idea how I can make the username and password persistence?

Resources