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!
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.
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.
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.
Related
Playing around with this javascript library
https://www.w3.org/TR/webmidi/#introduction I got some basic functionality working and I was happily able to send midi notes to my syntheseizer and hear it working!..
However, when I wanted to try out the exact same javascript code, but hosted remotely, I got this error:
Uncaught TypeError: window.navigator.requestMIDIAccess is not a function
My code can be boiled down to following:
<html>
<body>
<h1 id="test-result">MIDI test</h1>
<script>
window.onload = function(){
window.navigator.requestMIDIAccess().then(
x => document.getElementById("test-result").innerHTML = "success!",
x => document.getElementById("test-result").innerHTML = "fail!"
);
};
</script>
</body>
</html>
Why does it work locally but not remote?
I am using google-chrome and it is my impression that webmidi should be supported, although experimental https://developer.mozilla.org/en-US/docs/Web/API/MIDIAccess
navigator.requestMIDIAccess() is only available in a secure context, which means your remote host must serve your resources via HTTPS.
Resources served from localhost are considered to be in a secure context, whether delivered via HTTPS or HTTP.
Connect to your remote host using HTTPS instead of HTTP and that should resolve the problem.
I have a Worker.js file and a Subworker.js file in my Scripts folder. No problem creating a worker, I can step through its code in the debugger; but when I want that worker to spawn a subworker, it isn't getting created, and I'm unable to step through the subworker code file in the debugger.
In myPage.htm script block:
var worker = new Worker("Scripts/Worker.js"); // Succeeds
In Worker.js script file:
var subworker = new Worker("Subworker.js"); //without the folder name FAILS
The IE10 developer tools Network console shows this:
URL....................Method...Result..Type.......................Received.......Taken......Initiator
/Scripts/Worker.js.....GET......200.....application/x-javascript...1.00KB..........<1ms......webworker
/Scripts/Subworker.js..GET......404.....text/html..................2.50KB..........239.29s...webworker
EDIT: Found the answer to the 404 error although still unable to instantiate the subworker:
var subworker = new Worker("..Subworker.js");
EDIT2: Also found that the following trick to cause the current version of a script to be used generates a 400 error:
var subworker = new Worker("..Subworker.js?version=2.0");
I'm in about the same boat.
My plan is to load a subworker from another doamin or file:// protocol because you cannot load one directly from a regular js script. I still need to test this, but I know that Workers/SharedWorkers are not subject to the normal Cross-Origin Restriction Policy, except** for when you're trying to load one (and hopefully only when doing this from a window script).
Another method is to use window.postMessage to forward messages to a Worker that it has created in the other window.
Alternatively, for my specific needs I am considering running a headless browser locally, a CDN, or a localhost "forever-server" with CORS enabled -- but this most likely still requires a window.postMessage().
Hope this helps, Tim!
Post back if you find an answer, eh?
I've been experimenting with the Valence javaScript client library and the 'GettingStartedSample' download from D2L.
If the sample files are uploaded, accessed and ran from within a D2L course site the script works, however, if I try to run it from a localhost I run into a problem. On localhost I can successfully authenticate the application however when I try to run a 'Get Versions' or 'WhoAmI' request nothing happens.
Firebug tells me the following:
Object { readyState=0, status=0, statusText="error" } server.js (line 77)
error server.js (line 78)
(an empty string) (line 79)
Should I be able to make a request using the javascript client library from a localhost?
The short answer is yes, but you need to do some additional work.
I would advise reading up on the same origin policy so you have some background as to why XHRs (in your case, Valence calls) between domains do not work out of the box. The easiest thing to do is to use jsonp if all you are making are GET requests. If you need to make other requests, you will need to look into getting CORS support set up on your instance.
Have some Javascript that I need to work via the following:
://localhost
://servername
:/www.domainnamefortheserver.com
When I run the script from http://servername with an IFRAME referencing the domain - it does not load.
Is there a way to get the Javascript security model to recognize the server name, localhost and the domain as the same "domain"?
Thanks
If you are running on UNIX you can edit /etc/hosts to give a fake DNS entry for your server.
eg.
127.0.0.1 localhost www.domainnamefortheserver.com
Then you can always connect to it as the correct name even when it's not on the live site yet. Don't try and break the javascript security directly.
This will also work on OSX. Windows works differently, I expect.
If you are using a server-side language to generate the page, you may be able to set the security domain like so:
document.domain = $CURRENT_HOSTNAME;
So the security domain will be the domain the user requested. This is a shot in the dark, but I hope it helps nonetheless.
Use root relative URIs:
href="/foo/bar"
rather than absolute URIs:
href="http://example.com/foo/bar"
That way the document will be loaded from the same hostname.
What do you mean by
my references are to the domain name
?
If you load scripts in your page on http://servername (using <script src=''>), they will have access to everything on http://servername, even if they come from another domain.
However, if you try to make AJAX calls to the other domain, then you have a problem. You can use the trick explained by Christopher, ie making aliases to the domain.
I have:
A web server (server 1)
An application server running some beast of a legacy web app (server 2)
An iframe on server 1 pulling in the application from server 2
My problem is:
The legacy app uses JS validation on its forms. When a user attempts to submit an incomplete form, an alert pops up to notify the user that they are a dummy. Of course, this fails when the app is run inside of an iframe because server 1 and server 2 live at different domains.
I tried setting the following proxy directives on server 1:
ProxyPass /legacy_app http://server2.url/legacy_app
ProxyPassReverse /legacy_app http://server2.url/legacy_app
I'm now able to serve the iframe from http://server1.url/legacy_app, but I'm still unable to execute javascript inside that iframe -- I get the same security/access errors as I did when the app was running on a different domain.
Is there something else I can try?
How is the legacy app checking if the boxes are filled in? Simple javascript? Ajax?
The alert box itself should still work. I'm thinking the code for determining if the alert should be issued might be what's broken.
Running the following code on my local apache server still gives me the alert onLoad even though the page is on a remote host:
<html>
<body>
<div>
<iframe src="http://www.crowderassoc.com/javascript/alertbox.html" width="300" height="200">
</div>
</body>
</html>
Try copying the above code to a page on server #1 and see if you get the alert box from that remote site in the iframe.
Have you tried hosting the script inside of a .js file hosted on server #1 but running out of the iframe (referenced out of server #2)?
I think a browser is okay with referencing an external site, but doesn't like it when it is referenced by an external site.
Haven't tried it myself, but I believe that's how I've heard of this sort of a problem being worked around. I know this is the method that Google Analytics uses - you have to request the .js file from Google's servers, but once it's there, it has access to the browser.
Joe, I think you are correct. A quick test with other servers shows that I can trigger alerts from remotely-hosted scripts quite easily.
The legacy server is the client's and we don't have easy access to it, but glancing at their JS it looks like they're doing some sort of cross-site/framing detection -- worth further investigation.
I've had this situation in the past where I was trying to build an app around a heavily scripted pre-existing app on a remote server, and the app would run fine if it was opened in its own window, but if I tried loading it into a frame, it would break.
What I ended up doing for this project was opening the local application in a pop-up with a width of 495px, loading the external app in the main (already existing) window, resizing the main external app window to the screen width minus 495px, and positioning the windows side by side on the screen. This gave the end user a similar effect to what I had been trying to do with frames, only it worked.
In case it helps, here is the code I used from my index.php file:
// Manipulating the current window
window.location.href = 'http://www.someExternalApp.com'; // setting the page location.
window.name = 'legacyapp'; // setting the window name just the for heck of it.
moveTo(0,0); // moving it to the top left.
// Resizing the current window to what I want.
mainWindowWidth = screen.width - 495;
mainWindowHeight = screen.height; // Makes the window equal to the height of the users screen.
resizeTo(mainWindowWidth,mainWindowHeight);
// function for opening pop-up
function openWin(){
win2 = window.open(page,'',winoptions);
win2.focus();
}
// internal app location (for use in pop-up)
page = 'someLocalApp.php';
// internal app Window Options (for pop-up)
winoptions = 'width=490,height='+mainWindowHeight+',top=0,left='+mainWindowWidth+'leftscrollbars=1,scrolling=1,scrollbars=1,resizable=1,toolbar=0,location=0,menubar=0,status=0,directories=0';
// Opens the local app pop-up
openWin();