Fetch url of html page inside an iframe [duplicate] - javascript

Is there a simple way to get the current URL from an iframe?
The viewer would going through multiple sites.
I'm guessing I would be using something in javascript.

For security reasons, you can only get the url for as long as the contents of the iframe, and the referencing javascript, are served from the same domain. As long as that is true, something like this will work:
document.getElementById("iframe_id").contentWindow.location.href
If the two domains are mismatched, you'll run into cross site reference scripting security restrictions.
See also answers to a similar question.

If your iframe is from another domain, (cross domain), the other answers are not going to help you... you will simply need to use this:
var currentUrl = document.referrer;
and - here you've got the main url!

If you are in the iframe context,
you could do
const currentIframeHref = new URL(document.location.href);
const urlOrigin = currentIframeHref.origin;
const urlFilePath = decodeURIComponent(currentIframeHref.pathname);
If you are in the parent window/frame, then you can use https://stackoverflow.com/a/938195/2305243 's answer, which is
document.getElementById("iframe_id").contentWindow.location.href

I had an issue with blob url hrefs. So, with a reference to the iframe, I just produced an url from the iframe's src attribute:
const iframeReference = document.getElementById("iframe_id");
const iframeUrl = iframeReference ? new URL(iframeReference.src) : undefined;
if (iframeUrl) {
console.log("Voila: " + iframeUrl);
} else {
console.warn("iframe with id iframe_id not found");
}

Hope this will help some how in your case,
I suffered with the exact same problem, and just used localstorage to share the data between parent window and iframe.
So in parent window you can:
localStorage.setItem("url", myUrl);
And in code where iframe source is just get this data from localstorage:
localStorage.getItem('url');
Saved me a lot of time.
As far as i can see the only condition is access to the parent page code.
Hope this will help someone.

If you're inside an iframe that don't have cross domain src, or src is empty:
Then:
function getOriginUrl() {
var href = document.location.href;
var referrer = document.referrer;
// Check if window.frameElement not null
if(window.frameElement) {
href = window.frameElement.ownerDocument.location.href;
// This one will be origin
if(window.frameElement.ownerDocument.referrer != "") {
referrer = window.frameElement.ownerDocument.referrer;
}
}
// Compare if href not equal to referrer
if(href != referrer) {
// Take referrer as origin
return referrer;
} else {
// Take href
return href
}
}
If you're inside an iframe with cross domain src:
Then:
function getOriginUrl() {
var href = document.location.href;
var referrer = document.referrer;
// Detect if you're inside an iframe
if(window.parent != window) {
// Take referrer as origin
return referrer;
} else {
// Take href
return href;
}
}

I've been trying to retrieve the full URL from the inside of the shopify google analytics additional script iframe. document.refferer shows only hostname without search params. But I found another property that worked for me document.baseURI

Some additional information for anyone who might be struggling with this:
You'll be getting null values if you're trying to get URL from iframe before it's loaded.
I solved this problem by creating the whole iframe in javascript and getting the values I needed with the onLoad function:
var iframe = document.createElement('iframe');
iframe.onload = function() {
//some custom settings
this.width=screen.width;this.height=screen.height; this.passing=0; this.frameBorder="0";
var href = iframe.contentWindow.location.href;
var origin = iframe.contentWindow.location.origin;
var url = iframe.contentWindow.location.url;
var path = iframe.contentWindow.location.pathname;
console.log("href: ", href)
console.log("origin: ", origin)
console.log("path: ", path)
console.log("url: ", url)
};
iframe.src = 'http://localhost/folder/index.html';
document.body.appendChild(iframe);
Because of the same-origin policy, I had problems when accessing "cross origin" frames - I solved that by running a webserver locally instead of running all the files directly from my disk. In order for all of this to work, you need to be accessing the iframe with the same protocol, hostname and port as the origin. Not sure which of these was/were missing when running all files from my disk.
Also, more on location objects: https://www.w3schools.com/JSREF/obj_location.asp

Related

Check if specific text exists in iframe using javascript

I got this iframe:
<iframe id="frami" src="http://192.168.178.22/file.html"></iframe>
which contains the text:
var m1_enable="1"; var m1_x="0"; var m1_y="570"; var m1_w="1920"; var m1_h="510"; var m1_sensitivity="50"; var m1_threshold="0";
How can I check if m1_enable="1" exists in the iframe?
I tried this now:
iframe_html = document.getElementById('frami').contentWindow.document.body.innerHTML;
if(iframe_html.includes("var")){
alert();
}
else{
}
iframe tag has a property called contentDocument that returns the document object generated by an iframe and another called contentWindow that returns the window object generated by an iframe. You can check if "m1_enable="1" by
var x = document.getElementById("frami");
var y = (x.contentWindow || x.contentDocument);
if (y.document) y = y.document;
if (y.body.textContent.indexOf('m1_enable="1"')>-1){
alert('found the phrase'
}
You can get the HTML from iframe with:
iframe_html = document.getElementById('iframe').contentWindow.document.body.innerHTML
And check if it includes m1_enable="1" with:
iframe_html.includes("m1_enable='1'")
This will work only if the frame source is on the same domain. If it is from a different domain, cross-site-scripting (XSS) protection will kick in.
If your iframe is on the same domain it is document.getElementById('frami').contentWindow['m1_enable'] (if this isn't null, compare with 1 with ==1).
otherwise, look at window.postMessage
https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage

Retrieve URL of AppScript using Javascript

I am trying to reload the current page with a new parameter, but I am unable to retrieve the correct URL of the webpage. I am getting an alternate URL instead of the one that triggers the web app
https://script.google.com/a/user/macros/s/A...ljhGC/dev?action=menu&id=1
when the button is clicked I want the action parameter's value to change and the page to reload as
https://script.google.com/a/user/macros/s/A...ljhGC/dev?action=checkout&id=1
Here is my javascript within the HTML File
console.log(document.url);
var url = new URL(window.location.href);
var query_string = url.search;
var search_params = new URLSearchParams(query_string);
search_params.set('action', 'checkout');
url.search = search_params.toString();
var new_url = url.toString();
window.location.replace(new_url);
console.log(new_url);
}
This is the URL that gets logged
https://n-ikwx...khq-1lu-script.googleusercontent.com/userCodeAppPanel?action=checkout
How do I retrieve the actual URL that is in the address bar?
Thanks in advance!
Issue:
A iframe with different origin cannot read the href property of location of the the parent/top frame, which is write only. So, You can't.
Solution:
You can however pass the url from server side.
Server side:
function getTopUrl(){
return ScriptApp.getService().getUrl();
}
Client side:
var topUrl;
function getTop(){
google.script.run.withSuccessHandler((url)=>{topUrl=url;}).getTopUrl();
}
window.addEventListener('load', getTop);
References:
Where is my iframe in the published web application/sidebar?
Same origin policy
Service#getUrl
google.script#run

JavaScript changing iframe src causes http request conflict and iframe doesn't reload

I am new to web dev and have done a lot of research on my problem, but I still feel stuck:
What I am trying to achieve:
Pass data via URL parameters to an iframe src to be used in the iframe document. The parent page and the iframe are on different domains.
Setup:
I can have one or multiple iframe(s) with a src=”www.example.com”. After the DOM is fully loaded, I try to change the iframe(s) src in order to append some query parameters.
I am using pure JS to get the initial iframe(s) src > concatonate it with the query parameters > save the new URL in variable > change the iframe(s) src to the URL from the variable.
Problem:
Sometimes the iframe src doesn’t change – seems to be related to the internet connection. Every few refreshes javascript will not succeed changing the src, but doesn’t throw any errors.
My troubleshooting:
If I inspect the page and go to Network (Chrome), I can see there are 2 HTTP requests for the iframe: first with the initial src and second with the new src (even if the JS dones’t succeed changing it).
From here I encountered 3 scenarios:
First http request is cancelled and the second is finished – everything is fine – src is changed and data is passed.
both http requests remain in ‘pending’ status – the src is change and data is passed.
first http request is finished before the second one is started. The second one remains in ‘pending’ status – this is the problem – the src doesn’t change, it remains to the old one even though JS seems to have executed properly.
I understand that when the src of an iframe is changed it should cause the iframe to reload, thus triggering the second http request. However, when scenario 3 happens the iframe doesn’t reload. It’s like an http request ‘conflict’ (not sure if it's the correct way to put it).
Why changing the src would not properly reload the iframe consistently?
I appreciate any suggestions, best practices or possible alternatives to make this work.
Here is my code. I've put comments to describe what I intend to do:
paramToPass = ['parma1', 'param2', 'param3']
if (paramToPass) {
var myIframe = 'myIframeClass'; // define what iframes to find
var iframes = document.getElementsByClassName(myIframe); // get all iframes from the page with desired class
var paramStr = paramToPass.join('&'); // create the query parameter string
var iframesElm;
for (iframesElm = 0; iframesElm < iframes.length; iframesElm++) {
var initialSrc = iframes[iframesElm].getAttribute('src'); // find the initial src of the iframe
if(initialSrc.indexOf("?") > -1) { // if initialSrc already contains parameters
var newSrc = initialSrc + '&' + paramStr; // concatonate initial src with parameters
iframes[iframesElm].src = newSrc; // change the iframe src
// iframes[iframesElm].setAttribute('src', newSrc); // alternative to change iframe src
} else { // if initialSrc doesn't contain parameters
var newSrc = initialSrc + '?' + paramStr; // concatonate initial src with parameters
iframes[iframesElm].src = newSrc; // change iframe src
// iframes[iframesElm].setAttribute('src', newSrc); // alternative to change iframe src
};
};
};
Thank you!
EDIT:
New, working code. For wider browser compatibility, I've included polyfill for Array.from() and forEach():
paramToPass = ['parma1', 'param2', 'param3']
if (paramToPass.length > 0) {
var iframes = document.getElementsByClassName(myIframe);
var paramToPassStr = paramToPass.join('&');
Array.from(iframes).forEach(function(iframe) {
iframe.onload = function() { // execute after the iframe is loaded. Prevents http request conflict
var initialSrc = iframe.src;
var sep = initialSrc.indexOf("?") > -1 ? "&" : "?"; // choose separator based on whether or not params already exist in the initialSrc
var newSrc = initialSrc + sep + paramToPassStr;
iframe.src = newSrc;
console.log('iframe reload');
iframe.onload = null; // stops the infinite reload loop
};
});
} else { // paramToPass array is empty, throw error
console.log('no paramToPassStr to pass found')
};
You should probably put the code to reload the iframe into its onload handler, so it runs after the iframe successfully loaded the first time. Then there won't be any conflict.
Array.from(iframes).forEach(iframe => iframe.onload = () => {
var initialSrc = this.src;
var sep = initialSrc.indexOf("?") > -1 ? "&" : "?";
var newSrc = initialSrc + sep + paramStr;
this.src = newSrc;
this.onload = null;
});

Prevent preflight OPTIONS when using sub domains

Given two sub domains:
web.mysite.com and api.mysite.com
Currently making any request from web. to api. results in the preflight OPTIONS request being made. This wouldn't be so much of an issue if it didn't add an extra 600ms to requests in China.
I was told that setting document.domain = 'mysite.com'; in JS would resolve the issue but this hasn't helped at all.
Is it possible / how can I disable the OPTIONS request when sending to just a different sub domain.
Solved this using the iframe technique which seems to be what Facebook / Twitter do.
Steps below:
1) Set the document.domain to be the root domain. So given the url http://site.mysite.com/ I set the domain in JavaScript like document.domain = 'mysite.com';
2) Setup an iframe which pulls a HTML file from the API Domain.
<iframe id="receiver" src="http://api.mysite.com/receiver" style="position:absolute;left:-9999px"></iframe>
This is set to be positioned so it can't be seen.
3) Set the HTML of the receiver page to set the domain:
<!DOCTYPE html><body><script>document.domain='mysite.com'</script></body></html>
4) Added an onload event to the iframe to capture the window once its loaded.
onload="window.tempIframeCallback()"
5) Assign the child window to a variable.
window.tempIframeCallback = function() {
window.childWindow = window.receiver.contentWindow;
}
6) Make the XMLHttpRequest() from the childWindow instead of the main window.
var xhr = new window.childWindow.XMLHttpRequest();
Now all requests will be sent without a preflight OPTIONS request.
7) When using jQuery, you can also set the source of xhr in the settings:
$.ajax({
...
xhr: function() {
return new window.childWindow.XMLHttpRequest();
}
});
As a complement to #Phill's answer that deserves all the credits, here is the final html code, that also exposes the iframe's fetch function:
<!DOCTYPE html>
<html><body>
<script>
document.domain = 'mysite.com';
window.setupAPI = function() {
var receiverWindow = window.receiver.contentWindow;
// you may also want to replace window.fetch here
window.APIfetch = receiverWindow.fetch;
// same thing, you may as well replace window.XMLHttpRequest
window.APIXMLHttpRequest = receiverWindow.XMLHttpRequest;
}
</script>
<iframe id="receiver"
src="http://api.mysite.com/receiver"
style="position:absolute;left:-9999px"
onload="window.setupAPI()"></iframe>
</body></html>
And of course the HTML "http://api.mysite.com/receiver" should retrieve:
<!DOCTYPE html>
<html><body><script>
document.domain='mysite.com';
</script></body></html>
And then, within your JS code, you can now use APIfetch and APIXMLHttpRequest like you'd use fetch and XMLHttpRequest ... et voilà, no more preflight request whatever the method and content type used!
Here's an all javascript approach:
document.domain = 'mysite.net';
var apiIframe = document.createElement('iframe');
apiIframe.onload = function(){
window.XMLHttpRequest = this.contentWindow.XMLHttpRequest;
};
apiIframe.setAttribute('src', API_URL + '/iframe');
apiIframe.style.display = 'none';
document.body.appendChild(apiIframe);
where API_URL + '/iframe' returns this:
<!DOCTYPE html><body><script>document.domain = 'mysite.net'</script></body></html>

Get Current location of Iframe [duplicate]

Is there a simple way to get the current URL from an iframe?
The viewer would going through multiple sites.
I'm guessing I would be using something in javascript.
For security reasons, you can only get the url for as long as the contents of the iframe, and the referencing javascript, are served from the same domain. As long as that is true, something like this will work:
document.getElementById("iframe_id").contentWindow.location.href
If the two domains are mismatched, you'll run into cross site reference scripting security restrictions.
See also answers to a similar question.
If your iframe is from another domain, (cross domain), the other answers are not going to help you... you will simply need to use this:
var currentUrl = document.referrer;
and - here you've got the main url!
If you are in the iframe context,
you could do
const currentIframeHref = new URL(document.location.href);
const urlOrigin = currentIframeHref.origin;
const urlFilePath = decodeURIComponent(currentIframeHref.pathname);
If you are in the parent window/frame, then you can use https://stackoverflow.com/a/938195/2305243 's answer, which is
document.getElementById("iframe_id").contentWindow.location.href
I had an issue with blob url hrefs. So, with a reference to the iframe, I just produced an url from the iframe's src attribute:
const iframeReference = document.getElementById("iframe_id");
const iframeUrl = iframeReference ? new URL(iframeReference.src) : undefined;
if (iframeUrl) {
console.log("Voila: " + iframeUrl);
} else {
console.warn("iframe with id iframe_id not found");
}
Hope this will help some how in your case,
I suffered with the exact same problem, and just used localstorage to share the data between parent window and iframe.
So in parent window you can:
localStorage.setItem("url", myUrl);
And in code where iframe source is just get this data from localstorage:
localStorage.getItem('url');
Saved me a lot of time.
As far as i can see the only condition is access to the parent page code.
Hope this will help someone.
If you're inside an iframe that don't have cross domain src, or src is empty:
Then:
function getOriginUrl() {
var href = document.location.href;
var referrer = document.referrer;
// Check if window.frameElement not null
if(window.frameElement) {
href = window.frameElement.ownerDocument.location.href;
// This one will be origin
if(window.frameElement.ownerDocument.referrer != "") {
referrer = window.frameElement.ownerDocument.referrer;
}
}
// Compare if href not equal to referrer
if(href != referrer) {
// Take referrer as origin
return referrer;
} else {
// Take href
return href
}
}
If you're inside an iframe with cross domain src:
Then:
function getOriginUrl() {
var href = document.location.href;
var referrer = document.referrer;
// Detect if you're inside an iframe
if(window.parent != window) {
// Take referrer as origin
return referrer;
} else {
// Take href
return href;
}
}
I've been trying to retrieve the full URL from the inside of the shopify google analytics additional script iframe. document.refferer shows only hostname without search params. But I found another property that worked for me document.baseURI
Some additional information for anyone who might be struggling with this:
You'll be getting null values if you're trying to get URL from iframe before it's loaded.
I solved this problem by creating the whole iframe in javascript and getting the values I needed with the onLoad function:
var iframe = document.createElement('iframe');
iframe.onload = function() {
//some custom settings
this.width=screen.width;this.height=screen.height; this.passing=0; this.frameBorder="0";
var href = iframe.contentWindow.location.href;
var origin = iframe.contentWindow.location.origin;
var url = iframe.contentWindow.location.url;
var path = iframe.contentWindow.location.pathname;
console.log("href: ", href)
console.log("origin: ", origin)
console.log("path: ", path)
console.log("url: ", url)
};
iframe.src = 'http://localhost/folder/index.html';
document.body.appendChild(iframe);
Because of the same-origin policy, I had problems when accessing "cross origin" frames - I solved that by running a webserver locally instead of running all the files directly from my disk. In order for all of this to work, you need to be accessing the iframe with the same protocol, hostname and port as the origin. Not sure which of these was/were missing when running all files from my disk.
Also, more on location objects: https://www.w3schools.com/JSREF/obj_location.asp

Categories

Resources