iOS stream audio from authenticated URL - iphone

I want to stream audio file from a source that needs OAuth2 authentication, this is my code, but it is not working.
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];
[req setValue:[NSString stringWithFormat:#"Bearer %#", accessToken] forHTTPHeaderField:#"Authorization"];
player = [AVPlayer playerWithURL:req.URL];
[player play];
Can you please help?

The issue is that you're adding your authentication token as an HTTP header, but then making a request using only the URL (and headers are not included in the URL).
I need to do a similar thing in my app, but it doesn't look like it's possible to interfere with AVPlayer's network request (at least, not with a public API). So now I'm looking at either requesting the file myself using NSURLSession (which means no streaming - gotta wait for the whole file, or else do some complicated processing to hand it off to an audio player in chunks), or else fudge the web service to accept my parameter as a query parameter instead of as an HTTP header.
This question also has some potential work-arounds: Send headers with AVPlayer request in iOS

Related

iOS NSURLConnection object always returns same response

I'm creating an iPhone app that consumes a json webservice. I have an NSURLRequest and NSURLConnection object that are used to load JSON data from that webservice:
NSMutableURLRequest *request = [[NSMutableURLRequest alloc]
initWithURL:url
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:30];
[request setHTTPMethod: #"POST"];
//[request setHTTPShouldHandleCookies:YES];
//create connection
NSURLConnection *connection = [[NSURLConnection alloc]
initWithRequest:request delegate:self];
[connection start];
First time I executed the above code, using as the url "admin.mydomain.com/param1/value1/param2/value2", the response came through correctly (a JSON string: {"Wrong API Key"}).
I then changed the url to my staging server: "admin.stg.mydomain.com/param1/value1/param2/value2". This server provides me with some completely different output (when I try that new url in a browser, the correct output is shown, a json object completely different from what the first url gives me), but in my iphone app I still get the exact same response I got from the other server. If I try non existent urls I do get a correct error message.
It just seems to have cached the result from the original server and returns the same value for my stg subdomain, somehow matching the two urls (is this possible?), but I have cleared all caching data I could find. I have tried to clean the build and build directory, restarted xcode, the computer and everything, the cache policy is set to ignore the cache (see code). Important: I get the same behavior on my actual iPhone, not just the simulator.
Does anyone have any idea what could cause this kind of behavior? Am I forgetting something obvious?
I have been looking at this for hours on end now, any help is greatly appreciated!
I have changed the request method to 'GET', now I get the expected results! When checking the url in the browser a get request is used, when posting it I get a different response, which happens to be exactly the same as what I get on the dev server. Problem solved, just have to make some adjustments to the backend to allow a post request!

Using a custom NSURLProtocol with UIWebView and POST requests

In my iOS app, I'm using a UIWebView and a custom protocol (with my own NSURLProtocol implementation). I've been fairly careful about making sure that whenever I load a url, I load something like this into my UIWebView:
myprotocol://myserver/mypath
and in my NSURLProtocol implementation, I take a mutable copy of the NSURLRequest, convert the URL to http: and send that to my server.
Everything works for HTTP GET requests. The problem I encounter is with POST requests. It seems like the UIWebView doesn't properly encode the form data in the HTTPBody if the request uses my custom protocol.
One work-around, since I'm using HTTPS for my server requests, is that I register my protocol handler to intercept http: instead of myprotocol: and I can convert all calls to https: This other question, here, pointed me toward that solution:
But I'm wondering if there's any alternative and/or better way of accomplishing what I want.
Instead of trying to use POST requests, one work around is to continue using GET requests for myprotocol:// URLs, but transform them in your NSURLProtocol implementation to an http:// and POST request to your server using the request query string as the body of the POST.
The worry with using GET requests to send large amounts of data is that somewhere along the request chain, the request line might get truncated. This appears to not be a problem, however, with locally-implemented protocols.
I wrote a short Cordova test app to experiment and I found that I was able to send through a little over 1 MiB of data without trouble to the HTTP request echoing service http://http-echo.jgate.de/
Here is my startLoading implementation:
- (void)startLoading {
NSURL *url = [[self request] URL];
NSString *query = [url query];
// Create a copy of `url` without the query string.
url = [[[NSURL alloc] initWithScheme:#"http" host:#"http-echo.jgate.de" path:[url path]] autorelease];
NSMutableURLRequest *newRequest = [NSMutableURLRequest requestWithURL:url];
[newRequest setHTTPMethod:#"POST"];
[newRequest setAllHTTPHeaderFields:[[self request] allHTTPHeaderFields]];
[newRequest addValue:#"close" forHTTPHeaderField:#"Connection"];
[newRequest addValue:#"application/x-www-form-urlencoded;charset=UTF-8" forHTTPHeaderField:#"Content-Type"];
[newRequest setHTTPBody:[query dataUsingEncoding:NSUTF8StringEncoding]];
urlConnection = [[NSURLConnection alloc] initWithRequest:newRequest delegate:self];
if (urlConnection) {
receivedData = [[NSMutableData data] retain];
}
}
I then implemented the NSURLConnection protocol methods to forward to the appropriate NSURLProtocolClient method, but building up the response data in the case of Transfer-Encoding:chunked (as is the case for responses from http://http-echo.jgate.de/).
Unfortunately it looks like that http: and https: scheme requests are handled slightly differently than other (including custom) schemes by Foundation Framework. Obviously HTTPBody and HTTPBodyStream calls on relevant NSURLRequest returns always nil for former ones. This is decided already prior call of [NSURLProtocol canInitWithRequest] therefore custom NSURLProtocol implementation has no way of influencing that (it is too late).
It seems that different NSURLRequest class is used for http: and https: than 'a default one'. Default GnuStep implementation of this class returns always nil from HTTPBody and HTTPBodyStream calls. Therefore particular implementations (e.g. one under PhoneGap, likely part of Foundation Framework) choose NSURLRequest-type of class based on scheme prior consulting that with NSURLProtocol. For custom schemes, you get NSURLRequest that returns nil for both HTTPBody and HTTPBodyStream which effectively disables use of POST method (and other methods with body) in custom URI scheme handler.
Maybe there is a way how to influence decision of which NSURLRequest class is actually used but it is currently unknown to me.
As a workaround, you can still use http: or https: scheme and decide in [NSURLProtocol canInitWithRequest] based on other criteria (e.g. host name).

what is the difference between post and get request for asihttprequest?

I am wondering what the difference between Get and Post with asihttprequest library..
Is this a GET?
- (IBAction)sendHttpsRequest
{
//Set request address
NSMutableString *databaseURL = [[NSMutableString alloc] initWithString:#"https://142.198.16.35"];
//call ASIHTTP delegates (Used to connect to database)
NSURL *url = [NSURL URLWithString:databaseURL];
//This sets up all other request
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setDelegate:self];
[request startAsynchronous];
}
is a post when you try to set elements say within a php document? any examples would be awesome!
http://www.cs.tut.fi/~jkorpela/forms/methods.html
An HTTP GET is a request from the client to the server, asking for a resource.
An HTTP POST is an upload of data (form information, image data, whatever) from the client to the server.
What you have there is an HTTP POST.
-EDIT:
Per http://allseeing-i.com/ASIHTTPRequest/:
ASIFormDataRequest
A subclass of ASIHTTPRequest that handles x-www-form-urlencoded and multipart/form-data posts. It makes POSTing data and files easy, but you do not need to add this to your project if you want to manage POST data yourself or don’t need to POST data at all.
My bad, this one was a POST, not a GET. The rest of my answer was valid, though :)
That is a POST request, which is the default for ASIFormDataRequest. The difference is the same as it would be in a normal HTTP request. You can read about that here if you don't already know.
In general, if you are just downloading a web page and do not need to send any variables to the server, a GET request is sufficient. If you want to send variables in your request, often times a POST request is the way to go since it is a bit more secure and less transparent.

MPMoviePlayerController referer

We host a website with some videos, and we're aiming to restrict these videos so only an specific referer can access to them. We were using secdownload, but seems to be a pain with HTTP Live Streaming.
In our iPhone APP, we're trying to customize the HTTP Header fields by setting our custom referer or user-agent and be able to play this videos.
We customize it this way
NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:self.UrlString]];
[theRequest setValue: customreferer forHTTPHeaderField:#"Referer"];
If we start a connection (NSConnection) everything is fine, but the problem comes when using with MPMoviePlayerController, because it seems that there is no way to customize its http requests.
You can specify an NSURL in MPMoviePlayerController, but doesn't seem to allow you to edit the request.
Am I missing something? If so, how do we achieve this? We're outputting the log from apache and all the HTTP requests made by the movieplayer have an empty referer.
That is correct. To use a MPMoviePlayerController with a different URL, you should release the original and alloc/initWithContentURL: a new one. You could consider adding a parameter to the URL, or customise the URL in some other way, to identify the referrer.
But I am aware of no way of getting at the NSURLRequest.

iOS: How to make a secure HTTPS connection to pass credentials?

I am creating my first iPad app. I have a web application that I would like to authenticate against and pull data from in a RESTful way.
If you open up the URL in the browser (https://myapp.com/auth/login), you will get a form to enter your username and password. I was thinking I could set the login credentials in the post data of the request and submit the data.
The site uses HTTPS for login so that credentials aren't passed in plain text over the internet.
How can I make a secure HTTPS connection to pass credentials? Will this remember that I am logged in for future requests? What is the best way to do this?
Further update, October 2013
Although at the time I wrote this answer, ASIHTTPRequest was maintained a widely supported, this is no longer the case. It is not recommended for new projects - instead use NSURLConnection directly, or use AFNetworking.
With AFNetworking, there is a [httpClient setAuthorizationHeaderWithUsername:username password:password]; method for http authentication, and create a POST style form is equally easy - see AFNetworking Post Request for that.
Original answer:
A lot of people use the ASIHTTPRequest class to deal with http & https on the iPhone/iPad, as it has a lot of useful features that are difficult or time consuming to achieve with the built in classes:
http://allseeing-i.com/ASIHTTPRequest/
Starting at the simplest level you'd start with something like:
NSURL *url = [NSURL URLWithString:#"http://allseeing-i.com"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request startSynchronous];
NSError *error = [request error];
if (!error) {
NSString *response = [request responseString];
NSLog(#"response = %#", response);
}
If you're using HTTP authentication, ASIHTTPRequest will automatically prompt the user for the username and password.
IF you're using some other form of authentication you probably need to request the username and password from the user yourself, and submit them as a POST value or a custom http header, and then the response may either include a token in a JSON or XML response, or it could set a cookie.
If you add more details as to how the authentication scheme works I can be a bit more specific.
Update
Based on the update, to emulate a POST form you'd just need to add lines like:
[request addPostValue:usernameString forKey:#"username"];
[request addPostValue:passwordString forKey:#"password"];
You will also need to change the way you create the request, instead of:
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
do:
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
(I also forget to mention it above, there's code I put earlier is using a synchronous request, so you'd want to replace it with an asynchronous one to avoid blocking the UI once you'd proved it was working.)
There's a JSON framework for the iphone here:
http://code.google.com/p/json-framework/
which works well for me and is simple to use with ASIHTTPRequest.