I have an angularjs application running on tomcat, and behind a loadbalancer
If the app is requested via the loadbalancer with https, the balancer still requests the application internally via http, of course.
Problem: I'd like to hide one tab that shows mixed content in this case (because I have to embed external pdf links which do not support https, thus I'd like to hide them).
I cannot use $location.protocol() because the app is behind the loadbalancer and always only gets http.
Question: is there a chance I could detect if the browser is actually showing mixed content?
You can't detect it in the simple way. You can try to listen load event on iframe and set timeout, and when timeout triggered, block iframe because iframe didn't loaded like this (jsfiddle example):
checkMixedContent(urlToCheck, function(urlToCheck) {
// For example, change location
alert('ok');
// load iframe
}, function() {
alert('Error: resource timed out');
// hide iframe / show message
}, checkDelay);
function checkMixedContent(urlToCheck, successCallback, errorCallback, checkDelay, dontCheckOnError) {
checkDelay = checkDelay || 10000;
// 1. Create invisible iframe and append it to body
var iframeHelper = document.createElement("iframe");
iframeHelper.src = urlToCheck;
iframeHelper.height = 0;
iframeHelper.width = 0;
iframeHelper.style.visibility = 'hidden';
document.body.appendChild(iframeHelper);
// 2. Set time out and while content on iframeHelper.src should be definitely loaded
var checkTimeout = window.setTimeout(function() {
errorCallback(urlToCheck);
}, checkDelay);
var onLoad = function() {
window.clearTimeout(checkTimeout); // if OK - not show error => clearTimeout
iframeHelper.removeEventListener('load', onLoad);
iframeHelper.removeEventListener('error', onError);
document.body.removeChild(iframeHelper);
successCallback(urlToCheck);
};
var onError = function() {
window.clearTimeout(checkTimeout); // if OK - not show error => clearTimeout
iframeHelper.removeEventListener('load', onLoad);
iframeHelper.removeEventListener('error', onError);
document.body.removeChild(iframeHelper);
errorCallback(urlToCheck);
};
// 3. If everything is fine - "load" should be triggered
iframeHelper.addEventListener('load', onLoad);
// Turn "true" in case of "X-Frame-Options: SAMEORIGIN"
if (!dontCheckOnError) {
iframeHelper.addEventListener('error', onError);
}
}
Related
I have a userscript that refreshes the page every second, but sometimes the website it's trying to refresh runs into the status 503 error, and that stops the script from running anymore. That means that script will no longer try refresh the page every second. How do I keep the script running after the page runs into the status 503 error? The error looks like this in the console:
Failed to load resource: the server responded with a status of 503 (Service Unavailable)
// ==UserScript==
// #name script
// #namespace name
// #description example
// #match *^https://example.com/$*
// #version 1
// #require https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js
// #grant GM_xmlhttpRequest
// #run-at document-end
// ==/UserScript==
//*****************************************START OF SET_TIMEOUT
var timeOne = 1000;
var theTime = timeOne;
var timeout = setTimeout("location.reload(true);", theTime);
function resetTimeout() {
clearTimeout(timeout);
timeout = setTimeout("location.reload(true);", theTime);
} //end of function resetTimeout()
//*****************************************END OF SET_TIMEOUT
The user-script run at page load, they won't run if page does not load at all for any status code other than 200. You can use <iframe> as #Hemanth suggested but you have to break the infinite loop as the <iframe> will also load the user-script and so on. To break it just check if the user-script is loaded on the top window.
if (window == window.top) {
// Remove everything from the page
// Add an iframe with current page URL as it's source
// Add an event to reload the iframe few seconds after it is loaded
}
Complete Code:
(function ($) {
'use strict';
var interval = 5000;
if (window == window.top) {
var body = $('body').empty();
var myframe = $('<iframe>')
.attr({ src: location.href })
.css({ height: '95vh', width: '100%' })
.appendTo(body)
.on('load', function () {
setTimeout(function () {
myframe.attr({ src: location.href });
}, interval);
});
}
})(jQuery);
Simple solution I could think of is to move the actual webpage that need to be refreshed every second to another frame or some HTML container and using your user script you could refresh or reload that container with the HTML page you want to refresh.
Unless you are making a http request to load webpage from your script it may not be possible to handle the http errors (I might be wrong!). Your user script should be at a superset level where it will have control or scope even after any 503 or any similar HTTP errors.
You could use Page state change events to ensure or to check to refresh the page in the frame/container has loaded or not to avoid reloading the webpage before it loads. Unless if you want to reload irrespective of webpage successfully loaded or not.
Hope this helps..
The problem is that location.reload attempts to completely replace the page with a reloaded version, but if the browser fails to connect to the server, the page will not be loaded, and any userscripts for that page will fail to run, because there's no page for them to run on.
A workaround would be to use a Javascript network request to fetch the text of the new page, and then replace the existing content with the new content with Javascript - if the response is a 503 error (or some other error), you can simply ignore it and try again. This ensures that you'll always stay on the same (loaded) page, so the userscript will continue running indefinitely, even if the responses sometimes fail.
Here's an example of a userscript that updates StackOverflow's homepage every 10 seconds with new HTML. You can use DOMParser to transform response text into a document that can be navigated with querySelector, among other things:
// ==UserScript==
// #name Update SO
// #namespace CertainPerformance
// #version 1
// #match https://stackoverflow.com/
// #grant none
// ==/UserScript==
const container = document.querySelector('.container');
function getNewData() {
console.log('getting new data');
fetch('https://stackoverflow.com',
{
// The following is needed to include your existing cookies with the request, which may be needed:
credentials: "same-origin"
})
.then((resp) => {
// If there are errors, such as a 503 error, proceed directly to the `finally` to try again:
if (!resp.ok) return;
return resp.text();
})
.then((text) => {
const doc = new DOMParser().parseFromString(text, 'text/html');
container.innerHTML = doc.querySelector('.container').innerHTML;
})
.finally(() => {
// Whether there was an error or not, try to refresh again in a few seconds:
setTimeout(getNewData, 10000);
});
}
setTimeout(getNewData, 10000);
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 have a content script which times how long a user views a page. To do this, I inject a content script into each page, start a timer and then emit a message back to the add-on when the onbeforeunload event is triggered.
The message never seems to get passed to the background script however.
Given that my main.js looks like this:
var pageMod = require('page-mod'),
self = require("self");
pageMod.PageMod({
include: "http://*",
contentScriptFile: [self.data.url('jquery.min.js'),
self.data.url('content.js')],
onAttach: function(worker) {
worker.port.on('pageView', function(request) {
console.log("Request received");
});
}
});
I can send a message to main.js using the following code no problem.
self.port.emit('pageView', { visitTime: time });
I run into a problem when I try to do it as the user leaves the page however. The message is never received when I do it like this:
$(window).bind('onbeforeunload', function(e) {
self.port.emit('pageView', { visitTime: time });
// This should prevent the user from seeing a dialog.
return undefined;
});
I've tried listening for beforeunload too, that doesn't work either. What could be the problem?
The window object that content scripts access in Firefox browser add-ons is a proxy object and can be a little temperamental. Using window.addEventListener will work.
window.addEventListener('beforeunload', function(e) {
# Do stuff then return undefined so no dialog pops up.
return undefined
});
The onbeforeUnload event is not synchronous, so the browser garbage collects the page before it is finished. Use a synchronous AJAX request:
function Data()
{
var client = new XMLHttpRequest();
client.open("GET", "/request", false); // third paramater indicates sync xhr
client.setRequestHeader("Content-Type", "text/plain;charset=UTF-8");
client.send({ visitTime: time });
client.onreadystatechange = emitter;
}
function emitter()
{
self.port.emit('pageView', { visitTime: time });
}
or return a string as an alternative.
I'm trying to create a firefox addon that will look for a certain page on startup and grab some info from it. I'm having trouble finding the page at load. Here's what I have so far:
var myfancyaddon = {
onLoad: function() {
var observerService = Components.classes["#mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
observerService.addObserver(function restored() {
observerService.removeObserver( restored, "sessionstore-windows-restored");
var browser = myfancyaddon.findMySite();
if (browser) {
alert("tree falling in the woods"); // THIS LINE NEVER RUNS
browser.contentWindow.addEventListener("load", function tab_loaded(){
browser.contentWindow.removeEventListener("load", tab_loaded(), false);
alert("mysite loaded!");
}, false);
}
}, "sessionstore-windows-restored", false);
},
findMySite: function() {
var browsers = gBrowser.browsers;
for ( var i = 0; i < browsers.length; i++ ) {
var browser = browsers[i];
if (!browser.currentURI.spec) continue;
if ( browser.currentURI.spec.match('^https?://(www\.)?mysite\.com/') ) return browser;
}
return null;
}
};
window.addEventListener("load", function ff_loaded(){
window.removeEventListener("load", ff_loaded, false); //remove listener, no longer needed
myfancyaddon.onLoad();
},false);
after some investigation it seems the currentURI.spec is "about:blank" for a short time before it becomes mysite.com. Any ideas?
Instead of filtering first and then adding the load listener, you could use gBrowser.addEventListener("DOMContentLoaded", myfunction, false); to listen for page loads on all tab documents and then only run your code based on the url.
https://developer.mozilla.org/en/XUL_School/Intercepting_Page_Loads
The "sessionstore-windows-restored" notification is sent when the tabs from the previous session have been restored and the loading in these tabs has been started (sometimes: "Don't load tabs until selected" option means that the load isn't even started in the background tabs). But the location of these tabs is still about:blank until the server is contacted because the address loaded might redirect or the server might be unreachable (meaning an internal redirect to about:neterror). Firefox only changes browser location when content is definitely being served from the new location.
It should be indeed better to intercept page loads rather than waiting for session restore.
I am quite new to Firefox and its extensions. Is there something like a script using JavaScript that runs every time a page loads? My chrome extension injects a css file creating a link tag using js. How do I port this to Firefox?
You want the pageMod API.
var pageMod = require("page-mod");
pageMod.PageMod({
include: "*.example.org",
contentScript: 'window.alert("Page matches ruleset");'
});
You can use mozIJSSubScriptLoader to execute the JavaScript (chrome://myExtension/content/script.js) every time a webpage loads. Here is the sample code that you need to modify according to your chrome directory
window.addEventListener("load", function load(event){
window.removeEventListener("load", load, false); //remove listener, no longer needed
myExtension.init();
},false);
var myExtension = {
init: function() {
var appcontent = document.getElementById("appcontent"); // browser
if(appcontent){
appcontent.addEventListener("DOMContentLoaded", myExtension.onPageLoad, true);
}
var messagepane = document.getElementById("messagepane"); // mail
if(messagepane){
messagepane.addEventListener("load", function(event) { myExtension.onPageLoad(event); }, true);
}
},
onPageLoad: function(aEvent) {
var doc = aEvent.originalTarget; // doc is document that triggered "onload" event
// do something with the loaded page.
// doc.location is a Location object (see below for a link).
// You can use it to make your code executed on certain pages only.
var loader = Components.classes["#mozilla.org/moz/jssubscript-loader;1"].getService(Components.interfaces.mozIJSSubScriptLoader);
loader.loadSubScript("chrome://myExtension/content/script.js", doc);
// add event listener for page unload
aEvent.originalTarget.defaultView.addEventListener("unload", function(event){ myExtension.onPageUnload(event); }, true);
},
onPageUnload: function(aEvent) {
// do something
}
};
I used to use Greasemonkey on Firefox. In fact, Chrome Extensions began as a mimic of Greasemonkey, and were the origin of content scripts.