I have a bit of code for sending/receiving data from a webpage that works ~90% of the time. However the ~10% of the time it doesn't really bothers me, and I can't understand what's going on because the code isn't changing, and I have a similar android implementation that works flawlessly. Here's what I have.
- (NSString*) postData:(NSString*) url params:(NSString*) params
{
NSURL* urlRequest = [NSURL URLWithString:url];
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:[urlRequest standardizedURL] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10.0f];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/x-www-form-urlencoded;charset=utf-8" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:[params dataUsingEncoding:NSUTF8StringEncoding]];
NSError* err = nil;
NSData* responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&err];
if (!err) {
return [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];;
}
return nil;
}
- (NSString*) getData:(NSString*) url
{
NSURL* urlRequest = [NSURL URLWithString:url];
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:[urlRequest standardizedURL] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10];
NSError* err = nil;
NSData* responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&err];
if (!err) {
return [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];;
}
return nil;
}
I call getData to make the initial connection to the website. It has some information I parse out (two security tokens to send in when I send postData) and then send the data through the POST request. This first part always works everytime. However I then send another POST request to change pages again (after parsing out any new security tokens), and this is the part that fails ~10% of the time. By fail, I mean the website responds that my session has been compromised. I know this message happens if the security tokens are invalid, but I've checked those over and over and over and everytime they're fine. My theory is that I'm loosing cookie information, but from what I understand NSURLConnection should store the cookie information based on domain.
If I open a browser and go to the page, then delete the only cookie that is stored however, it takes me back to the login page (like expected) and doesn't give me the error message about my session being corrupted.
Any ideas would be greatly appreciated
Related
I'm writing some with server API. I'm using RestKit but this question I wrote without. I don't understand why console request is working and my is not. Please help me with this.
-(void)uploadFile {
NSString *URLPath = [NSString stringWithFormat:#"https://api.interlabs.pro/v1/texts/23041/content"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:URLPath]];
[request setHTTPMethod:#"PUT"];
[request addValue: #"Bearer ewogICAgInR5cCI6ICJKV1QiLAogICAgImFsZyI6ICJIUzI1NiIKfQ.ewogICAgImlzcyI6ICJhcGkuaW50ZXJsYWJzLnBybyIsCiAgICAiaWF0IjogMTQ2MzY3ODg2NCwKICAgICJleHAiOiAxNDYzNjgyNDY0LAogICAgInN1YiI6IDgzCn0.SuvGXfsDDzpA5-qJtRUZi7uw98IqA8_axfTGcMVjZdw" forHTTPHeaderField: #"Authorization"];
NSError *err;
NSURLResponse *response;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&err];
NSString *resSrt = [[NSString alloc]initWithData:responseData encoding:NSASCIIStringEncoding];
NSLog(resSrt);
}
And it's still doesn't not work, but console work perfectly
But enter link description here
update token link
The code works fine and result is that token is expired.
But you should not use deprecated methods like "NSURLConnection sendSynchronousRequest", then you should check error, when handling results from internet it is utf8 most of the time and not ascii. Then when logging strings use NSLog(#"%#", theString) to avoid problems if the content of theString contains formating specifiers.
I came to the last stage of development of my app and here is the bit that I've never done before.
My friend has developed and API for my app to send and receive data, using django rest framework.
I need to authenticate my app to connect to it, send some data and receive data.
What I have found so far is:
NSURL *url = [NSURL URLWithString:#"http://localhost:8080/my/path/to/api/login/"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
NSString *authStr = [NSString stringWithFormat:#"%#:%#", #"myUsername", #"myPassword"];
NSData *authData = [authStr dataUsingEncoding:NSASCIIStringEncoding];
NSString *authValue = [NSString stringWithFormat:#"Basic %#", authData];
[request setValue:authValue forHTTPHeaderField:#"Authorization"];
[request setHTTPMethod:#"GET"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
//------------------------------------------------------------------------------------------------------------------------------------//
//EDIT: Added this based on answer form #Quver.
NSURLResponse *response1;
NSError *responseError;
NSData *result = [NSURLConnection sendSynchronousRequest:request returningResponse:&response1 error:&responseError];
if (result.length > 0 && responseError == nil)
{
NSDictionary *greeting = [NSJSONSerialization JSONObjectWithData:result
options:0
error:NULL];
NSLog(#"Got response form server: %#", greeting);
}
This equals output like:
<0a0a3c68 746d6c3e 0a0a2020 20203c68 6561643e 0a202020 20202020 200a2020 20202020 20200a20 20202020 + ~50 lines of similar stuff. Hope this helps.
//-----------------------------------------------------------------------------------------------------------------------------------------//
I guess this is the way to create request. What should I do next? And how do I know that I have connected?
Then, if I have connected, how do I get data form there? (I have a url that gives me json as output - this is what I want to get). Assume the url to be http://localhost:8080/url/that/gives/json/.
Thank you for any help. Hope this is enough information for the question. I will add anything else required.
NSURLResponse *response;
NSError *responseError;
NSData *result = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&responseError];
Add this to get response. You already prepared request, now it's time to send it with NSURLConnection. I you sync request insted of async, becouse of using GCD for whole metod request + sqlite update.
After a few days of searching I have found a way.
First, we need a token for authentication. I am generating it through terminal for now:
curl -X POST -d "grant_type=password&username=<your username>&password=<your password>" http://<client secret>:<client id>#url/to/token/page
Then, in your view controller where you want to connect:
//always put </> at the end of link
NSURL *aUrl = [NSURL URLWithString: #"http://where/you/trying/to/conect"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:aUrl
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:30.0];
[request addValue:[NSString stringWithFormat:#"<type> <your token>"] forHTTPHeaderField:#"Authorization"];
[request setHTTPMethod:#"GET"];
NSError *error = nil;
self.response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error: &error];
This will return any json that the page supposed to return. This might not be the most secure way, but this is exactly what I need for now. I will look at more secure solutions like OAuth 2, later.
Hope this helps to someone.
I am trying to call a web service that is developed with ASP.NET. The purpose is to pass a username and password to the web service to simulate a log-in procedure.
In order to call the service i used the following method:
NSError *errorReturned = nil;
NSString *urlString = #"http:myDomain/myMethod?Operation=SignIn";
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod: #"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setObject:#"test" forKey:#"userName"];
[dict setObject:#"test" forKey:#"passWord"];
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:kNilOptions error:&errorReturned];
[request setValue:[NSString stringWithFormat:#"%d", [jsonData length]] forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody: jsonData];
NSURLResponse *theResponse =[[NSURLResponse alloc]init];
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&theResponse error:&errorReturned];
if (errorReturned)
{
NSLog(#"%#", errorReturned);
}
else
{
NSString *retVal = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"%#", retVal);
}
After running the app and clicking on the UIButton that fires the above method, nothing is shown in the console window.
The service returns the response in JSON format.
I want to know if i am missing something here since i am neither getting an error nor success log?
Any help would be appreciated!
Thank you.
Granit
A couple of thoughts:
If this method is getting called, you'd see something, even if retVal was empty and your
NSLog(#"%#", retVal);
just logged the app name and timestamp. Maybe change that NSLog to
NSLog(#"retVal = %#", retVal);
to remove any ambiguity. Or put in breakpoints in your code and single step through it to see what path the app takes.
Are you confident of your server interface? For example, is it possible that the Operation value of SignIn belongs in the JSON request, itself? Also, some services are case sensitive, so you might want to check that, too.
I don't know what access you have to the server, but it would be worthwhile to check the logs to make sure the request was received, possibly temporarily adding some logging within the code so you can confirm that the parameters were all received properly. Or, if nothing else, make sure that the server properly logs/reports any errors.
BTW, your instantiation of theResponse is unnecessary, and should just be
NSURLResponse *theResponse = nil;
The sendSynchronousRequest call doesn't populate an existing NSURLResponse instance, but rather creates a new instance and updates theResponse to point to it.
You should fix your request first, but you probably want, at the very least, to change this to use sendAsynchronousRequest instead of sendSynchronousRequest. You should never do synchronous calls on the main thread.
I solved my issue by using ASIHHTPRequest. Also i checked the server interface and it turned out that the parameters had to be sent with the URL.
-(void)signInAction:(id)sender{
NSURL *url = [NSURL URLWithString:#"http://mydomaain.com/UserService/SignIn/test/test"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDidFinishSelector:#selector(requestCompleted:)];
[request setDidFailSelector:#selector(requestError:)];
[request setDelegate:self];
[request setRequestMethod:#"GET"];
[request startAsynchronous];
}
- (void)requestCompleted:(ASIHTTPRequest *)request
{
NSString *responseString = [request responseString];
//[responseString UTF8String];
NSLog(#"ResponseString:%s",[responseString UTF8String]);
}
- (void)requestError:(ASIHTTPRequest *)request
{
NSError *error = [request error];
NSLog(#"Error:%#",[error description]);
}
I'm writing an iPad app that needs to communicate with a backend server. The first order of business in using this backend is to login, and for this the server has a URL that we can POST to, which I do like this:
// Create the request.
NSString* loginURL = #"http://foo.local/signature/service/auth/rest/firewall/login";
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:loginURL]];
NSString* credentials = #"{\"userName\":\"foo2#foolinator.com\", \"password\":\"password\"}";
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:[credentials dataUsingEncoding:NSASCIIStringEncoding
allowLossyConversion:YES]];
// Logging in...
NSError* error = nil;
NSURLResponse* response;
NSData* result = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*) response;
NSString* responseString = [NSHTTPURLResponse localizedStringForStatusCode:[httpResponse statusCode]];
NSLog(#"Response String is: %#\n", responseString);
NSLog(#"Header fields are: %#\n", [httpResponse allHeaderFields]);
What's odd is that the response I'm getting is Error 405: Method Not Allowed. I would've expected this if I was doing a GET, but I'm doing a POST.
I installed WireShark to examine the HTTP requests and it seems that there's actually two being made. The first one, is a POST call, and the server returns some cookie information as a response, and then a second GET call, which is what the code above gets back.
Why does this happen? Is it something to do with the response from the server the first time?
While you research your web service's login API, a couple of unrelated observations:
You should be sending this asynchronously if doing this from the main queue. Never issue synchronous network requests from the main queue. If you do this synchronously on the main queue (a) you risk having the iOS watch-dog process kill your app, which happens if the main queue becomes unresponsive while some synchronous network request is being processed; and (b) it's a bad UX to simply freeze an app during a network request ... if you need, disable the UI and show an indeterminate progress indicator (a UIActivityIndicatorView) while the network request is in progress.
You should probably be setting a value forHTTPHeaderField for Content-Length. It's probably not required, but it's good practice.
You probably should not be using a string with the JSON with the userid and password, but rather you should probably build this from a NSDictionary using something like NSJSONSerialization. As it is, if your password, for example, had any characters that needed to be escaped (e.g. a quotation mark), the existing code might not work. Using NSJSONSerialization is an easy way to ensure that your JSON is properly formatted.
You probably should not be sending a password in plaintext in your JSON request. At the very least, I hope your server employs HTTPS.
Anyway, with these observations, assuming your server really is expecting a JSON request, I might suggest something like:
// hopefully your production server is employing HTTPS
NSString *loginURL = #"https://foo.local/signature/service/auth/rest/firewall/login";
// use NSJSONSerialization to create JSON rather than building it in a NSString
NSDictionary *postDictionary = #{#"userName": userName, #"password": password}; // assuming you have NSString variables, `userName` and `password`
NSError *error = nil;
NSData *postData = [NSJSONSerialization dataWithJSONObject:postDictionary options:0 error:&error];
NSAssert(postData, #"dataWithJSONObject failed: %#", error);
// when creating request, also set Content-Length
NSURL *url = [NSURL URLWithString:loginURL];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:postData];
[request setValue:#"application/json; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
// issue request asynchronously
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
if (connectionError) {
NSLog(#"sendAsynchronousRequest error: %#", connectionError);
return;
}
// process the server response here
}];
You might still want to use a NSURLConnectionDataDelegate/NSURLConnectionDelegate based request (you can identify redirects, challenges, cancel it if you need, etc.), but the above might be a good start at an asynchronous JSON-based request.
I'm trying to use NSURLConnection sendSynchronousRequest: to send a binary file (an JPEG image) to a server. The code I have is:
// url contains the URL of the remote server.
// fileURL contains the URL for the local file to be sent.
request = [NSMutableURLRequest requestWithURL:url];
[request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];
[request setHTTPMethod:#"PUT"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"image/jpeg" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBodyStream:[NSInputStream inputStreamWithURL:fileURL]];
responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&requestError];
if (requestError != nil) {
NSLog(#"%#", requestError);
return NO;
}
This almost works. The remote server receives the request properly, and responds with an appropriate JSON object. But sendSynchronousRequest: blocks until the timeout value, and then reports a timeout.
Elsewhere, I'm able to send and receive JSON objects properly using pretty much this same code pattern, so I'm baffled why this one would be timing out.