Using given function to post message, but getting error "DataCloneError: The object could not be cloned." at Line "target['postMessage'](message, target_url.replace( /([^:]+://[^/]+).*/, '$1'));" in FireFox-34, same code is working fine on Chrome and older version of FireFox.
var storage = function() {
return {
postMessage : function(message, target_url, target) {
if (!target_url) {
return;
}
var target = target || parent; // default to parent
if (target['postMessage']) {
// the browser supports window.postMessage, so call it with a targetOrigin
// set appropriately, based on the target_url parameter.
target['postMessage'](message, target_url.replace( /([^:]+:\/\/[^\/]+).*/, '$1'));
}
}
}
}();
postMessage sends messages using the structured clone algorithm in Firefox and because of that there are certain things you need to adjust prior to sending.
In your example it isn't obvious what message contains but one hack-y way around structured clone is to coerce a bit. Sending a URL via postMessage will throw an error:
someWindow.postMessage(window.location, '*');
// ERROR
But you can do this to work around it:
var windowLocation = '' + window.location;
someWindow.postMessage(windowLocation, '*');
// WORKS
There are better ways to handle this but for what you've provided this should at least allow consistent behavior.
Related
I have this piece of javascript code doing my clickouts and it should enable correct click-out tracking. clickDestinations are all different, and there are many ( cross domain ).
var response = window.open(clickDestination, randomName);
if (typeof response.focus === 'function') {
alert('tracking this click-out');
}
Problem with this implementation is the clickDestination was given by users and some of it is very old, so there is no guarantee that http or https protocol is correctly set.
When window.open is called with the wrong protocol, ex. with https on sites where https is not supported, i get "This site can’t be reached" page (ERR_CONNECTION_CLOSED). But my tracker tracks anyway since var response is a window object.
Any ideas how can i detect the mistake and not track in this case ?
First idea valid if url is on the same domain (same origin policy applies here):
var w = window.open(url);
// if window opened successfully
if ( w ) {
w.onload = function() {
alert('tracking this click-out');
};
}
Second idea:
window.open returns a reference to the newly created window.
If the call failed, it will be null instead. Ref.
So in case the connection fails because the server at specified URL does not support https or either http null will be returned so you can use this information to skip your tracking code.
Example (not tested):
var response = window.open(clickDestination, randomName);
// if destination cannot be open, skip tracking code
if(!response){
return;
}
if (typeof response.focus === 'function') {
alert('tracking this click-out');
}
I've got some code running in an iframe on 3rd-party sites. Some will be directly in the top page, some will be inside another iframe and some of these may be cross-domain. I need to find a way to get the URL value of the top page using any means necessary.
The furthest I can go up due to cross-domain policy is until the browser stops what the code is doing. I catch the error and look at the referrer of the current window context I'm in. Most cases the page above this is the top page, but not necessarily.
The only way I can see around this is building up a list of URLs which I think are the top page, and then sending a bot with a JS browser validate by seeing if the iframe my code got up to was in fact directly nested in them.
That's still not particularly accurate though, and I'm sure there must be another way of doing it...
Thanks to anyone who can help.
There is actually a way to get the domain in both Chrome and Opera, (in multiple nested cross-domain iframes), though it is not possible in other browsers.
You need to use the 'window.location.ancestorOrigins' property.
I have created a snippet of code below, which should work for you and if you think you can improve the code or comments, please don't hesitate to edit the gist on Github so we can make it even better:
Gist: https://gist.github.com/ocundale/281f98a36a05c183ff3f.js
Code (ES2015):
// return topmost browser window of current window & boolean to say if cross-domain exception occurred
const getClosestTop = () => {
let oFrame = window,
bException = false;
try {
while (oFrame.parent.document !== oFrame.document) {
if (oFrame.parent.document) {
oFrame = oFrame.parent;
} else {
//chrome/ff set exception here
bException = true;
break;
}
}
} catch(e){
// Safari needs try/catch so sets exception here
bException = true;
}
return {
'topFrame': oFrame,
'err': bException
};
};
// get best page URL using info from getClosestTop
const getBestPageUrl = ({err:crossDomainError, topFrame}) => {
let sBestPageUrl = '';
if (!crossDomainError) {
// easy case- we can get top frame location
sBestPageUrl = topFrame.location.href;
} else {
try {
try {
// If friendly iframe
sBestPageUrl = window.top.location.href;
} catch (e) {
//If chrome use ancestor origin array
let aOrigins = window.location.ancestorOrigins;
//Get last origin which is top-domain (chrome only):
sBestPageUrl = aOrigins[aOrigins.length - 1];
}
} catch (e) {
sBestPageUrl = topFrame.document.referrer;
}
}
return sBestPageUrl;
};
// To get page URL, simply run following within an iframe on the page:
const TOPFRAMEOBJ = getClosestTop();
const PAGE_URL = getBestPageUrl(TOPFRAMEOBJ);
If anybody would like the code in standard ES5, let me know, or simply run it through a converter online.
Definitely not possible without communicating with some sort of external system. The cleanest/most accurate way to gather data is to get the top window URL if the browser lets you, but catch errors and use the referer with a flag to note it's the referer.
I'm currently trying to build a firefox extension that determines a proxy for each http request based on Regular Expressions. The Proxy that has been used for loading a page should be remembered for any new request coming from that page, ie. any image/script/css file needed for that page, any outgoing links or ajax requests. That also means that the proxy needs to be remembered for each open tab.
This is where I run into my problem: Up until now I tried to mark each open tab by inserting a unique id as an attribute of the browser element of the tab, and looking for this id in an implementation of the shouldLoad() method of nsiContentPolicy. The code I'm using for this is shown below, and it was extracted from the addon sdk's getTabForContentWindow method in tabs/utils.js.
shouldLoad: function(contentType, contentLocation, requestOrigin, context, mimeTypeGuess, extra)
{
var tabId = null;
if (!(context instanceof CI.nsIDOMWindow))
{
// If this is an element, get the corresponding document
if (context instanceof CI.nsIDOMNode && context.ownerDocument)
context = context.ownerDocument;
// Now we should have a document, get its window
if (context instanceof CI.nsIDOMDocument)
context = context.defaultView;
else
context = null;
}
let browser;
try {
browser = context.QueryInterface(CI.nsIInterfaceRequestor)
.getInterface(CI.nsIWebNavigation)
.QueryInterface(CI.nsIDocShell)
.chromeEventHandler;
} catch(e) {
this.console.log(e);
}
let chromeWindow = browser.ownerDocument.defaultView;
if ('gBrowser' in chromeWindow && chromeWindow.gBrowser &&
'browsers' in chromeWindow.gBrowser) {
let browsers = chromeWindow.gBrowser.browsers;
let i = browsers.indexOf(browser);
if (i !== -1)
tabId = chromeWindow.gBrowser.tabs[i].getAttribute("PMsMark");
}
return CI.nsIContentPolicy.ACCEPT;
}
This works fine for any load that does not change the displayed document, but as soon as the document is changed(ie. a new page is loaded), the variable browser is null.
I have looked at the other mechanisms for intercepting page loads described on https://developer.mozilla.org/en-US/Add-ons/Overlay_Extensions/XUL_School/Intercepting_Page_Loads , but those seem to be unsuitable for what I want to achieve, because as far as I understand they work on HTTP requests, and for a request to exist, the proxy already needed to be determined.
So, if anybody knows a way to catch imminent loads before they become requests, and at the same time, it's possible to find out which tab is responsible for those loads-to-be, I'd be glad if they could let me know in the answers! Thanks in advance!
https://developer.mozilla.org/en-US/docs/Code_snippets/Tabbed_browser#Getting_the_browser_that_fires_the_http-on-modify-request_notification
Components.utils.import('resource://gre/modules/Services.jsm');
Services.obs.addObserver(httpObs, 'http-on-opening-request', false);
//Services.obs.removeObserver(httpObs, 'http-on-modify-request'); //uncomment this line, or run this line when you want to remove the observer
var httpObs = {
observe: function (aSubject, aTopic, aData) {
if (aTopic == 'http-on-opening-request') {
/*start - do not edit here*/
var oHttp = aSubject.QueryInterface(Components.interfaces.nsIHttpChannel); //i used nsIHttpChannel but i guess you can use nsIChannel, im not sure why though
var interfaceRequestor = oHttp.notificationCallbacks.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
//var DOMWindow = interfaceRequestor.getInterface(Components.interfaces.nsIDOMWindow); //not to be done anymore because: https://developer.mozilla.org/en-US/docs/Updating_extensions_for_Firefox_3.5#Getting_a_load_context_from_a_request //instead do the loadContext stuff below
var loadContext;
try {
loadContext = interfaceRequestor.getInterface(Components.interfaces.nsILoadContext);
} catch (ex) {
try {
loadContext = aSubject.loadGroup.notificationCallbacks.getInterface(Components.interfaces.nsILoadContext);
//in ff26 aSubject.loadGroup.notificationCallbacks was null for me, i couldnt find a situation where it wasnt null, but whenever this was null, and i knew a loadContext is supposed to be there, i found that "interfaceRequestor.getInterface(Components.interfaces.nsILoadContext);" worked fine, so im thinking in ff26 it doesnt use aSubject.loadGroup.notificationCallbacks anymore, but im not sure
} catch (ex2) {
loadContext = null;
//this is a problem i dont know why it would get here
}
}
/*end do not edit here*/
/*start - do all your edits below here*/
var url = oHttp.URI.spec; //can get url without needing loadContext
if (loadContext) {
var contentWindow = loadContext.associatedWindow; //this is the HTML window of the page that just loaded
//aDOMWindow this is the firefox window holding the tab
var aDOMWindow = contentWindow.top.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIWebNavigation).QueryInterface(Ci.nsIDocShellTreeItem).rootTreeItem.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow);
var gBrowser = aDOMWindow.gBrowser; //this is the gBrowser object of the firefox window this tab is in
var aTab = gBrowser._getTabForContentWindow(contentWindow.top); //this is the clickable tab xul element, the one found in the tab strip of the firefox window, aTab.linkedBrowser is same as browser var above //can stylize tab like aTab.style.backgroundColor = 'blue'; //can stylize the tab like aTab.style.fontColor = 'red';
var browser = aTab.linkedBrowser; //this is the browser within the tab //this is what the example in the previous section gives
//end getting other useful stuff
} else {
Components.utils.reportError('EXCEPTION: Load Context Not Found!!');
//this is likely no big deal as the channel proably has no associated window, ie: the channel was loading some resource. but if its an ajax call you may end up here
}
}
}
};
I'm using the Firefox Addon SDK to build something that monitors and displays the HTTP traffic in the browser. Similar to HTTPFox or Live HTTP Headers. I am interested in identifying which tab in the browser (if any) generated the request
Using the observer-service I am monitoring for "http-on-examine-response" events. I have code like the following to identify the nsIDomWindow that generated the request:
const observer = require("observer-service"),
{Ci} = require("chrome");
function getTabFromChannel(channel) {
try {
var noteCB= channel.notificationCallbacks ? channel.notificationCallbacks : channel.loadGroup.notificationCallbacks;
if (!noteCB) { return null; }
var domWin = noteCB.getInterface(Ci.nsIDOMWindow);
return domWin.top;
} catch (e) {
dump(e + "\n");
return null;
}
}
function logHTTPTraffic(sub, data) {
sub.QueryInterface(Ci.nsIHttpChannel);
var ab = getTabFromChannel(sub);
console.log(tab);
}
observer.add("http-on-examine-response", logHTTPTraffic);
Mostly cribbed from the documentation for how to identify the browser that generated the request. Some is also taken from the Google PageSpeed Firefox addon.
Is there a recommended or preferred way to go from the nsIDOMWindow object domWin to a tab element in the SDK tabs module?
I've considered something hacky like scanning the tabs list for one with a URL that matches the URL for domWin, but then I have to worry about multiple tabs having the same URL.
You have to keep using the internal packages. From what I can tell, getTabForWindow() function in api-utils/lib/tabs/tab.js package does exactly what you want. Untested code:
var tabsLib = require("sdk/tabs/tab.js");
return tabsLib.getTabForWindow(domWin.top);
The API has changed since this was originally asked/answered...
It should now (as of 1.15) be:
return require("sdk/tabs/utils").getTabForWindow(domWin.top);
As of Addon SDK version 1.13 change:
var tabsLib = require("tabs/tab.js");
to
var tabsLib = require("sdk/tabs/helpers.js");
If anyone still cares about this:
Although the Addon SDK is being deprecated in support of the newer WebExtensions API, I want to point out that
var a_tab = require("sdk/tabs/utils").getTabForContentWindow(window)
returns a different 'tab' object than the one you would typically get by using
worker.tab in a PageMod.
For example, a_tab will not have the 'id' attribute, but would have linkedPanel property that's similar to the 'id' attribute.
I need to extend firebug to use the link extracted from the webpage(when a download from any link in the page is initiated) to send it to another machine where it will be downloaded. I was planning to use firebug to extract this link for me. If there is any other way I can get this information from the browser, even that would be appreciated.
Typo in above answer observer service call should read: Components.classes["#mozilla.org/observer-service;1"] .getService(Components.interfaces.nsIObserverService);
Reference for Observer Service usage: https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsIObserverService
actually, its bad idea to use events to detect things like http requests,the power of firefox xul language gives you the ability to detect the all browsers requests/response then you can decide what links you need from the request/response header:
you can use "http-observe" witch actually Firebug use for the net panel
- here is the link for "http-observe" in mozilla MDN [https://developer.mozilla.org/en/Setting_HTTP_request_headers][1]
- also here is a simple example for "http-observe"
// first create observerService component as a property into your extension javascript object
var myExtension = { observerService:Components.classes["#mozilla.org/observerservice;1"].getService(Components.interfaces.nsIObserverService),
init:function(){
// in the init function setup the observe service and set witch javascript object is the listener for http response for example "this"
this.observerService.addObserver(this,"http-on-examine-response", false);
this.observerService.addObserver(this,"http-on-examine-cached-response", false);
},
observe: function(aSubject, aTopic, aData){ // the observe function
if (aTopic == "http-on-examine-response" || aTopic == "http-on-examine-cached-response"){
var httpChannel = aSubject.QueryInterface(Components.interfaces.nsIHttpChannel);
var URI = httpChannel.originalURI.spec;
if (aSubject.loadFlags & httpChannel.LOAD_INITIAL_DOCUMENT_URI){ // this detect if the response is primery request
var contentType = httpChannel.getResponseHeader("content-type"); // check the heder content-type
if (contentType == "what ever you want"){ // you can check if it zip/html/xml ...etc
//do what ever you want
}
}
}
}
}