get url after redirect with stringWithContentsOfURL - iphone

NSString* HTML = [NSString stringWithContentsOfURL:url usedEncoding:&enc error:&error];
works great, but if there is a redirect I need to know the url of the redirected page.
Any ideas?
Thanks~~

You will probably want to use NSURLConnection and load manually rather than using the stringWithContesOfURL method. Then you can set a URLConnectionDelegate on your connection. When you get redirected, the connection will call this method on your delegate:
- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse
The request argument provides the URL that you are being redirected to. You can inspect it and do what you want with it. If you want to allow the redirect to continue then you should return it from your delegate's method.

Here you go (synchronous approach):
NSURLResponse *response;
NSError *error;
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:#"URL_STRING"]];
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSLog(%#,response.URL);

Related

Refactoring my code for asynchronous NSURLConnection

There are problems with using synchronous requests. The problem is that I am not really sure how to refactor the code below to use an asynchronous request to accomplish the following two tasks:
Use a UIActivityIndicatorView subview to notify of active fetching;
Implement a Reachability check before the connection request to ensure that there is an Internet connection and that the host is available, i.e. reachabilityWithHostName:#"wwww.mywebhostingisterrible.com".
Currently I have a Fetcher class with a +(Fetcher *)sharedFetcher singleton that is used in all of my view controllers to fetch data. Currently all data is fetched using the following code:
- (NSString *)stringWithUrl:(NSURL *)url {
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:30];
NSData *urlData;
NSURLResponse *response;
NSError *error;
urlData = [NSURLConnection sendSynchronousRequest:urlRequest
returningResponse:&response
error:&error];
return [[NSString alloc] initWithData:urlData encoding:NSUTF8StringEncoding];
}
A method that fetches looks like this:
-(NSArray *)fetchDogFoodListing {
NSString *urlString = [NSString stringWithFormat:#"%#query/dogFood/%#/%lli/%#/%#",self.connectionUrl,self.queryCriteria.dogFoodName,self.queryCriteria.dogFoodBrandId,self.queryCriteria.dogFoodIngredients,self.queryCriteria.dogFoodBrand];
NSString *json = [self stringWithUrl:[NSURL URLWithString:urlString]];
return [self.factory buildIKDogFoodArrayWithJSON:json];
}
and a call from the UIViewController in -(void)viewDidLoad looks like this:
self.dogFoods = [[IKFetcher sharedFetcher] fetchDogFoodListing];
I have thought about implementing a delegate in this situation but I am very shaky on how delegation ought to work. I'm not even sure which way it should go. Should the Fetcher have a FetcherDelegate that can notify the view controller of when it is done, so the UI can update? Should the view controller have a delegate so that the fetcher can update the view when stuff is done?
I'm sure based on my questions you can see my inexperience with delegation, so I would appreciate any help.
You could do something like this
dispatch_async(queue, ^{
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:30];
NSData *urlData;
NSURLResponse *response;
NSError *error;
urlData = [NSURLConnection sendSynchronousRequest:urlRequest
returningResponse:&response
error:&error];
dispatch_async(dispatch_get_main_queue(), ^{
//.. do stuff with data here...
}
}
or you could just do the sendSynchronousRequest code inside a dispatch_sync if you want the connection to be synchronous, though you should really should be as asynchronous as possible.
you may want to look at the brilliant framework by Mugunth Kumar:
http://blog.mugunthkumar.com/products/ios-framework-introducing-mknetworkkit
I plan on using this for NSURLConnection in my future projects

Get content of webservice

I've got an URL like here. When I type that into Safari's address bar I see an result like "Error" or "OK".
So, how do I properly call that URL from within my code and get that result as a string?
I've tried it with NSURLConnection, NSURLRequest and NSURLResponse but my response object is always nil.
The "response" in those classes refers to the protocol response (HTTP headers, etc.), not the content.
To get the content, you have a few options:
Use NSURLConnection in asynchronous mode: Using NSURLConnection
Use NSURLConnection in synchronous mode:
// Error checks omitted
NSURL *URL = [NSURL URLwithString:#"http://www.myserver.com/myservice.php?param=foobar"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
NSData *data = [NSURLConnection sendSynchronousRequest:request
returningResponse:nil
error:nil];
Use [NSString stringWithContentsOfURL:]
NSURL *URL = [NSURL URLwithString:#"http://www.myserver.com/myservice.php?param=foobar"];
NSString *content = [NSString stringWithContentsOfURL:URL];
Of course, you should use options 2 and 3 only if your content will be really small in size, to maintain responsiveness.

iPhone Objective-C: combining methods together

I'm a complete noob at objective-C, so this might be a very silly question to a lot of you.
Currently, I have a view with a 'SignIn' button, which when clicked, activates a sigupUp IBAction that I have defined below. Basically, this method needs to make a JSON call and get back some data about the user.
So, right now, my code looks something like this:
-(IBAction)signIn:(id)sender{
//run registration API call
//establish connection
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%d",[postData length]];
NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
[request setURL:[NSURL URLWithString:[NSString stringWithFormat:#"http://www.apicallhere.com/api/auth"]]];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Current-Type"];
[request setHTTPBody:postData];
[[NSURLConnection alloc]initWithRequest:request delegate:self];
responseData = [[NSMutableData data] retain];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{[responseData setLength:0];}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{[responseData appendData:data];}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{/*NSLog(#"%#",error);*/}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
NSString *response=[[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
....code carries on from here.
}
As you can see, the problem with my code is that even though it is initiated via the 'SignUp' method, it finishes with the 'connectionDidFinishLoading' method. I want to have all this code in a single method. Not 2 separate ones, as I want to be able to return a boolean verifying if the connection was successful or not.
If someone could please tell me how to code up this procedure into a single method, I would really appreciate it.
If you really want the code all in one method, you're talking about potentially blocking all of the UI and so forth on a synchronous HTTP request method and response call.
The method to put this all "inline" is sendSynchronousRequest:returningResponse:error on NSURLConnection
[NSURLConnection sendSynchronousRequest:returningResponse:error:]
i.e.
NSError *error;
NSURLResponse *response;
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
... do something with the NSURLResponse to enjoy with your data appropriately...
I would personally encourage you to look at an alternative for most of this sort of thing towards the asynchronous methods.

iPhone development: How to implement HTTPS connection?

I am working on an iPhone project which need to connect to the IIS server over HTTPS or SSL protocol. Can anyone tell me how to implement HTTPS connection in iPhone? Any advice would be appreciate.
Thank you in advance.
Ben Copsey's ASIHTTPRequest framework makes it trivially easy to issue web requests over SSL.
Modifying the site's example slightly:
NSURL *url = [NSURL URLWithString:#"https://allseeing-i.com"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request startSynchronous];
NSError *error = [request error];
if (!error) {
NSString *response = [request responseString];
NSLog (#"%#", response);
}
Just use NSURLConnection with an NSURLRequest pointing to an NUSUL with https protocol, just like that:
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"https://mySecureServer.net"]];
NSURLResponse *response = nil;
NSError *error = nil;
NSData *result = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if (!error) {
//do something with response & data
}
But I suggest you have a look at the documentation of the URL loading system in Cocoa.
Jason don't forget to implement the connection:canAuthenticateAgainsProtectionSpace and connection:didReceiveAuthenticationChallenge to make sure you're handling the challenges for the Server authentication and Client Authentication:
check out this post that will help you with this https://devforums.apple.com/message/143091#143091
You probably don't have a public certificate. Can you access the https resource with firefox/safari/chrome without an error? if not - that's the problem, not your code.

iPhone API for Accessing Amazon S3 REST API

Does anyone have any suggestions for GETing from or POSTing to Amazon S3 services using their REST API via the iPhone. It does not look like it is possible but I may be reading the docs wrong.
Thank you in advance for your help!
L.
In a general case I'd recommend to use ASIHttpRequest, it has a lot of built-in functionality (REST compatible too) and a lot of things, making life easier than with NSURLConnection.
It also has S3 support out of box.
You should be able to use the NSURLRequest stuff to do what you want.
NSMutableData* _data = nil;
- (IBAction) doIt:(id)sender {
NSURL* url = [NSURL URLWithString: #"http://theurl.com/"];
NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL: url];
NSURLConnection* con = [NSURLConnection connectionWithRequest: req delegate: self];
NSData* body = [#"body of request" dataUsingEncoding: NSUTF8StringEncoding];
_data = [NSMutableData new];
[req setHTTPMethod: #"POST"];
[req setHTTPBody: body];
[con start];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[_data appendData: data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString* result = [[[NSString alloc] initWithData: _data encoding: NSUTF8StringEncoding] autorelease];
// process your result here
NSLog(#"got result: %#", result);
}
This doesn't have any error checking in it and the _data variable should be stored in an instance variable, but the general idea should work for you. You will probably also need to set some request headers to tell the server what encoding the body data is in and so on.