Attempting to track the number of outstanding AJAX requests in Firefox

I use Selenium to test a web application, and I am not allowed to modify the javascript code of the application. I am trying to track the number of outstanding AJAX requests using GreaseMonkey to override XMLHttpRequest.send. The new send () function will basically wrap what was set as the onreadystatechange callback, check for readiness, increment or decrement the counter, if necessary, and call the callback function.

The problem I am facing is a privilege problem, because if I just go to the page in a regular Firefox browser, open firebug and paste the following code, it seems to work fine:

document.ajax_outstanding = 0; if (typeof XMLHttpRequest.prototype.oldsend != 'function') { XMLHttpRequest.prototype.oldsend = XMLHttpRequest.prototype.send; XMLHttpRequest.prototype.send = function() { console.log('in new send'); console.log('this.onreadystatechange = ' + this.onreadystatechange); this.oldonreadystatechange = this.onreadystatechange; this.onreadystatechange = function() { if (this.readyState == 2) { /* LOADED */ document.ajax_outstanding++; console.log('set ajax_outstanding to ' + document.ajax_outstanding); } this.oldonreadystatechange.handleEvent.apply(this, arguments); if (this.readyState == 4) { /* COMPLETED */ document.ajax_outstanding--; console.log('set ajax_outstanding to ' + document.ajax_outstanding); } }; this.oldsend.apply(this, arguments); }; } 

Now, if I use a slightly modified version of this snippet from a GreaseMonkey user script as follows:

 unsafeWindow.document.ajax_outstanding = 0; if (typeof unsafeWindow.XMLHttpRequest.prototype.oldsend != 'function') { unsafeWindow.XMLHttpRequest.prototype.oldsend = unsafeWindow.XMLHttpRequest.prototype.send; unsafeWindow.XMLHttpRequest.prototype.send = function() { GM_log('in new send'); GM_log('this.onreadystatechange = ' + this.onreadystatechange); this.oldonreadystatechange = this.onreadystatechange; this.onreadystatechange = function() { if (this.readyState == 2) { /* LOADED */ unsafeWindow.document.ajax_outstanding++; GM_log('set ajax_outstanding to ' + unsafeWindow.document.ajax_outstanding); } this.oldonreadystatechange.handleEvent.apply(this, arguments); if (this.readyState == 4) { /* COMPLETED */ unsafeWindow.document.ajax_outstanding--; GM_log('set ajax_outstanding to ' + unsafeWindow.document.ajax_outstanding); } }; this.oldsend.apply(this, arguments); }; } 

and I go to the page, do something that triggers the AJAX request, I get the following message in the javascript error console:

 http://www.blah.com/gmscripts/overrides: in new send uncaught exception: [Exception... "Illegal value" nsresult: "0x80070057 (NS_ERROR_ILLEGAL_VALUE)" location: "JS frame :: file:///tmp/customProfileDir41e7266f56734c97a2ca02b1f7f528e1/extensions/%7Be4a8a97b-f2ed-450b-b12d-ee082ba24781%7D/components/greasemonkey.js :: anonymous :: line 372" data: no] 

So this seems to throw an exception when trying to access this.onreadystatechange

Presumably, this is due to an isolated environment. Any help would be greatly appreciated. I am not attached to this decision, so any other suggestions in order to do what I need are welcome. It is just that I tried several others, and it seems the most promising. The requirement is that I need to make sure that the counter reaches 0 after the ReadyState goes to 4 and the onreadystatechange callback completes the execution.

+6
javascript firefox greasemonkey sandbox
source share
2 answers

I did something myself: http://jsfiddle.net/rudiedirkx/skp28agx/ (updated January 22, 2015)

script (should be run first):

 (function(xhr) { xhr.active = 0; var pt = xhr.prototype; var _send = pt.send; pt.send = function() { xhr.active++; this.addEventListener('readystatechange', function(e) { if ( this.readyState == 4 ) { setTimeout(function() { xhr.active--; }, 1); } }); _send.apply(this, arguments); } })(XMLHttpRequest); 

And the jsFiddle script test:

 window.onload = function() { var btn = document.querySelector('button'), active = btn.querySelector('span'); btn.onclick = function() { // jQuery for easy ajax. `delay` is a jsFiddle argument // to keep some requests active longer. jQuery.post('/echo/json/', { delay: Math.random() * 3, }); }; updateActive(); function updateActive() { active.textContent = XMLHttpRequest.active; requestAnimationFrame(updateActive); } }; 

It updates the counter in each frame of the animation (~ 60 times per second), separately from AJAX requests. Regardless of what you do, however, you press it fast and hard, the counter should always end at 0 after a few seconds.

+3
source share

I ended up using the following:

 unsafeWindow.document.ajax_outstanding = 0; if (typeof unsafeWindow.XMLHttpRequest.prototype.oldsend != 'function') { unsafeWindow.XMLHttpRequest.prototype.oldsend = unsafeWindow.XMLHttpRequest.prototype.send; unsafeWindow.XMLHttpRequest.prototype.send = function() { unsafeWindow.XMLHttpRequest.prototype.oldsend.apply(this, arguments); this.addEventListener('readystatechange', function() { if (this.readyState == 2) { /* LOADED */ unsafeWindow.document.ajax_outstanding++; console.log('set ajax_outstanding to ' + unsafeWindow.document.ajax_outstanding); } else if (this.readyState == 4) { /* COMPLETED */ unsafeWindow.document.ajax_outstanding--; console.log('set ajax_outstanding to ' + unsafeWindow.document.ajax_outstanding); } }, false); }; } 
+1
source share

All Articles