1

I'm writing a Greasemonkey script where I want to overload the XMLHttpRequest.prototype.open function to hijack the Ajax calls on the page.

I'm using the following code:

// ==UserScript==
// @name        name
// @namespace   namespace
// @description desc
// @include     https://url*
// @version     1.0
// ==/UserScript==

if (XMLHttpRequest.prototype) {
    //New Firefox Versions
    XMLHttpRequest.prototype.realOpen = XMLHttpRequest.prototype.open;
    var myOpen = function(method, url, async, user, password) {

        //call original
        this.realOpen (method, url, async, user, password);
        myCode();

    }  
    //ensure all XMLHttpRequests use our custom open method
    XMLHttpRequest.prototype.open = myOpen ;
}


This works well until I start using GM APIs. When I just add the following line to the meta section my code breaks, and myOpen is no longer called:

// @grant       GM_getValue

This could be any GM API really, and my code breaks. Everything else in my script works fine even with the GM APIs, it's just the overload of the XMLHttpRequest.prototype.open function that breaks.

I can kind of workaround it by using waitForKeyElements, however, I don't like it because it slows down the browser due to the interval it uses.

Any ideas why the GM APIs break the overload of the XMLHttpRequest.prototype.open call?

Many thanks,

Peter

Brock Adams
  • 90,639
  • 22
  • 233
  • 295
pondrejk
  • 13
  • 2
  • If you have a case where `waitForKeyElements` really slows down the page, I'd like to see it. (I coded the original waitForKeyElements and want to eliminate bugs and performance issues as much as is, cost-effectively, possible.) – Brock Adams May 23 '13 at 03:23

1 Answers1

0

The @grant directive switches Greasemonkey's sandbox back on -- which it must have to use any of the GM_ functions.

That prototype override would then only affect the script scope, and you want it to affect the page scope. To get around this, you need to inject the override. Like so:

function overrideXhrFunctions () {
    if (XMLHttpRequest.prototype) {
        //New Firefox Versions
        XMLHttpRequest.prototype.realOpen = XMLHttpRequest.prototype.open;
        var myOpen = function(method, url, async, user, password) {

            //call original
            this.realOpen (method, url, async, user, password);
            myCode();
        }
        //ensure all XMLHttpRequests use our custom open method
        XMLHttpRequest.prototype.open = myOpen ;
    }
}

addJS_Node (null, null, overrideXhrFunctions) {

//-- addJS_Node is a standard(ish) function
function addJS_Node (text, s_URL, funcToRun, runOnLoad) {
    var D                                   = document;
    var scriptNode                          = D.createElement ('script');
    if (runOnLoad) {
        scriptNode.addEventListener ("load", runOnLoad, false);
    }
    scriptNode.type                         = "text/javascript";
    if (text)       scriptNode.textContent  = text;
    if (s_URL)      scriptNode.src          = s_URL;
    if (funcToRun)  scriptNode.textContent  = '(' + funcToRun.toString() + ')()';
    var targ = D.getElementsByTagName ('head')[0] || D.body || D.documentElement;
    targ.appendChild (scriptNode);
}


Note that mixing GM_ functions and injected code can get tricky. See "How to use GM_xmlhttpRequest in Injected Code?" for one way to do that.

Community
  • 1
  • 1
Brock Adams
  • 90,639
  • 22
  • 233
  • 295