GM_xmlHttpRequest POST doesn't work in event listener

562 views Asked by At

What I want is really simple: intercept the xmlHttpRequests sent by a page and send them to my local server to log it in a text file. But obviously, Ajax calls don't work in event listeners... I found several solutions and tried, and tried, and tried... Spent my whole day searching for a solution. Here's the code:

var ajaxQueue = [];
var processAjaxQueue = function(){
  if (ajaxQueue.length > 0) {
    for (ajax in ajaxQueue) {
      var obj = ajaxQueue[ajax];
      setTimeOut(function(){GM_xmlhttpRequest(obj);},0);
    }
    ajaxQueue = [];
  }
}
setInterval(function(){
  processAjaxQueue();
}, 100);
function gmAjax(obj){
  ajaxQueue.push(obj);
}

function envoiData(donnees)
{
                setTimeout(function() {gmAjax({
                    method: "POST",
                    url: "http://127.0.0.1/log/index.php",
                    data: "prix="+donnees,
                    headers: {"Content-Type": "application/x-www-form-urlencoded"},
                    onload: function(reponse){alert('Chargé ! '+reponse.responseText);}
                });}, 0);
}

(function(open) {
    XMLHttpRequest.prototype.open = function(method, url, async, user, pass) {
        this.addEventListener("readystatechange", function() {
            console.log(this.readyState);
            if(this.readyState == 4)
            {
                alert(this.responseText);
                envoiData(this.responseText);
        }
        }, false);
        open.call(this, method, url, async, user, pass);
    };
})(XMLHttpRequest.prototype.open);

I really don't get what the problem is. The gmAjax idea comes from a site where the guy says that greasemonkey scripts execute and stop immediately, and therefore using addevent listener is impossible.

I have no error in the error console and my request works when outside the event listener.

Any help appreciated ^^

1

There are 1 answers

0
amakhrov On

The original idea is correct. However, you need to add a couple of things.

  • Add the @run-at document-start meta, so that the loggin started prior to any ajax requests are sent by the page.
  • You need to manipulate with XMLHttpRequest in the actual window scope (unsafeWindow) rather than in the sandbox.

So the resulting code is:

// ==UserScript==
// @run-at document-start
// @grant unsafeWindow
// ==/UserScript==

var unsafe = unsafeWindow;

... // keep your ajax queue code here

var oldOpen = unsafe.XMLHttpRequest.prototype.open;

unsafe.XMLHttpRequest.prototype.open = function(method, url, async, user, pass) {
    this.addEventListener("readystatechange", function() {
        if(this.readyState == 4)
        {
            alert(this.responseText);
            envoiData(this.responseText);
    }
    }, false);
    oldOpen.call(this, method, url, async, user, pass);
};