I've been trying to break this up for a few hours now but with no success... I am pretty desperate now :(
I am doing penetration testing for a company and I need to bypass this frame killer JS:
<script type="text/javascript">/* <![CDATA[ */
if (top != self) {
try {
if (parent != top) {
throw 1;
}
var disallowed = ['XXXXXXX.com'];
var href = top.location.href.toLowerCase();
for (var i = 0; i < disallowed.length; i++) {
if (href.indexOf(disallowed[i]) >= 0) {
throw 1;
}
}
} catch (e) {
try {
window.document.getElementsByTagName('head')[0].innerHTML = '';
} catch (e) { /* IE */
var htmlEl = document.getElementsByTagName('html')[0];
htmlEl.removeChild(document.getElementsByTagName('head')[0]);
var el = document.createElement('head');
htmlEl.appendChild(el);
}
window.document.body.innerHTML = '<img src="http://www.XXXXXXX.com/img/XXXXXX.gif" style="border:0px;" /><br />Go to XXXXXXX.com';
}
}
/* ]]> */</script>
Thank you very much!
Use one of the following:
IP Address instead of domain name to bypass the disallowed list
X-Frame-Options
HTML5 sandbox
If the body element's node document's browsing context is a nested browsing context, and the browsing context container of that nested browsing context is a frame or iframe element, then the container frame element of the body element is that frame or iframe element. Otherwise, there is no container frame element.
The above requirements imply that a page can change the margins of another page (including one from another origin) using, for example, an iframe. This is potentially a security risk, as it might in some cases allow an attack to contrive a situation in which a page is rendered not as the author intended, possibly for the purposes of phishing or otherwise misleading the user.
References
HTML5 Specification, Section 10: Rendering
Related
im trying to download a file that constructs itself based on the value it recives. This is my code
<html>
<head>
<script>
var myList=[];
window.onmessage = function(event){
if (event.data) {
myList = event.data;
if (myList.length>0) {
buildHtmlTable();
}
}
else {
myList = [];
}
};
function buildHtmlTable() {
var columns = addAllColumnHeaders(myList);
for (var i = 0 ; i < myList.length ; i++) {
var row$ = $('<tr/>');
for (var colIndex = 0 ; colIndex < columns.length ; colIndex++) {
var cellValue = myList[i][columns[colIndex]];
if (cellValue == null) { cellValue = ""; }
row$.append($('<td/>').html(cellValue));
}
$("#excelDataTable").append(row$);
}
return exportF(); // Make Excel file download now
}
function addAllColumnHeaders(myList)
{
var columnSet = [];
var headerTr$ = $('<tr/>');
for (var i = 0 ; i < myList.length ; i++) {
var rowHash =`enter code here` myList[i];
for (var key in rowHash) {
if ($.inArray(key, columnSet) == -1){
columnSet.push(key);
headerTr$.append($('<th/>').html(key));
}
}
}
$("#excelDataTable").append(headerTr$);
return columnSet;
}
function exportF() {
var table = document.getElementById("excelDataTable");
var html = table.outerHTML;
var url = 'data:application/vnd.ms-excel,' + escape(html);
var link = document.getElementById("downloadLink");
link.setAttribute("href", url);
link.setAttribute("download", "export.xls"); // Choose the file name here
link.click(); // Download your excel file
return false;
}
</script>
</head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body onLoad="">
<table id="excelDataTable" border="1">
</table>
<a style="display: none" id="downloadLink"></a>
</body>
</html>
The code itself works, but the error i get is "Download is disallowed. The frame initiating or instantiating the download is sandboxed, but the flag ‘allow-downloads’ is not set. See https://www.chromestatus.com/feature/5706745674465280 for more details."
What can i do to work around this? It feels like ive tried everything i can get my hands on but nothing seems to work for it to download
As the warning message says, you can't initialize downloads from a sandboxed iframe if it doesn't have the allow-downloads permission.
All solutions will imply having access to the page where the iframe is displayed (hereafter "the embedder").
The easiest and recommended way,
is to ask the embedder to add this permission when they define their iframe:
<iframe src="yourpage.html" sandbox="allow-scripts allow-downloads"></iframe>
An other way would be to ask them to not sandbox that iframe at all,
<iframe src="yourpage.html"></iframe>
but I guess that if they did, it's because they don't trust your page enough.
Finally a more complex way would be to pass the generated file back to the parent window.
For this you'd need to define a new API with your clients.
You could obviously just emit a global message event back to them, but I guess the cleanest is to make them pass a MessageChannel's MessagePort along with the myList data, so they can wait for the response there easily and be sure they'll only catch the response and no other unrelated message.
So in the embedder page they'd do
frame.onload = (evt) => {
const channel = new MessageChannel();
// handle the response from the iframe
channel.port2.onmessage = (evt) => {
const file = evt.data;
saveAs( file, "file.html" ); // the embedder is reponsible to initialize the download
};
frame.contentWindow.postMessage( embedders_data, [ channel.port1 ] );
};
And in your page you'd do
window.onmessage = (evt) => {
const myList = evt.data;
// get the MessageChannel's port out of the transfer-list
const port = evt.ports[ 0 ];
// buildHtmlTable has to return the final file, not to make it download
const file = buildHtmlTable( myList );
if( port ) {
port.postMessage( file ); // send back to embedder
}
};
See it as a live plnkr.
Ps: note that your files are not xlsx files but HTML markup.
The correct answer
Under normal circumstances Kaiido's answer is indeed the correct solution to your problem. They will NOT work in your case though.
The answer that will work on WixSince you are using Wix there is no way for you to directly edit the Sandbox attribute of the iframe element. This is just how Wix does things. You can, however, use custom code (only applies to premium websites) to get the class name of the iframe and programatically use javascript to set the new attribute to the existing iframe.
You must use the web inspector to find out the class name (iframes in Wix do not have ids) then add "allow-downloads" to the sandbox attribute. You might then need to reload the iframe using js as well. Go to your website's settings -> Custom Code -> Create custom code at the end of the body tag
If you do not have a premium website then you unfortunately cannot do this. This is due to Wix's own limitations as a platform. If this is an absolute "must" for you project, I recommend you to not use Wix since they limit your freedom as a developer when it comes to working with
technologies that were not made by them. Not to mention that they lock features such as custom elements behind a pay wall. So we can't even test our ideas before committing to a hosting plan. For anyone reading this in the future, take this into consideration and look into other platforms.
Thanks for answers, i didnt find a sollution with the recomended answers. What i did is that i made a completely new page, instead of initializing a html iframe i redirected the current window to the new page i created. The new page took a variable from "www.page.com/?page={value} and downloaded what i needed from there instead. Its messy but it works so if anyone else has this problem i recomend this if you are using wix.
I need to use a content of a .txt file on a web page. The problem is that I can't do it easy way (server-side php). I figured out the trick of opening a text file in the iframe and then asking for innerHTML/innerText. It turns out that people were there before - found the following code, much cleaner than my attempts, at https://zipcon.net/~swhite/docs/computers/browsers/extern_via_iframe.html
It works locally under FireFox and IE, but does not under Chrome. How to make it work under Chrome?
function getIframeContentText( frameID )
{
var elt = document.getElementById(frameID);
//alert( "getIframeContentText:" + elt );
//alert( "getIframeContentText Content:" + elt.contentDocument );
if( elt.contentDocument ) // DOM
{
var iframe_doc = elt.contentDocument;
var range = iframe_doc.createRange();
range.selectNodeContents( iframe_doc.body );
return range.toString();
}
else // IE6
{
var iframe_doc = document.all[frameID].contentWindow.document;
//return iframe_doc.body.innerHTML; // gets HTML
return iframe_doc.body.outerText;
}
}
This is because handling iFrames in ie and firefox is differentthan chrome ,because of chromes same-origin policy
start the browser using chrome.exe --user-data-dir="." --disable-web-security
and you have to wait for the document to load fully ie all the contents of the page ,it may happen there may be iFrame inside iFrame (for generic solution )
$(window).load(function()
{
chromeFrameInitializers(document);//for handling frames and IFrames
});
function chromeFrameInitializers(document)
{
var frame=document.getElementsByTagName("frame");
for(var i=0;i<frame.length;i++)
{
var subDocFrame=frame[i].contentDocument;
//do your stuf
chromeFrameInitializers(subDocFrame)
}
var iFrame=document.getElementsByTagName("iFrame");
for(var i=0;i<iFrame.length;i++)
{
var subDocIFrame=iFrame[i].contentDocument;
//do your stuf
chromeFrameInitializers(subDocIFrame)
}
}
`
it handles for both frame and iFrame (recursively ). for this $(window).load jquery needed
I know that (a handful of) non-JavaScript users are out there and I'd like to cater for them instead of giving them poorer experience just because of their preference (be that for privacy reasons or whatever).
Most lazy-loading JS libraries seem to address this in the same fashion, for example see lazysizes:
<style>
.no-js img.lazyload {
display: none;
}
</style>
<noscript>
<img src="image.jpg" />
</noscript>
<img src="grey.jpg" data-src="image.jpg" class="lazyload" />
Mainly out of curiosity, I got to wondering if it would be possible to pull the fallback out of the <noscript> tag and add it to the DOM programmatically with JavaScript so that the image source didn't have to be duplicated in two image tags which would leave me with just:
<noscript>
<img src="image.jpg" class="lazyload" width="600" height="400"/>
</noscript>
Here's what I've knocked together:
(function(attribute) {
Array.prototype.forEach.call(document.getElementsByTagName("noscript"), function(node) {
var parser = new DOMParser,
el = parser.parseFromString(node.textContent, "text/xml").documentElement, // XML => <img/> required
img = ("img" == el.tagName) ? el : el.getElementsByTagName("img")[0]; // allow for <img/> in <picture>
img.setAttribute(attribute, img.getAttribute("src"));
img.setAttribute("src", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC");
node.insertAdjacentHTML("beforebegin", el.outerHTML);
});
})("data-src"); // different libraries use different data attribute names
This appears to work everywhere (Chrome, Safari, Opera, Firefox) except Internet Explorer (naturally). I know that .textContent isn't available pre-IE9 but IE9+ all seem to be failing at the final hurdle - the .outerHTML. Am I doomed to failure and having to repeat myself in my markup?
Update: To clarify, I'd ideally like to be able to use arbitrary attributes (alt, title, etc.) in the image tag or even use responsive markup:
<noscript>
<picture>
<source ... />
<source ... />
<img src="image.jpg" />
</picture>
</noscript>
I'm the creator of lazySizes. This approach has multiple porblems:
A noscript element is never renderend, which means it is not detectable, wether it is visible or not (or better said it is always invisible)
You can't use statefull classes lazyloading and lazyload to give feedback to the user
You can't pre-occupy the space for your lazy embed content (which is important for both a) user experience (no content jumping) and b) performance (no reflow)
(It has problems in older browsers)
The data-sizes="auto" feature can't be used
However if 4. and 5. isn't a problem for you, it is possible to use a noscript child element in conjunction with a lazyload parent to achieve this.
The markup could look something like this:
<div class="lazyload" data-noscript="">
<noscript>
<p>any kind of content you want to be unveiled</p>
</noscript>
</div>
And the lazySizes plugin code would look something like this:
(function(){
'use strict';
var supportPicture = !!window.HTMLPictureElement;
addEventListener('lazybeforeunveil', function(e){
if(e.defaultPrevented || e.target.getAttribute('data-noscript') == null){return;}
var imgs, i;
var noScript = e.target.getElementsByTagName('noscript')[0] || {};
var content = noScript.textContent || noScript.innerText || '';
e.target.innerHTML = content;
if(supportPicture){return;}
imgs = e.target.querySelectorAll('img[srcset], picture > img');
for(i = 0; i < imgs.length; i++){
lazySizes.uP(imgs[i]);
}
});
})();
In case you like this, I might make an official plugin for this. Here is the plugin: https://github.com/aFarkas/lazysizes/tree/master/plugins/noscript
Here's how I'd do it, using methods that should be available in all browsers
(function(attribute) {
Array.prototype.forEach.call(document.getElementsByTagName("noscript"), function(node) {
var content = node.childNodes[0].nodeValue,
parser = new DOMParser(),
doc = parser.parseFromString(content, "text/html"),
images = doc.getElementsByTagName('img');
for (var i=images.length; i--;) {
var img = document.createElement('img');
img.src = 'data:image/png;base64,iVBOR ....';
img.height = images[i].getAttribute('height');
img.width = images[i].getAttribute('width');
img.setAttribute(attribute, images[i].getAttribute('src'));
node.parentNode.insertBefore(img, node.nextSibling);
}
});
})("data-src");
Here's the trick I use:
(function() {
"use strict";
var config = {
// If the image gets within 50px in the Y axis, start the download.
rootMargin: "50px 0px",
threshold: 0.01
};
var observer;
//If we're using a browser without the IntersectionObserver (IE11, Safari 11), skip the lazy part and just load the resources
if ("IntersectionObserver" in window) {observer = new IntersectionObserver(onIntersection, config);}
//If we're using a browser without requestAnimationFrame (IE9, Opera Mini), just run the passed function
var rAF;
if ("requestAnimationFrame" in window) rAF = window.requestAnimationFrame;
else rAF = function(func) { func(); };
var tempImg = "data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==";
/**
* Temporarily replace a expensive resource load with a cheap one
*/
function storeSourceForLater(lazyItem, tempData) {
//Store our ACTUAL source for later
lazyItem.setAttribute("data-lazy-src", lazyItem.getAttribute("src"));
//Set the item to point to a temporary replacement (like a data URI)
lazyItem.setAttribute("src", tempData);
//Now observe the item so that we can start loading when it gets close to the viewport
observer.observe(lazyItem);
}
/**
* Temporarily prevent expensive resource loading by inserting a <source> tag pointing to a cheap one (like a data URI)
*/
function jamSourceLoading(lazyItem, tempData) {
var newSource = document.createElement("source");
newSource.setAttribute("srcset", tempData);
newSource.setAttribute("data-lazy-remove", "true");
//adding this source tag at the start of the picture tag means the browser will load it first
lazyItem.insertBefore(newSource, lazyItem.firstChild);
var baseImage = lazyItem.getElementsByTagName("img")[0];
if (baseImage) {
//this is a picture tag, so we need to watch the image (as the picture tag is smaller than the image usually)
observer.observe(baseImage);
}
}
/**
* Set up the lazy items so that they won't try to load when we add them to the document, but will once the user is close to seeing them
*/
function prepareLazyContents(lazyArea) {
var lazyImgs = lazyArea.getElementsByTagName("img");
for(var i = lazyImgs.length; i--;){
storeSourceForLater(lazyImgs[i], tempImg);
}
var lazyPictures = lazyArea.getElementsByTagName("picture");
for(var i3 = lazyPictures.length; i3--;) {
jamSourceLoading(lazyPictures[i3], tempImg);
}
}
/**
* Put the source back where we found it - now that the element is attached to the document, it will load now
*/
function restoreSource(lazyItem) {
lazyItem.setAttribute("src", lazyItem.getAttribute("data-lazy-src"));
lazyItem.removeAttribute("data-lazy-src");
}
/**
* Remove the source tag preventing the loading of picture/audio/video
*/
function removeJammingSource(lazyItem) {
var jammingSource = lazyItem.querySelector("source[data-lazy-remove]");
if (jammingSource) lazyItem.removeChild(jammingSource);
}
/**
* Handle the intersection postback
*/
function onIntersection(entries, obsvr) {
entries.forEach(function(entry) {
if(entry.intersectionRatio === 0) return;
//if the item is now visible, load it and stop watching it
var lazyItem = entry.target;
obsvr.unobserve(lazyItem);
//Just in case the img is the decendent of a picture element, check for source tags
removeJammingSource(lazyItem.parentNode);
restoreSource(lazyItem);
});
}
/**
* Retrieve the elements from the 'lazy load' no script tags and prepare them for display
*/
function setUp() {
//Get all the noscript tags on the page
var lazyLoadAreas = document.getElementsByTagName("noscript");
for(var i = lazyLoadAreas.length; i--;) {
var noScriptTag = lazyLoadAreas[i];
//only process the ones marked for lazy loading
if (!noScriptTag.hasAttribute("data-lazy-load")) continue;
// The contents of a noscript tag are treated as text to JavaScript
var lazyAreaHtml = noScriptTag.textContent||noScriptTag.innerHTML;
// So we stick them in the innerHTML of a new div tag to 'load' them
var lazyArea = document.createElement("div");
lazyArea.innerHTML = lazyAreaHtml;
//Only delay loading if we can use the IntersectionObserver to check for visibility
if(!observer) {
noScriptTag.parentNode.replaceChild(lazyArea, noScriptTag);
} else {
prepareLazyContents(lazyArea);
noScriptTag.parentNode.replaceChild(lazyArea, noScriptTag);
}
}
}
//If the page has loaded already, run setup - if it hasn't, run as soon as it has.
//Use requestAnimationFrame as this will propably cause repaints
if (/comp|inter/.test(document.readyState)) {
rAF(setUp);
} else if ("addEventListener" in document) {
document.addEventListener("DOMContentLoaded",
function(){rAF(setUp);});
} else {
document.attachEvent("onreadystatechange", function() {
if (document.readyState=="complete") {
setUp();
}
});
}
})();
<p>Scroll down to see lazy loading in action!</p>
<noscript><p>Even with JavaScript turned off, the images should still load.</p></noscript>
<p>Why are the assets in noscript tags? So that they will load for people who have turned JavaScript off!</p>
<p>(The conditional comments are becuase there is no way to fetch the contents of a noscript tag in IE8 and below.)</p>
<hr/>
<div style="height: 600px;"></div>
<hr/>
<!--[if (gt IE 8)|!(IE)]><!--><noscript data-lazy-load><!--<![endif]-->
<img src="//upload.wikimedia.org/wikipedia/commons/2/27/F-16_Plan_Black_on_Circle_Light_Blue.svg?c=25" alt="This is an image used to demonstrate a lazy-loading trick." width="250" height="250">
Here is some text on the outside to demonstrate the lack of reflows!
<!--[if (gt IE 8)|!(IE)]><!--></noscript><!--<![endif]-->
<hr/>
<!--[if (gt IE 8)|!(IE)]><!--><noscript data-lazy-load><!--<![endif]-->
<picture>
<img src="//upload.wikimedia.org/wikipedia/commons/2/27/F-16_Plan_Black_on_Circle_Light_Blue.svg?c=25" alt="This is an image used to demonstrate a lazy-loading trick." width="250" height="250">
</picture>
This one is a reponsive picture element!
<!--[if (gt IE 8)|!(IE)]><!--></noscript><!--<![endif]-->
It only Lazy-Loads on browser that support Intersection Observer (so not IE, but about 87% of the world at time of writing) but the image will show in all browsers.
Since 2019 the img tag has a new attribute: loading. You can specify loading="lazy" which defers loading the image until it reaches a calculated distance from the viewport, as defined by the browser.
It has broad browser support (Edge, Firefox, Chrome, Safari and Opera):
It defaults to eager/normal loading in case of older browsers or when Javascript is disabled. The latter is an anti-tracking measure, because if a user agent supported lazy loading when scripting is disabled, it would still be possible for a site to track a user's approximate scroll position by strategically placing images in a page's markup. (source: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-loading)
I have an iFrame that is running some Javascript and I want the iFrame to behave differently depending on which page it is loaded into. I found this code which works brilliantly but it shows me the url of the iFrame not the parent.
var Page1 = "page1.html";
var Page2 = "page2.html";
var thisUrl = decodeURI(window.location);
var urlChunks = thisUrl.split("/");
for (var chunk in urlChunks) {
alert('chunk: ' + chunk);
alert('urlChunks[chunk]: ' + urlChunks[chunk]);
if (urlChunks[chunk] == Page1) {
alert('inside index.html');
}
else if (urlChunks[chunk] == Page2) {
}
else
{
}
}
What can I change the
decodeURI(window.location);
to in order to get it to read from the parent.
window.parent.location
Remember that JavaScript has the Same-Origin restriction, so when the parent document is a different origin (eg. domain), you will most probably get an access-denied exception.
Is there any good way to detect when a page isn't going to display in a frame because of the X-Frame-Options header? I know I can request the page serverside and look for the header, but I was curious if the browser has any mechanism for catching this error.
OK, this one is old but still relevant.
Fact:
When an iframe loads a url which is blocked by a X-Frame-Options the loading time is very short.
Hack:
So if the onload occurs immediately I know it's probably a X-Frame-Options issue.
Disclaimer:
This is probably one of the 'hackiest' code I've written, so don't expect much:
var timepast=false;
var iframe = document.createElement("iframe");
iframe.style.cssText = "position:fixed; top:0px; left:0px; bottom:0px; right:0px; width:100%; height:100%; border:none; margin:0; padding:0; overflow:hidden; z-index:999999;";
iframe.src = "http://pix.do"; // This will work
//iframe.src = "http://google.com"; // This won't work
iframe.id = "theFrame";
// If more then 500ms past that means a page is loading inside the iFrame
setTimeout(function() {
timepast = true;
},500);
if (iframe.attachEvent){
iframe.attachEvent("onload", function(){
if(timepast) {
console.log("It's PROBABLY OK");
}
else {
console.log("It's PROBABLY NOT OK");
}
});
}
else {
iframe.onload = function(){
if(timepast) {
console.log("It's PROBABLY OK");
}
else {
console.log("It's PROBABLY NOT OK");
}
};
}
document.body.appendChild(iframe);
Disclaimer: this answer I wrote in 2012(Chrome was version ~20 at that time) is outdated and I'll keep it here for historical purposes only. Read and use at your own risk.
Ok, this is a bit old question, but here's what I found out (it's not a complete answer) for Chrome/Chromium.
the way do detect if a frame pointing to a foreign address has loaded is simply to try to access its contentWindow or document.
here's the code I used:
element.innerHTML = '<iframe class="innerPopupIframe" width="100%" height="100%" src="'+href+'"></iframe>';
myframe = $(element).find('iframe');
then, later:
try {
var letstrythis = myframe.contentWindow;
} catch(ex) {
alert('the frame has surely started loading');
}
the fact is, if the X-Frame-Options forbid access, then myFrame.contentWindow will be accessible.
the problem here is what I called "then, later". I haven't figured out yet on what to rely, which event to subsribe to find when is the good time to perform the test.
This is based on #Iftach's answer, but is a slightly less hacky.
It checks to see if iframe.contentWindow.length > 0 which would suggest that the iframe has successfully loaded.
Additionally, it checks to see if the iframe onload event has fired within 5s and alerts that too. This catches failed loading of mixed content (in an albeit hacky manner).
var iframeLoaded = false;
var iframe = document.createElement('iframe');
// ***** SWAP THE `iframe.src` VALUE BELOW FOR DIFFERENT RESULTS ***** //
// iframe.src = "https://davidsimpson.me"; // This will work
iframe.src = "https://google.com"; // This won't work
iframe.id = 'theFrame';
iframe.style.cssText = 'position:fixed; top:40px; left:10px; bottom:10px;'
+ 'right:10px; width:100%; height:100%; border:none; margin:0; padding:0; overflow:hidden; z-index:999999;';
var iframeOnloadEvent = function () {
iframeLoaded = true;
var consoleDiv = document.getElementById('console');
if (iframe.contentWindow.length > 0) {
consoleDiv.innerHTML = '✔ Content window loaded: ' + iframe.src;
consoleDiv.style.cssText = 'color: green;'
} else {
consoleDiv.innerHTML = '✘ Content window failed to load: ' + iframe.src;
consoleDiv.style.cssText = 'color: red;'
}
}
if (iframe.attachEvent){
iframe.attachEvent('onload', iframeOnloadEvent);
} else {
iframe.onload = iframeOnloadEvent;
}
document.body.appendChild(iframe);
// iframe.onload event doesn't trigger in firefox if loading mixed content (http iframe in https parent) and it is blocked.
setTimeout(function () {
if (iframeLoaded === false) {
console.error('%c✘ iframe failed to load within 5s', 'font-size: 2em;');
consoleDiv.innerHTML = '✘ iframe failed to load within 5s: ' + iframe.src;
consoleDiv.style.cssText = 'color: red;'
}
}, 5000);
Live demo here - https://jsfiddle.net/dvdsmpsn/7qusz4q3/ - so you can test it in the relevant browsers.
At time of writing, it works on the current version on Chrome, Safari, Opera, Firefox, Vivaldi & Internet Explorer 11. I've not tested it in other browsers.
The only thing I can think of is to proxy an AJAX request for the url, then look at the headers, and if it doesn't have X-Frame-Options, then show it in the iframe. Far from ideal, but better than nothing.
At least in Chrome, you can notice the failure to load because the iframe.onload event doesn't trigger. You could use that as an indicator that the page might not allow iframing.
Online test tools might be useful.
I used https://www.hurl.it/.
you can clearly see the response header.
Look for X-frame-option. if value is deny - It will not display in iframe.
same origin- only from the same domain,
allow- will allow from specific websites.
If you want to try another tool, you can simply google for 'http request test online'.
This is how I had checked for X-Frames-Options for one of my requirements. On load of a JSP page, you can use AJAX to send an asynchronous request to the specific URL as follows:
var request = new XMLHttpRequest();
request.open('GET', <insert_URL_here>, false);
request.send(null);
After this is done, you can read the response headers received as follows:
var headers = request.getAllResponseHeaders();
You can then iterate over this to find out the value of the X-Frames-Options. Once you have the value, you can use it in an appropriate logic.
This can be achieved through
a) Create a new IFrame through CreateElement
b) Set its display as 'none'
c) Load the URL through the src attribute
d) In order to wait for the iframe to load, use the SetTimeOut method to delay a function call (i had delayed the call by 10 sec)
e) In that function, check for the ContentWindow length.
f) if the length > 0, then the url is loaded else URL is not loaded due to X-Frame-Options
Below is the sample code:
function isLoaded(val) {
var elemId = document.getElementById('ctlx');
if (elemId != null)
document.body.removeChild(elemId);
var obj= document.createElement('iframe');
obj.setAttribute("id", "ctlx");
obj.src = val;
obj.style.display = 'none';
document.body.appendChild(obj);
setTimeout(canLoad, 10000);
}
function canLoad() {
//var elemId = document.getElementById('ctl100');
var elemId = document.getElementById('ctlx');
if (elemId.contentWindow.length > 0) {
elemId.style.display = 'inline';
}
else {
elemId.src = '';
elemId.style.display = 'none';
alert('not supported');
}
}