How to read/intercept JavaScript on the page before it is executed?

I would like to intercept location.reload(); via a Firefox API or by reading the JS on the page (remote & embedded) before it is loaded/executed or by any other means possible.

Example:

<head>
    <script>
        window.setTimeout(function() { location.reload(); }, 10000);
    </script>
</head>

I have tried beforescriptexecute event listener (via GreaseMonkey & // @run-at document-start) but it is fired AFTER above is executed.

beforescriptexecute works nicely on REMOTE scripts since the event beforescriptexecute is fired before making the request (but then on the script src and not script content). It is different if the script is within normal script tag (and not remote), as per the example given. The beforescriptexecute fires and the script content can be rewritten but by then the window.setTimeout() has already fired and it is executing.


Another approach would be to verify whether a reload was initiated by the user (F5, refresh button etc in bowser scope) or via JavaScript on page-content scope.

1 Like

I’m not sure what GreaseMonkey is doing but normally you would register an observer for the content-document-global-created notification. If you want to be E10S-compatible then you need to do this from a process script. If you register your beforescriptexecute handler from that notification then it should run before any page scripts get to run.

I’m mostly certain that Add-on SDK will do as well, via page-mod module with contentScriptWhen: "start". From what I remember, the Add-on SDK does exactly what I explain above.

Thank you :slight_smile:

Initially, I would like to find a way to override location.reload(); of the page/window (if existed).

Reading and altering the page JavaScript is an option but that can become very tricky and slow if there are large libraries involved.

Possible routes would be one of the followings:

  1. Override location.reload(); function
  2. Listen to reload e.g. onLocationChange) and check if that was originated from Page content scope JavaScript or user-action or browser scope
  3. Listen to beforeunload and check the origin of unload

I am open to suggestions. :slightly_smiling:

Problem is, I don’t think any of the high-level APIs will give you sufficient information to recognize specifically location.reload() as opposed to assigning to location.href for example. Browser code will call nsIWebNavigation methods one way or another, the load flags here don’t have the necessary information however.

I tried to re-assign window.location.reload but I get an error: TypeError: "reload" is read-only

Indeed, that property isn’t configurable - meaning that you cannot replace it.

However, turned out that Gecko indeed stores whether something is a regular load, reload or replace (see http://mxr.mozilla.org/mozilla-central/source/docshell/base/nsIDocShellLoadInfo.idl#56).

I was wrong, there is nsIDocShell.loadType. So you can check the following:

var docShell = window.QueryInterface(Ci.nsIInterfaceRequestor)
                     .getInterface(Ci.nsIWebNavigation)
                     .QueryInterface(Ci.nsIDocShell);
alert(docShell.loadType);

The lower 16 bits are load types, the upper 16 bits represent the load flags. This way you could indeed recognize reloads, both triggered by content and by the user. Problem is, I guess that the docShell info only changes after the load starts - onLocationChange will fire too early. Also, you would still need a way to recognize reloads triggered by the user, nsIWebNavigation.reload() doesn’t seem to care who called it. This will most likely mean observing Browser:Reload and context-reload elements in the browser document.

No easy solutions for what you have in mind.

Great… Thank you Wladimir

I will read on what you have said and see how far I can get. :slightly_smiling:

From onLocationChange whatever I do, load, reload, refresh, F5 etc… I get loadType = 2

What does loadType 2097153 or 8388609 mean?

I also tried windowUtils.isHandlingUserInput but it was false all the time.

I just overrid the location.reload in a sense.

I setup a webprogress listener and onStateChange i abort the request on STATE_START and then on STATE_STOP I do webProgress.DOMWindow.location = 'what i want'.

So to ensure its a reload you would check for STATE_START and also LOCATION_CHANGE_SAME_DOCUMENT.

1 Like

Thank you @noitidart

I had looked into similar approaches. The problem was to differentiate between user initiated action and content JS initiated action.

The webProgress listener can notify of reload but cant say if the user clicked reload button, or click F5 etc and I couldn’t find a way to find out. :frowning: