javascript google chrome extension iframe cannot examine contentWindow - javascript

I am writing a Google Chrome extension. Now I need to examine the contents of an iframe but the content script seems unable to access this content even though the debugger can. The iframe contents are a list of messages I have previously sent to that site. If I put the following statement in the content script, it always returns null:
document.getElementById("td_messages_show").getElementsByTagName("iframe")[0].contentWindow.document;
But if I open the debugger and execute the same command from the command line, it returns "Document" with the appropriate contents. At first I thought it was because the frame wasn't finished loading so I found a snippet like this and tried to use it.
function wait4Iframe2Load() {
// Get a handle to the iframe element
//console.log('Checking for null myFrame');
var myFrame = document.getElementById("td_messages_show").getElementsByTagName("iframe")[0].contentWindow;
if (myFrame!=null)
{
console.log(myFrame);
// Check if loading is complete
if ( myFrame.document.readyState == 'complete' ) {
// The loading is complete, call the function we want executed once the iframe is loaded
console.log('Loading Complete');
//frameContent=document.getElementById("td_messages_show").getElementsByTagName("iframe")[0].contentWindow.document.getElementsByTagName('tbody')[0];
return;
}
else alert(" Frame is Not Loaded");
}
else myFrame = document.getElementById("td_messages_show").getElementsByTagName("iframe")[0].contentWindow;
// If we are here, it is not loaded. Set things up so we check the status again in 100 milliseconds
console.log('Waiting for frame to load...');
window.setTimeout('wait4Iframe2Load()', 100);
}
This simply returns null forever. But while this script is piling up console messages, I can open the debugger and execute the very same command line and it returns a document. Faced with this problem and researching internet answers, it seems it may be some deliberate kind of security issue. Whether it is or isn't, I need to examine the iframe contents and determine what I have written there previously so I can decide what to write there next.
Does anybody have an idea how to solve this problem?

The idea is to inject content script into this iframe and use it to get required information.
As I understand this frame has a specific url known upfront, so you can just inject the script through the manifest (use the all_frames option).
If for some reason you need to dynamically inject it, then there is:
chrome.tabs.executeScript(tabId, {allFrames: true});
It will be injected into both parent and iframe pages. Then inside injected content script you can check whether or not it is running inside the right iframe. For example your dynamically injected content script might look like this (if you inject it though the manifest url checking won't be needed):
if(window.location.href == "http://iframe.example.com/" && window != window.top) {
//we are in the right page that is embedded as iframe, do stuff
} else {
//do nothing
}

Excuse me, have you got solution, Jerome? I am having same problem as yours. But I can not make comment on your post. So please do not mind because this is a question...
Edited:
Finally I got it working. I don't understand while flag all_frames: true in manifest.json is not affected. I need to code as #serg's:
chrome.tabs.executeScript(tabId, {allFrames:true, file:"content_script.js"})
Thank you all, and could you please accept #serg's answer as the right one, Jerome? :-)

I created this library:
https://github.com/attachmentsme/Queuebert
to simplify the communication between browser tabs, the extension's background process, and iframes.
The use-case that I was running into was:
an action is taken in one iframe.
the results should be displayed in an alternate iframe.
Doing this can be a pain, hence the abstraction I built.

Related

Inject javascript at the very top of the page \ Anti iframe-buster

I'm developing an extension that, sometimes, will show some websites inside iframes. I've already bypassed the X-FRAME-OPTIONS issue but now I'm stuck with the simple iframe buster code, eg.:
if (top != self) {
document.getElementsByTagName("html")[0].style.display = "none";
top.location.replace(location);
}
I'm trying to inject javascript at the very top of the page to override the window.top object, but at document_start is already too late to inject it, ie alert() is never called before the buster script runs:
chrome.webRequest.onCompleted.addListener(function(details) {
if (isEnabled) {
chrome.tabs.executeScript(details.tabId, {frameId: details.frameId, runAt: "document_start", code: "alert('asas');"});
}
}, {
types: ["sub_frame"],
urls: ["<all_urls>"]
});
Is there any way around this?
Thank you
The problem is probably caused by chrome.webRequest.onCompleted.addListener listener being asynchronous
document_start injects code before any DOM is created, so that is not the cause of your problem. I have verified this while playing around and trying to answer this question.
The problem here is that chrome.webRequest.onCompleted.addListener is asynchronous, which means that when the callback (and therefor your chrome.tabs.executeScript) is executed, the browser has already started constructing the DOM.
You can start by injecting the script to all relevant iframes directly using the "content_scripts" in manifest.json instead of using programmatic injection. I haven't verified this, but you could also try injecting the script from a chrome.webRequest.onHeadersReceived listener with the "blocking" option, which allows you to handle the request synchronously. You are probably already listening to onHeadersReceived in order to remove the X-Frame-Options header anyway.
Edit:
Programmatic injection in a blocking onHeadersReceived listener is not possible. Chrome returns an error about lack of permissions - probably because the URL is not known at this point yet (the headers could cause a redirect).

Detect when an iframe returns from a cross domain site

I have an iframe on my page that submits a form to a third party page. Once that third party is done with its calculation, it redirects back to my own site. I would like to detect when the iframe returns back to my own site.
My current approach is to use a timeout and check location.host of the iframe every 0.5 seconds. However, while the iframe is still on the third party site, I get a JS error, which I would like to avoid.
Is there a good way to figure out when the iframe's location is back on my own server without getting a JS error?
function check() {
try {
location.host; // if I error, doStuff() is never hit.
doStuff();
} catch( e ) {
setTimeout(check, 5000);
}
}
Using a try / catch statement should solve this issue for you. There are likely other ways around this, however after reviewing your question this was the first that came to mind.
Another alternative is to listen for the onload event from the iframe. This (in chrome at least) fires each time the iframe page changes. http://jsfiddle.net/rlemon/DwVJX/1/ here is a quick demo. In the iframe click on the jsFiddle logo to go back to the homepage. I understand this doesn't tell you IF you're on the right domain or not, but in conjunction with the try/catch this eliminates the need for a timer.
You could wrap your check in a try catch block. Alternatively you could have the page which is on your host 'call' the parent. (something like parent.notifyReady() ) That way you avoid having to use a setInterval
You could base your logic on whether to call the parent or not by using the document.referrer property
So on your third page you could have something like this:
if(document.referrer.indexOf('otherdomain.com') != -1) {
// script called via otherdomain.com
parent.notifyReady();
}
I think what you are currently doing is the only way to reliably detect whether an iframe is or isn't on a page hosted on your parent page's domain.
Most iframe properties are inaccessible (throw an exception when accessed) while the iframe is on a different domain than the parent. An exception is actually an indication that the iframe IS NOT on your site, so simply catch the exception and try again. If no exception is thrown, the iframe is on a page that is in the same domain as it's parent.

How to call javascript after frame is fully rendered?

I am looking for a way to modify an iFrame attribute (a textbox value actually). The iFrame is on another domain and I do have access to it. From what I understand I must do that after the entire page (iFrame included) is rendered. I tryed something like that:
<script type="text/javascript">
$(window).load(function() {
alert("test");
d = document.getElementById("myframe");
d.contentWindow.document.getElementById("frametxtbox");
});
</script>
But I always get the following error:
Cannot call method 'getElementById' of undefined
I also noticed that the alert pops up BEFORE the iFrame is rendered, so I think my script is executed before page has access to frame values and, therefore I get the error. I have very few knowledge of web-related programming (always worked on backend side) so forgive me if my question maybe makes no sense.
If the iframe points to another domain, it'll be subject to same origin policy. This means that before you try to access its document you'll have to check the wiki and relax the policy (check the link for details). After that you'll need to bind ready event to the iframes document, rather than your main page doc.
$(window.frames['myframe'].document).ready(function() { alert('moo'); });
See if this helps :)

"undefined" randomly appended in 1% of requested urls on my website since 12 june 2012

Since 12 june 2012 11:20 TU, I see very weirds errors in my varnish/apache logs.
Sometimes, when a user has requested one page, several seconds later I see a similar request but the all string after the last / in the url has been replaced by "undefined".
Example:
http://example.com/foo/bar triggers a http://example.com/foo/undefined request.
Of course theses "undefined" pages does not exist and my 404 page is returned instead (which is a custom page with a standard layout, not a classic apache 404)
This happens with any pages (from the homepage to the deepest)
with various browsers, (mostly Chrome 19, but also firefox 3.5 to 12, IE 8/9...) but only 1% of the trafic.
The headers sent by these request are classic headers (and there is no ajax headers).
For a given ip, this seems occur randomly: sometimes at the first page visited, sometimes on a random page during the visit, sometimes several pages during the visit...
Of course it looks like a javascript problem (I'm using jquery 1.7.2 hosted by google), but I've absolutely nothing changed in the js/html or the server configuration since several days and I never saw this kind of error before. And of course, there is no such links in the html.
I also noticed some interesting facts:
the undefined requests are never found as referer of another pages, but instead the "real" pages were used as referer for the following request of the same IP (the user has the ability to use the classic menu on the 404 page)
I did not see any trace of these pages in Google Analytics, so I assume no javascript has been executed (tracker exists on all pages including 404)
nobody has contacted us about this, even when I invoked the problem in the social networks of the website
most of the users continue the visit after that
All theses facts make me think the problem occurs silently in the browers, probably triggered by a buggy add-on, antivirus, a browser bar or a crappy manufacturer soft integrated in browsers updated yesterday (but I didn't find any add-on released yesterday for chrome, firefox and IE).
Is anyone here has noticed the same issue, or have a more complete explanation?
There is no simple straight answer.
You are going to have to debug this and it is probably JavaScript due to the 'undefined' word in the URL. However it doesn't have to be AJAX, it could be JavaScript creating any URL that is automatically resolved by the browser (e.g. JavaScript that sets the src attribute on an image tag, setting a css-image attribute, etc). I use Firefox with Firebug installed most of the time, so my directions will be with that in mind.
Firebug Initial Setup
Skip this if you already know how to use Firebug.
After the installs and restarting Firefox for Firebug, you are going to have to enable most of Firebug's 'panels'. To open Firebug there will be a little fire bug/insect looking thing in the top right corner of your browser or you can press F12. Click through the Firebug tabs 'Console', 'Script', 'Net' and enable them by opening them up and reading the panel's information. You might have to refresh the page to get them working properly.
Debugging User Interaction
Navigate to one of the pages that has the issue with Firebug open and the Net panel active. In the Net panel there will be a few options: 'Clear', 'Persist', 'All', 'Html', etc. Make sure ALL is selected. Don't do anything on the page and try not to mouse over anything on it. Look through the requests. The request for the invalid URL will be red and probably have a status of 404 Not Found (or similar).
See it on load? Skip to the next part.
Don't see it on initial load? Start using your page and continue here.
Start clicking on every feature, mouse over everything, etc. Keep your eyes on the Net panel and watch for a requests that fail. You might have to be creative, but continue using your application till you see your browser make an invalid request. If the page makes many requests, feel free to hit the 'Clear' button on the top left of the Net panel to clear it up a bit.
If you submit the page and see a failed request go out really quick but then lose it because the next page loads, enable persistence by clicking 'Persist' in the top left of the Net panel.
Once it does, and it should, consider what you did to make that happen. See if you can make it happen again. After you figure out what user interaction is making it happen, dive into that code and start looking for things that are making invalid requests.
You can use the Script tab to setup breakpoints in your JavaScript and step through them. Investigate event handlers done via $(elemment).bind/click/focus/etc or from old school event attributes like onclick=""/onfocus="" etc.
If the request is happening as soon as the page loads
This is going to be a little harder to peg down. You will need to go to the Script tab and start adding break points to every script that runs on load. You do this by clicking on the left side of the line of JavaScript.
Reload your page and your break points should stop the browser from loading the page. Press the 'Continue' button on the script panel. Go to your net panel and see if your request was made, continue till it is found. You can use this to narrow down where the request is being made from by slowly adding more and more break points and then stepping into and out of functions.
What you are looking for in your code
Something that is similar to the following:
var url = workingUrl + someObject['someProperty'];
var url = workingUrl + someObject.someProperty;
Keep in mind that someObject might be an object {}, an array [], or any of the internal browser types. The point is that a property will be accessed that doesn't exist.
I don't see any 404/red requests
Then whatever is causing it isn't being triggered by your tests. Try using more things. The point is you should be able to make the request happen somehow. You just don't know yet. It has to show up in the Net panel. The only time it won't is when you aren't doing whatever triggers it.
Conclusion
There is no super easy way to peg down what exactly is going on. However using the methods I outlined you should be at least be able to get close. It is probably something you aren't even considering.
Based on this post, I reverse-engineered the "Complitly" Chrome Plugin/malware, and found that this extension is injecting an "improved autocomplete" feature that was throwing "undefined" requests at every site that has a input text field with NAME or ID of "search", "q" and many others.
I found also that the enable.js file (one of complitly files) were checking a global variable called "suggestmeyes_loaded" to see if it's already loaded (like a Singleton). So, setting this variable to false disables the plugin.
To disable the malware and stop "undefined" requests, apply this to every page with a search field on your site:
<script type="text/javascript">
window.suggestmeyes_loaded = true;
</script>
This malware also redirects your users to a "searchcompletion.com" site, sometimes showing competitors ADS. So, it should be taken seriously.
You have correctly established that the undefined relates to a JavaScript problem and if your site users haven't complained about seeing error pages, you could check the following.
If JavaScript is used to set or change image locations, it sometimes happens that an undefined makes its way into the URI.
When that happens, the browser will happily try to load the image (no AJAX headers), but it will leave hints: it sets a particular Accept: header; instead of text/html, text/xml, ... it will use image/jpeg, image/png, ....
Once such a header is confirmed, you have narrowed down the problem to images only. Finding the root cause will possibly take some time though :)
Update
To help debugging you could override $.fn.attr() and invoke the debugger when something is being assigned to undefined. Something like this:
​(function($, undefined) {
var $attr = $.fn.attr;
$.fn.attr = function(attributeName, value) {
var v = attributeName === 'src' ? value : attributeName.src;
if (v === 'undefined') {
alert("Setting src to undefined");
}
return $attr(attributeName, value);
}
}(jQuery));
Some facts that have been established, especially in this thread: http://productforums.google.com/forum/#!msg/chrome/G1snYHaHSOc/p8RLCohxz2kJ
it happens on pages that have no javascript at all.
this proves that it is not an on-page programming error
the user is unaware of the issue and continues to browse quite happily.
it happens a few seconds after the person visits the page.
it doesn't happen to everybody.
happens on multiple browsers (Chrome, IE, Firefox, Mobile Safari, Opera)
happens on multiple operating systems (Linux, Android, NT)
happens on multiple web servers (IIS, Nginx, Apache)
I have one case of googlebot following the link and claiming the same referrer. They may just be trying to be clever and the browser communicated it to the mothership who then set out a bot to investigate.
I am fairly convinced by the proposal that it is caused by plugins. Complitly is one, but that doesn't support Opera. There many be others.
Though the mobile browsers weigh against the plugin theory.
Sysadmins have reported a major drop off by adding some javascript on the page to trick Complitly into thinking it is already initialized.
Here's my solution for nginx:
location ~ undefined/?$ {
return 204;
}
This returns "yeah okay, but no content for you".
If you are on website.com/some/page and you (somehow) navigate to website.com/some/page/undefined the browser will show the URL as changed but will not even do a page reload. The previous page will stay as it was in the window.
If for some reason this is something experienced by users then they will have a clean noop experience and it will not disturb whatever they were doing.
This sounds like a race condition where a variable is not getting properly initialized before getting used. Considering this is not an AJAX issue according to your comments, there will be a couple of ways of figuring this out, listed below.
Hookup a Javascript exception Logger: this will help you catch just about all random javascript exceptions in your log. Most of the time programmatic errors will bubble up here. Put it before any scripts. You will need to catch these on the server and print them to your logs for analysis later. This is your first line of defense. Here is an example:
window.onerror = function(m,f,l) {
var e = window.encodeURIComponent;
new Image().src = "/jslog?msg=" + e(m) + "&filename=" + e(f) + "&line=" + e(l) + "&url=" + e(window.location.href);
};
Search for window.location: for each of these instances you should add logging or check for undefined concats/appenders to your window.location. For example:
function myCode(loc) {
// window.location.href = loc; // old
typeof loc === 'undefined' && window.onerror(...); //new
window.location.href = loc; //new
}
or the slightly cleaner:
window.setLocation = function(url) {
/undefined/.test(url) ?
window.onerror(...) : window.location.href = url;
}
function myCode(loc) {
//window.location.href = loc; //old
window.setLocation(loc); //new
}
If you are interested in getting stacktraces at this stage take a look at: https://github.com/eriwen/javascript-stacktrace
Grab all unhandled undefined links: Besides window.location The only thing left are the DOM links themselves. The third step is to check all unhandeled DOM links for your invalid URL pattern (you can attach this right after jQuery finishes loading, earlier better):
$("body").on("click", "a[href$='undefined']", function() {
window.onerror('Bad link: ' + $(this).html()); //alert home base
});
Hope this is helpful. Happy debugging.
I'm wondering if this might be an adblocker issue. When I search through the logs by IP address it appears that every request by a particular user to /folder/page.html is followed by a request to /folder/undefined
I don't know if this helps, but my website is replacing one particular *.webp image file with undefined after it's loaded in multiple browsers. Is your site hosting webp images?
I had a similar problem (but with /null 404 errors in the console) that #andrew-martinez's answer helped me to resolve.
Turns out that I was using img tags with an empty src field:
<img src="" alt="My image" data-src="/images/my-image.jpg">
My idea was to prevent browser from loading the image at page load to manually load later by setting the src attribute from the data-src attribute with javascript (lazy loading). But when combined with iDangerous Swiper, that method caused the error.

Call the function only after the browser is fully redirected?

<script>
function test() {
alert("this should only be called after the browser is fully redirected?");
}
window.location = "http://google.com";
test();
</script>
I'm about redirecting the user guys to a page and I want to do something (call a function) only after the browser is fully redirected but I can't get it to work. Is there any way for me to do so?
Is there any way for me to do so?
Nope. When the page has opened google.com, you no longer have any control over the browser window.
Once URL changes, all execution of the current page is stopped.
Not really. You'd have to put the page you were redirecting in a frame and keep the script in another frame, then watch for the content frame to get updated. But you'd also run into cross-domain issues because of the Same Origin Policy (which governs access to one document's contents [the new page] from another document [the one containing the script you're running]). So basically, you can't do this.
If you post a separate question saying what you're trying to achieve by running more code afterward, it may be that people can help you with alternative approaches.
i don't believe this would work. it's a form of XSS/injection and therefore a security risk. i don't think the W3C allowed this sort of thing because it's very dangerous. as soon as the user is loading a different page, the browser ignores the previous one.
http://www.coderanch.com/t/439675/HTML-JavaScript/Javascript-call-AFTER-redirect
see that guy's answer for a visual

Categories