CORS, Cordova, AngularJs $http and file:// confusion

Problem

I have an AngularJS/Cordova app which polls a JSON service on a remote server:

$http({method: 'GET', url: 'http://example.com/index.php'})

Developing in the browser and running off my intranet apache server (http://dev) I get "No 'Access-Control-Allow-Origin' header is present" so I fix this by adding:

Header set Access-Control-Allow-Origin "http://dev"

All works fine, and I see Origin:http://dev in my Chrome dev tools.

So, having to think about this for the first time, I wonder what the Origin will be when the app runs in the Android/iOS webviews. I decide to do a build and deploy on my devices and expect to see the same error in remote debugging (Safari for iOS and Weinre for Android), but to my surprise it works (without sending any CORS headers)! I also find that in both devices the app runs in the webview under the file:// scheme, rather than (what I assumed) a http server of some sorts provided by the phone OS.

So research seems to suggest that CORS is not required for file:// - such a "site' may access any XHR resource on any domain. But, when I test this on desktop browsers I find that while Safari does not need CORS for file:// but Chrome does, and FireFox works either way without CORS

So my questions:

1) why is my app working without CORS in Android/iOS - is it because CORS does not apply to file://, or, is Cordova doing something to make it work in the device?

I have <access origin="*"/> in my config

2) if, pending answers to Q1, I should want to be on the safe site and explicitly allow requests from apps, what value do you give Access-Control-Allow-Origin for file:// "hosts"? in my debugging there is no Origin header in the requests from file://

3) in addition to blocking the XHR request to the remote server, Chrome is also blocking my app templates (I'm using separate files), see below. Is this a potential issue with my app, or just a Chrome issue that I do not need to worry about?

XMLHttpRequest cannot load file:///Volumes/projects/phonegap/www/templates/tabs.html. Cross origin requests are only supported for HTTP. 
Problem courtesy of: KevInSol

Solution

There are two ways for CORS headers to signal that a cross-domain XHR should be allowed:

  • sending Access-Control-Allow-Origin: * (allow all hosts)
  • put the host you would like to allow into the Origin header by your backend

As for the file:// URLs they will produce a null Origin which can't be authorized via the second option (echo-back).

As mentioned:

Cross-domain policy does not apply to PhoneGap (for a variety of reasons, basically because your app is essentially running off the file:// URI on-device).

Please be aware that you will have to set up a whitelist for your apps to access these external domains.

As for the Chrome problem, which can be seen in the developer's console:

Failed to load resource: net::ERR_FILE_NOT_FOUND file:///C:/2.html XMLHttpRequest cannot load file:///C:/2.html. Received an invalid response. Origin 'null' is therefore not allowed access.

there was a discussion on Chromium project's issue tracker, #40787. They mark the issues as won't fix as that behaviour is happening by design.

There is a workaround proposed to simply switch off CORS in Chrome for development purposes, starting chrome with --allow-file-access-from-files --disable-web-security

e.g. for Windows

`C:\Users\YOUR_USER\AppData\Local\Google\Chrome\Application\chrome.exe --allow-file-access-from-files --disable-web-security`

Here is some more cordova related answer:

Check these resources for more info on CORS:

Check also Browser support for CORS:

And for the record formal CORS specification on W3C :)

Solution courtesy of: Blaise

Discussion

There is currently no discussion for this recipe.

This recipe can be found in it's original form on Stack Over Flow.