Using iframe with local files in Chrome
Asked Answered
A

3

37

I am having a tough time figuring out how to access a page loaded in an iframe from the outer page. Both pages are local files, and I'm using Chrome.

I have an outer page, and many inner pages. The outer page should always display the page title for the inner page (it makes sense in my application, perhaps less so in this stripped-down example). This works without any problem in AppJS, but I've been requested to make this app work directly in the browser. I'm getting the error "Blocked a frame with origin "null" from accessing a frame with origin "null". Protocols, domains, and ports must match.".

I think this is due to Chrome's same origin policy regarding local files, but that hasn't helped me fix the problem directly. I can work around the issue in this stripped-down example by using the window.postMessage method per Ways to circumvent the same-origin policy. However, going beyond this example, I also want to manipulate the DOM of the inner page from the outer page, since this will make my code much cleaner - so posting messages won't quite do the job.

Outer Page

<!DOCTYPE html>
<html>
    <head> 
        <meta name="viewport">
    </head> 
    <body>
        This text is in the outer page
        <iframe src="html/Home.html" seamless id="PageContent_Iframe"></iframe>
        <script src="./js/LoadNewPage.js"></script>
    </body>
</html>

Inner Page

<!DOCTYPE html>
<html>
    <head>
        <title id="Page_Title">Home</title> 
        <meta name="viewport">
    </head> 
    <body>
        This text is in the inner page
    </body>
</html>

JavaScript

var iFrameWindow = document.getElementById("PageContent_Iframe").contentWindow;
var pageTitleElement = iFrameWindow.$("#Page_Title");

Per Is it likely that future releases of Chrome support contentWindow/contentDocument when iFrame loads a local html file from local html file?, I tried launching Chrome with the flag

--allow-file-access-from-files

But there was no change in the results.

Per Disable same origin policy in Chrome, I tried launching Chrome with the flag

--disable-web-security

But again there was no change in the results.

Per What does document.domain = document.domain do?, I had both pages run the command

document.domain = document.domain;

This resulted in the error "Blocked a frame with origin "null" from accessing a frame with origin "null". The frame requesting access set "document.domain" to "", but the frame being accessed did not. Both must set "document.domain" to the same value to allow access."

For fun, I had both pages run the command

document.domain = "foo.com";

This resulted in the error "Uncaught Error: SecurityError: DOM Exception 18".

I'm floundering. Any help from more knowledgeable people would be fantastic! Thanks!

Ammoniac answered 30/7, 2013 at 15:2 Comment(0)
G
12

Per our discussion in my cube just a minute ago :)

I hit this same problem (Ajax post response from express js keeps throwing error) trying to get an AJAX post request to work correctly.

What got me around it is not running the file directly off the file system but instead running it from a local server. I used node to run express.js. You can install express with the following command: npm install -g express

Once that is accomplished, you can create an express project with the following command: express -s -e expressTestApp

Now, in that folder, you should see a file named app.js and a folder named public. Put the html files you wish to work with in the public folder. I replaced the file app.js with the following code:

var express = require('/usr/lib/node_modules/express');
var app = express();

app.use(function(err, req, res, next){
  console.error(err.stack);
  res.send(500, 'Something broke!');
});

app.use(express.bodyParser());
app.use(express.static('public'));

app.listen(5555, function() { console.log("Server is up and running");  });

Note, the require line may be different. You have to find where your system actually put express. You can do that with the following command: sudo find / -name express

Now, start the express web server with the following command: node app.js

At this time, the webserver is up and running. Go ahead and open a browswer and navigate to your ip address (or if you're on the same machine as your server, 127.0.0.1). Use the ip address:portnumber\filename.html where port number is the 5555 in the app.js file we created.

Now in that browser, you shouldn't (and didn't when we tested it) have any of these same problems anymore.

Godsend answered 1/8, 2013 at 14:8 Comment(4)
Note that if you have Python installed, you can apply the same approach you suggest here and set up a Web server one line: python -m SimpleHTTPServer [port]Lifelong
Wow, that is really nice. Hadn't seen that. I tested it on the same source code and it works, but slower than express. To be up and running that fast is pretty amazing and certainly a trade off to be considered.Godsend
With Python 3, use this instead: python -m http.server [port]Rebus
Another alternative is the Node package serve. Once you have it installed globally, you can just navigate with your terminal to that html directory and simply run the command serve (will default to port 3000) or serve -p [port].Chartier
Q
19

I'm sorry to say you that I've tried during weeks to solve this issue (I needed it for a project) and my conclusion is that it's not possible.

There are a lot of problems arround local access through javascript with chrome, and some of them can be solved using --allow-file-access-from-files and --disable-web-security, including some HTML5 offline features, but I definitely think there's no way to access local files.

I recomend you not to lose your time trying to circunvend this and to try to post messages wich you can interpret into the inner pages, so you can do the DOM modifications there.

Quackery answered 30/7, 2013 at 15:8 Comment(1)
Boy, that's too bad. Thanks very much for your response though!Ammoniac
G
12

Per our discussion in my cube just a minute ago :)

I hit this same problem (Ajax post response from express js keeps throwing error) trying to get an AJAX post request to work correctly.

What got me around it is not running the file directly off the file system but instead running it from a local server. I used node to run express.js. You can install express with the following command: npm install -g express

Once that is accomplished, you can create an express project with the following command: express -s -e expressTestApp

Now, in that folder, you should see a file named app.js and a folder named public. Put the html files you wish to work with in the public folder. I replaced the file app.js with the following code:

var express = require('/usr/lib/node_modules/express');
var app = express();

app.use(function(err, req, res, next){
  console.error(err.stack);
  res.send(500, 'Something broke!');
});

app.use(express.bodyParser());
app.use(express.static('public'));

app.listen(5555, function() { console.log("Server is up and running");  });

Note, the require line may be different. You have to find where your system actually put express. You can do that with the following command: sudo find / -name express

Now, start the express web server with the following command: node app.js

At this time, the webserver is up and running. Go ahead and open a browswer and navigate to your ip address (or if you're on the same machine as your server, 127.0.0.1). Use the ip address:portnumber\filename.html where port number is the 5555 in the app.js file we created.

Now in that browser, you shouldn't (and didn't when we tested it) have any of these same problems anymore.

Godsend answered 1/8, 2013 at 14:8 Comment(4)
Note that if you have Python installed, you can apply the same approach you suggest here and set up a Web server one line: python -m SimpleHTTPServer [port]Lifelong
Wow, that is really nice. Hadn't seen that. I tested it on the same source code and it works, but slower than express. To be up and running that fast is pretty amazing and certainly a trade off to be considered.Godsend
With Python 3, use this instead: python -m http.server [port]Rebus
Another alternative is the Node package serve. Once you have it installed globally, you can just navigate with your terminal to that html directory and simply run the command serve (will default to port 3000) or serve -p [port].Chartier
C
3

file:// protocol and http:// protocol make things to behave very differently in regards to iframes. I had the same issues you describe with an app on PhoneGap which uses file protocol to access all local files within the local assets/www folder.

If seems that modern browsers prevent the display of "local" files using the file protocol in iframes for security reasons.

We ended up dumping iframes and just using divs as "viewports". Fortunately the overall size of our app was not that big so we managed to load everything in a single page.

Culicid answered 4/12, 2013 at 15:42 Comment(5)
I'm kinda curious what those security reasons are. To be honest I do not see any reason this should be forbidden. If there is a specific case it would be great if Chrome could provide a sensible message, as I do expect protocol, domain and port to be the same for bunch of local files.Cornhusking
@JacekPrucia I'll take a crack: the reason is that if someone gives you an app that accesses local files, then if Chrome doesn't block it, it can go ahead and read/write your local files. (This is not obvious if you are working on your own app and just want to access your own filesystem, but it becomes more obvious if you distribute your app to others.)Drambuie
@martinjakubik Sure it can, but I still do not see a harm in that. Lets suppose your page is rooted at "C:\Projects\Test\Test.html". A malicious page can only write local files in that particular folder (same origin policy when applied to folders). Sure it can create malicious files -- apps that mask as innocent screen saver, however you still need user action for the damage to be done. If you just use the app I still do not see in what way it can damage local system.Cornhusking
@JacekPrucia I didn't know that... I thought that it could still exit the folder and overwrite (or read) other files.Drambuie
@martinjakubik well... technically it can do that. However since they do limit http protocol access to "same origin policy", they can also limit file protocol pretty much the same way. For some reason, they haven't bothered to come up with a scenario and just disabled the whole thing, forcing me to use local web server...Cornhusking

© 2022 - 2024 — McMap. All rights reserved.