iPhone NSData/NSUrl with cookie - iphone

I'm trying to play/stream a mp3 hosted on a website. The site requires a cookie header to be set, but I'm having trouble setting that or getting the container to do that for me.
NSURL *sampleUrl = [NSURL URLWithString:#"http://domain/files/sample.mp3"];
NSData *sampleAudio = [NSData dataWithContentsOfURL:sampleUrl];
Up until this point, I've been using jQuery to do/manage XMLHTTPRequests, but I've had to call into native code to stream the audio. It doesn't look like the cookie is getting picked up by the native HTTP request.
Is there anyway to inject the cookie into the above request, or otherwise ensure that a cookie gets added against a given domain?
Thanks

Ok, so the way to do this is not injecting headers but setting a cookie manager to always accept cookies. This will then pass on the cookie to subsequent requests.
NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
[cookieStorage setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways];
Robbie

Related

Cookie from ios webview

I wanted to ask some things about a piece of code i'm trying to make without having any previous contact with ios or objective-c.
This piece of code will:
Open a WebView with a specific url where the user will login
(done)
After the user logs in it will take the cookie created
from that login.
It will use that cookie in a next request to
load another site that requires authentication.
I'm stuck a bit at part 2 because it has to a) wait in another thread till the user does the login (how?) and b) because i can't seem to get the specific cookie for the site easily. I have only found and tried this poc but how do I filter out only the cookie for the site I want?
NSHTTPCookie *cookie;
NSHTTPCookieStorage *cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage];
for(cookie in [cookieJar cookies]) {
NSLog(#"%#", cookie);
}
Any ideas on how to make the 2a/b parts? Objective-c syntax seems a bit confusing.
I found a solution by following this https://www.inkling.com/read/learning-ios-programming-alasdair-allan-2nd/chapter-7/embedding-a-web-browser-in-your .
Used the webViewDidFinishLoad delegate and got the cookies from there with the cookiesForURL method.
NSArray* availableCookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:[NSURL URLWithString:#"MYURL"]];
Cookies are created as follows,
NSDictionary *properties = [NSDictionary dictionaryWithObjectsAndKeys:
url, NSHTTPCookieOriginURL,
#"testCookies", NSHTTPCookieName,
#"1", NSHTTPCookieValue,
nil];
NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:properties];
You can use the cookie object to get the origin URL attribute and filter.
NSDictionary *cookieProperties = [cookie properties];
NSURL *originURL = [cookieProperties objectForKey:NSHTTPCookieOriginURL];
After filtering the cookie you need you can get the cookie value using,
cookie.value

iphone nsurlconnection read cookies

I am using async NSURLConnection to connect to a web site from iPhone. Handle didReceiveResponse is activated on response and I am trying to get all cookies, by using allHeaderFields from NSHTTPURLResponse
I see many hreader, but no Set-Cookie - it looks like iphone simulator just ignores them...
And I am sure cookies are present in response - network monitor shows they present
I do not use any http storage - all that I am trying to do is to print to log all header - and do not see cookies info
Does anybody know about this issue?
UPDATE
I have made some research: if my website returns custom header, like "Custom-Header: value" - then this header is visible in java client, but is not in iphone...
thanks
Try to look for it in the shared HTTP cookies storage:
for (NSHTTPCookie *cookie in [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies])
{
NSLog(#"name: '%#'\n", [cookie name]);
NSLog(#"value: '%#'\n", [cookie value]);
NSLog(#"domain: '%#'\n", [cookie domain]);
NSLog(#"path: '%#'\n", [cookie path]);
}
or if working in Swift:
for cookie in HTTPCookieStorage.shared.cookies!
{
NSLog("name: \(cookie.name)")
NSLog("value: \(cookie.value)")
NSLog("domain: \(cookie.name)")
NSLog("path: \(cookie.path)")
}
Try this: in your NSMutableURLRequest, you should tell it to handle cookies:
[request setHTTPShouldHandleCookies:YES];
I don't know if it matters in apps, but what is your Accept Cookies setting for Safari in the Settings app. See if changing to Always matters.
According to some sites I've seen, a complete reboot of the iPhone is required for this setting to have any effect.

Private browsing with UIWebView on the iPhone & iPad

How do existing apps implement this feature???
Can I store cookie only for certain sites, and only inside my app? It's my understand that the web view stores cookies in shared mode...so that they are shared with Safari and other apps that use UIWebView.
According to the NSHTTPCookieStorage docs, cookies are not shared between applications:
iPhone OS Note: Cookies are not shared
among applications in iPhone OS.
So it seems like they should be "private" by default. You can also use the [NSHTTPCookieStorage sharedHTTPCookieStorage] object to set the cookie storage policy to not store cookies at all, or you could use the deleteCookie: method to clean up after yourself if you needed to.
As for other content that is loaded by your UIWebview, when you create the NSURLRequest that is loaded by your webview, you can set a cache policy that controls if the content will be cached. For example:
NSURLRequest * request = [NSURLRequest requestWithURL: [NSURL URLWithString: url]
cachePolicy: NSURLRequestReloadIgnoringLocalAndRemoteCacheData
timeoutInterval: 60.0]
[webView loadRequest: request];
NSURLRequestReloadIgnoringLocalAndRemoteCacheData tells the request to ignore the cache and load the request from the network. I'm not sure if it also prevents the response from the network from being cached, but to be sure, you could alway remove it from the cache yourself:
[NSURLCache sharedURLCache] removeCachedResponseForRequest:request];
If you're talking about Private Browsing, the UIWebView actually does not store history after the app is closed (only temporary for going back and forth). Instead you would have to implement storing history yourself, so it would be automatically Private Browsing.
Short answer: Don't do anything. Its already in Private Browsing mode.
EDIT: For handling cache check out this method:
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse
And make cashedResponse return nil.

iPhone - HTTPS connection to Server with Self-Signed Certificate [duplicate]

I have a cocoa class set up that I want to use to connect to a RESTful web service I'm building. I have decided to use HTTP Basic Authentication on my PHP backend like so…
<?php
if (!isset($_SERVER['PHP_AUTH_USER'])) {
header('WWW-Authenticate: Basic realm="My Realm"');
header('HTTP/1.0 401 Unauthorized');
//Stuff that users will see if they click 'Cancel'
exit;
}
else {
//Validation Code
echo "You entered info.";
}
?>
At this point I'm using a synchronous NSURLConnection, which I understand the Apple documentation states has less support for Authentication.
But is it even possible at all? I can do cookie authentication very easily sans NSURLProtectionSpaces or NSURLCredentials or any of the authentication classes. Also, are there any resources where I can read more about the Cocoa Authentication classes?
Thanks.
UPDATE: mikeabdullahuk
The code you supplied (the second example) is almost identical to what I had written. I have done some more investigating, and discovered that the NSURLConnection is returning an error…
Error Domain=NSURLErrorDomain Code=-1012 UserInfo=0x1a5170 "Operation could not be completed. (NSURLErrorDomain error -1012.)"
The code corresponds to NSURLErrorUserCancelledAuthentication. So apparently my code is not accessing the NSURLCredentialStorage and instead is canceling the authentication. Could this have anything to do with the PHP HTTP Authentication functions? I'm quite confused at this point.
A synchronous NSURLConnection will absolutely work with NSURLCredentialStorage. Here's how things usually work:
NSURLConnection requests the page from the server
The server replies with a 401 response
NSURLConnection looks to see what credentials it can glean from the URL
If the URL did not provide full credentials (username and password), NSURLConnection will also consult NSURLCredentialStorage to fill in the gaps
If full credentials have still not been determined, NSURLConnection will send the -connection:didReceiveAuthenticationChallenge: delegate method asking for credentials
If the NSURLConnection now finally has full credentials, it retries the original request including authorization data.
By using the synchronous connection method, you only lose out on step 5, the ability to provide custom authentication. So, you can either pre-provide authentication credentials in the URL, or place them in NSURLCredentialStorage before sending the request. e.g.
NSURLRequest *request =
[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://user:pass#example.com"]];
[NSURLConnection sendSynchronousRequest:request returningResponse:NULL error:NULL];
or:
NSURLCredential *credential = [NSURLCredential credentialWithUser:#"user"
password:#"pass"
persistence:NSURLCredentialPersistenceForSession];
NSURLProtectionSpace *protectionSpace = [[NSURLProtectionSpace alloc]
initWithHost:#"example.com"
port:0
protocol:#"http"
realm:nil
authenticationMethod:nil];
[[NSURLCredentialStorage sharedCredentialStorage] setDefaultCredential:credential
forProtectionSpace:protectionSpace];
[protectionSpace release];
NSURLRequest *request =
[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://example.com"]];
[NSURLConnection sendSynchronousRequest:request returningResponse:NULL error:NULL];
In a situation where a 401 or other authentication challenge is unacceptable/impossible, I sometimes use a dummy CFHTTPMessage to generate the authetication line, then copy that back into the NSURLRequest:
// assume NSString *username and *password exist and NSURLRequest *urlRequest
// exists and is fully configured except for HTTP Basic Authentication..
CFHTTPMessageRef dummyRequest =
CFHTTPMessageCreateRequest(
kCFAllocatorDefault,
CFSTR("GET"),
(CFURLRef)[urlRequest URL],
kCFHTTPVersion1_1);
CFHTTPMessageAddAuthentication(
dummyRequest,
nil,
(CFStringRef)username,
(CFStringRef)password,
kCFHTTPAuthenticationSchemeBasic,
FALSE);
authorizationString =
(NSString *)CFHTTPMessageCopyHeaderFieldValue(
dummyRequest,
CFSTR("Authorization"));
CFRelease(dummyRequest);
[urlRequest setValue:authorizationString forHTTPHeaderField:#"Authorization"];
This may seem completely a bizarre way to do it but it is tolerant of situations where the username/password aren't URL clean and where NSURLRequest refuses to consult the NSURLCredentialStorage because the server isn't actually sending a HTTP 401 (for example it sends a regular page instead).
I would note mikeabdullahuk's answer is good but also if you use NSURLCredentialPersistencePermanent instead of per session it will store the credentials in the users keychain so next time you can check NSURLCredentialStorage for a non nil value for the default credentials for a protection space and if you get a non nil value you can just pass the credentials in. I am using this method right now for a delicious.com client I am writing and it works very well in my tests.
Set your credential as the default credential for the protectionspace:
// Permananent, session, whatever.
NSURLCredential *credential = [NSURLCredential credentialWithUser:username password:password persistence: NSURLCredentialPersistencePermanent];
// Make sure that if the server you are accessing presents a realm, you set it here.
NSURLProtectionSpace *protectionSpace = [[NSURLProtectionSpace alloc] initWithHost:#"blah.com" port:0 protocol:#"http" realm:nil authenticationMethod:NSURLAuthenticationMethodHTTPBasic];
// Store it
[[NSURLCredentialStorage sharedCredentialStorage] setDefaultCredential:credential forProtectionSpace:protectionSpace];
At this point, any subsequent NSURLConnection that is challenged using a protection space that matches what you set will use this credential

Unable to POST data from IPhone using google account authentication

I'm working on an IPhone application that works with a Google App Engine application. I manage to get logged by using a google account and I get the authentication token. I'm also able to GET data from the GAE service (I did it after reading another question written here) but now I need to POST data so I need to send the authentication token in the header of the POST request. I tried several options but none of them worked.
Here is the code I use to put that auth into the header:
NSString* urlStr = [NSString stringWithFormat:#"%#%#", HOST, url];
NSMutableURLRequest* urlPost = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlStr]];
NSString* authStr = [NSString stringWithFormat:#"GoogleLogin auth=%#", token];
[urlPost addValue:authStr forHTTPHeaderField:#"Authorization"];
but it doesn't work.
Any help?
You need to use [request setHTTPMethod: #"POST"] and [request setHTTPBody: postdata] to properly configure the POST components. See the NSMutableURLRequest docs for more details.
Whenever I'm troubleshooting a problem related to HTTP, the first tool I'll grab is Charles HTTP Proxy. It will show you the entire request and response for closer examination.
If you're authenticating against an App Engine app, you need to obtain and send an authentication cookie, rather than using the GoogleLogin authentication. The source of appengine_rpc.py in the Python SDK demonstrates how.