Spoofing the user agent of an embedded Safari browser on the iPhone? - iphone

Is there any way to spoof the user agent on Safari on the iPhone?
So for example, you would create an application on the iPhone that has the embedded Safari browser, however any website the user visits with this browser wouldn't know you were on Safari on the iPhone, it would think you are on something like Safari on a PC, or even IE/FireFox.
Thanks

Yes I think you could change this. It would require a bit of a work around to get it working.
You would need to manually manage all requests. By making your own data requests.
In this data request you can add a HTTPheader for User-Agent which will override the default headers.
NSMutableURLRequest* urlRequest = [[[NSMutableURLRequest alloc] initWithURL:requestURL] autorelease];
[urlRequest setHTTPMethod: #"POST"];
[urlRequest setHTTPBody: [nvpString dataUsingEncoding:NSUTF8StringEncoding]];
[urlRequest addValue:#"Your+User+Agent+String" forHTTPHeaderField:#"User-Agent"];
receivedData = [[NSMutableData alloc] retain];
[receivedData setLength:0];
[NSURLConnection connectionWithRequest: urlRequest delegate: self];
If you embed the Safari Web Browser in your app you can subscribe to its delegate methods. One of them will notify your application that safari would like to load a URL, this is where you catch this load and get the data your self.
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
now you put your code in here to do the data load.
Once the data has loaded. Give it the data string back to the webView. I have set "baseURL:nil" but you might have to correctly set this to maybe the correct domain for this app.
[webView loadHTMLString:newString baseURL:nil]

Related

How to store the values in web server from i phone application

I am developing view based application.In my view i have register page in that page i have
some fields like Firstname, lastname,e mail ID. When we click save button after entering the values these all field should be store in in webserver.In webserver i have application that application was developed using .net MVC Architecture and database is MYSQL .How i can store these values in webserver.
thanks for your response i have written this code is it right way to store values in webserver
-(IBAction)buttonClick:(id)sender
{
NSString* firstname = nameInput.text;
NSString* lastname = passInput.text;
NSString* bname = lastInput.text;
NSString *post =
[[NSString alloc] initWithFormat:#"fname=%#&lname=%#&email=%#",firstname,lastname,bname];
NSData * postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:NO];
NSString * postLength = [NSString stringWithFormat:#"%d",[postData length]];
NSMutableURLRequest * request = [[[NSMutableURLRequest alloc] init] autorelease];
[request setURL:[NSURL URLWithString:[NSString stringWithFormat:#"http://www.yoursite.com/file.php?%#",post]]];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:postData];
NSURLConnection * conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if (conn) NSLog(#"Connection Successful");
}
#end
You have two options:
1) Develop a proper API that your iOS app can call using libraries like ASIHTTPRequest or AFNetworking
2) Have a .NET form processor in place, just like you would to process an HTML form, and then use ASIHTTPRequest, AFNetworking, or something similar to submit the request to this processor using the POST method and with the parameters you would like to store added to the request. This simulates an HTML form that has been filled and submitted, and then you can do whatever you wish with the data .NET receives. Both ASI and AFNetworking have pretty extensive documentation on how these types of requests are implemented on iOS with their respective libraries. Unfortunately, ASI is no longer being maintained, so I would recommend going with AFNetworking if possible.
RESPONSE TO UPDATE:
I only gave it a quick look over, but everything looks good to me. The only thing I would change is this:
[request setURL:[NSURL URLWithString:[NSString stringWithFormat:#"http://www.yoursite.com/file.php?%#",post]]];
to this:
[request setURL:[NSURL URLWithString:[NSString stringWithFormat:#"http://www.yoursite.com/file.php"]]];
What you will need now is code on the web side in that file.php that can process the request. It would use the typical $_POST['var_name_here'] to grab the data that is passed to it.
You have to implement a webapplication in your preferred language and deploy it to some webserver or hosting service. To get started, you should choose a language PHP, Java, Python, C# or whatever and google how you could implement a webservice within that language.
I would do this in Java and implement a RESTful wbeservice that sends and receives JSON or XML.

iPhone: How to download a raw .config file via program?

I am trying to download a xyz.config file which is created using iPhone Configuration utlity, via code.
NSString *urlString = #"http://xxxxx:xxx/ms/servlet/ConfigServer?userid=xxx&pwd=xxx&emailid=xxxxx";
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:urlString]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (theConnection) {
receivedData = [[NSMutableData data] retain];
} else {
// Inform the user that the connection failed.
}
Then, didReceiveData, didReceiveResponse are written. Finally,
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"Succeeded! Received %d bytes of data",[receivedData length]);
NSString *responseString = [[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding];
NSLog(#"Response : %#", responseString );
// release the connection, and the data object
[receivedData release];
[connection release];
}
With the above code, i'm getting response as string of the complete configuration file. But my Aim to download this file as raw data, which will automatically launch device profile to ask for installing this profile.
NOTE: I am able to provide the same URL in Safari browser on the device, and download the
raw file directly to install it on the device. I don't want to use Safari browser to download it, it should be done via my communication code.
I also tried with ASIHTTPRequest like below, but unable to download that file directly from the URL via this code as well.
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setRequestMethod:#"GET"];
[request startSynchronous];
Please help!
Thank you.
The Mobile Safari browser app on the iOS has a lot more freedom than your app. Case in point, on the latest iOS 4.3, Mobile Safari has the Nitro JavaScript engine which boost 2x performance increase. But the UIWebView which is available to your app doesn't have that engine. Your app is in a sandbox, therefore, you cannot write outside of that box.

Twitter profile image upload in objective-c

I want to upload an image to my twitter profile using objective-c. I saw in the twitter API that I need to send a HTML post to http://twitter.com/account/update_profile_image.format and send the picture as a parameter. I am done with the authentication. I am stuck with the uploading. Maybe somebody can help me with sending the picture as a parameter?
You should be using NSURLRequests and NSURLConnection to perform the API requests. If this is true, all you need to do is create an NSMutableURLRequest, set it's URL to the Twitter image upload API URL, set the method to POST.
Then you'll need to create an NSData object to represent your image, which you can do using
NSData *myImageData = [[NSData alloc] initWithData:[myImage CGImage]];
I don't know what the parameter name is for Twitter's upload API, so for arguments sake, lets call it "image". The next thing you need to do is set the image data as the request's body for the "image" parameter, like this
NSString *bodyString = [NSString stringWithFormat:#"image=%#", [[[NSString alloc] initWithData:myImageData encoding:NSStringUTF8Encoding] autorelease]];
[myRequest setBody:bodyString];
Then you can just start your NSURLConnection with the request and it should upload.
If you’ve managed to get started, then this post on CocoaDev should help you set the uploading up. There’s a sample linked at the top too.
I recommend using ASIHTTPRequest
What is ASIHTTPRequest?
ASIHTTPRequest is an easy to use wrapper around the CFNetwork API that makes some of the more tedious aspects of communicating with web servers easier. It is written in Objective-C and works in both Mac OS X and iPhone applications.
It is suitable performing basic HTTP requests and interacting with REST-based services (GET / POST / PUT / DELETE). The included ASIFormDataRequest subclass makes it easy to submit POST data and files using multipart/form-data.
See this blog post for an example
Somthing like this
// See http://groups.google.com/group/twitter-development-talk/browse_thread/thread/df7102654c3077be/163abfbdcd24b8bf
NSString *postUrl = #"http://api.twitter.com/1/account/update_profile_image.json";
ASIFormDataRequest *req = [[ASIFormDataRequest alloc] initWithURL:[NSURL
URLWithString:postUrl]];
[req addRequestHeader:#"Authorization" value:[oAuth oAuthHeaderForMethod:#"POST"
andUrl:postUrl andParams:nil]];
[req setData:UIImageJPEGRepresentation(imageView.image, 0.8)
withFileName:#"myProfileImage.jpg"
andContentType:#"image/jpeg" forKey:#"image"];
[req startSynchronous];
NSLog(#"Got HTTP status code from Twitter after posting profile image: %d", [req
responseStatusCode]);
NSLog(#"Response string: %#", [req responseString]);
[req release];

Handling redirects correctly with NSURLConnection

For the purposes of this, I'm going to pretend the original url is http://host/form and the new url is https://host/form. (Note that before I ship this, both URLs are going to be secure. However, the nonsecure-to-secure seems like a convenient redirect to test this on.)
I'm accessing a web API using NSURLConnection that redirects me. Basically, I want to take everything I just submitted to http://hostaform and re-submit it to https://host/form. I thought this would be the default behavior, but it looks like the body is being lost in the redirect.
So I think I need to handle the connection:willSendRequest:redirectResponse: event of the NSURLConnection's delegate and re-attach the body. The problem is this message seems woefully underdocumented. The only info I can find on this method is NSURLConnection Class Reference, which isn't very helpful. Among other things, it includes this:
redirectResponse: The URL response that caused the redirect. May be nil in cases where this method is not being sent as a result of involving the delegate in redirect processing.
I'm not sure what this means. Combined with an initial willSendRequest: invocation, I think this is means willSendRequest: is being sent even for my initial request, prior to the redirect response. Is that correct?
So I've added code to my delegate to retain the body an extra time, and added this willSendRequest: handler:
- (NSURLRequest *)connection: (NSURLConnection *)inConnection
willSendRequest: (NSURLRequest *)inRequest
redirectResponse: (NSURLResponse *)inRedirectResponse;
{
if (inRedirectResponse) {
NSMutableURLRequest *r = [[inRequest mutableCopy] autorelease];
[r setURL: [inRedirectResponse URL]];
[r setHTTPBody: body];
return r;
} else {
return inRequest;
}
}
It doesn't work. But I'm not even sure if this is the right approach. It seems excessively hackish to me. What should I be doing? Is this documented anywhere? I've found nothing useful in Apple's documentation or using Google so far.
(This is on the iPhone, although there doesn't seem to be much difference in these classes.)
There's a note in section 10.3.2 of RFC 2616 about this behaviour:
Note: When automatically redirecting a POST request after
receiving a 301 status code, some existing HTTP/1.0 user agents
will erroneously change it into a GET request.
So this behaviour seems to be non-standard but historical. That GET request is not a POST, and it'll be missing the payload.
Interestingly enough, this is also in the same section:
If the 301 status code is received in response to a request other
than GET or HEAD, the user agent MUST NOT automatically redirect the
request unless it can be confirmed by the user, since this might
change the conditions under which the request was issued.
That's pretty clear and seems to indicate we can't fix this, but I think ignoring this for the purpose of our own web service clients for services we pick (or control) is probably the least bad alternative.
So how do we solve this?
Instead of the willSendResponse: in the original question, I'm using this:
- (NSURLRequest *)connection: (NSURLConnection *)connection
willSendRequest: (NSURLRequest *)request
redirectResponse: (NSURLResponse *)redirectResponse;
{
if (redirectResponse) {
// we don't use the new request built for us, except for the URL
NSURL *newURL = [request URL];
// Previously, store the original request in _originalRequest.
// We rely on that here!
NSMutableURLRequest *newRequest = [_originalRequest mutableCopy];
[newRequest setURL: newURL];
return newRequest;
} else {
return request;
}
}
The idea here is that instead of cloning the new request and trying to shape it the same as the one Cocoa Touch sends me, I create a clone of the original request and change just the URL to match the request Cocoa Touch sent me. That original request is still a POST with the payload attached.
If you control the server, it's worth reading RFC 2616, section 10.3 in its entirety to see if there's a better code you can use (while checking, of course, that iOS handles the better code as it should).
You could also make a mutable copy of the redirected request and replace its HTTP method with the HTTP method of the original request. Same general principle, though that would favour keeping things from the new request rather than the old. In some circumstances that might work better, but I haven't tested this yet.
You should be checking the HTTP response status code sent by the server to determine whether to send a GET or repeat the POST. For 303 (or 302), send a GET request. For 307, repeat the POST.
i had the same problem with redirecting.
Thanks to AJSoaks!
I tried as he suggested and the problem is resolved.
So, i was trying to post the username and password through the POST method, and i saw that server redirected my request. As AJSoaks says, in case if there is 302 error you should repeat the request but this time using GET method instead of previous POST.
... at some point you have the following lines:
... it can be inside if your IBAction (button pressed) method or wherever you want...
NSMutableString *postString = [[NSMutableString alloc] init];
[postString appendString:#"username=YourUsername&password=YourPassword"];
//the original URL (https means that it supports SSL protocol)
//it doesn't change anything, don't worry about it
NSURL *URL = [NSURL URLWithString:#"https://loginWebpageURL"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
[request setHTTPMethod:#"POST"];
[request setValue:[NSString stringWithFormat:#"%d", [postString length]] forHTTPHeaderField:#"Content-length"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-type"];
[request setHTTPBody:[postString dataUsingEncoding:NSUTF8StringEncoding]];
[NSURLConnection connectionWithRequest:request delegate:self];
[postString release];
[request release];
Than you should also implement the redirect NSURLConnection delegate method, with the following signature:
- (NSURLRequest *)connection:(NSURLConnection *)connection
willSendRequest:(NSURLRequest *)request
redirectResponse:(NSURLResponse *)redirectResponse
inside of this method, in case if you have SERVER's Error 302 or 303 you should implement something similar to the code bellow, just copy the code that you see and replace it with the new URL (redirected). The new URL you can see in the browser or if you want it is very useful, also in the future, checking it with Firebug (Firefox plugin) or Safari WEB INSPECTOR. If you use Firebug all information you can find under the "Net" option:
if (redirectResponse) {
NSLog(#"REDIRECT");
NSMutableURLRequest *requestTmp = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"https://areaclienti.tre.it/selfcare/areaclienti133/4552_infoCosti_ITA_HTML.xsl"]];
return [requestTmp autorelease];
}
//return original request in case thay there is no redirecting...
else return request;
NSURLConnection does not add the originalRequest headers into the redirected request in the "willSendRequest: (NSURLRequest *)inRequest".
You can workaround this problem by adding "originalRequest.headers" into the redirected request.

Can I log in to my site from my iPhone app?

I'm trying to make a log in or sign up feature for my web site in my iPhone app. My website is a content management system, and like any other CMS, it has log in and registration features. It also has permmissions, dependent on the user account. I think I would have to use UIWebView for this.
Are there any examples or tutorials I can examine?
Check out the documentation for NSURLRequest (and NSMutableURLRequest): you can use it to make a POST request to your login and registration pages, just like a web browser. You can write the form UI in Cocoa/Objective-C and then send the data to the server.
As far as displaying the result to the user, you'll have to figure out a way to either parse the returned HTML (bad idea) or modify your CMS to return JSON or XML to iPhone requests (better idea).
Edit: Here's some sample code, taken from an app I'm working on (it submits data to Last.fm using POST):
NSURL *url = [NSURL URLWithString:#"http://example.com/"];
NSString *str = #"This is my example data!";
// everything below here is directly from my app:
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:[str dataUsingEncoding:NSUTF8StringEncoding]];
[request setValue:kLastFMClientUserAgent forHTTPHeaderField:#"User-Agent"];
[request setCachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData];
[request setHTTPShouldHandleCookies:NO];
*connection = [[NSURLConnection alloc] initWithRequest:request
delegate:self
startImmediately:YES];