Is it possible, having the ability to change (inject) XMLHttpRequest, to change it so that it is possible to intercept the contents of the response without replacing the entire object with all its methods?
It is assumed that further in the code there will be calls like:

x = new XMLHttpRequest(); x.open( "GET", "/" ); x.onreadystatechange = function () {...}; x.send( null ); 

or even with single threading:

 x = new XMLHttpRequest(); x.open( "GET", "/" ); x.send( null ); x.onreadystatechange = function () {...}; 
  • if you look at onreadystatechange, this is the object method, not the prototype method - Grundy
  • where did you see onreadystatechange [native] ? - Grundy
  • in fact, there it is somehow all very interestingly arranged :-) I will try to sort it out in the evening - Grundy

1 answer 1

Blink Solution

Blink is Chrome, Opera etc.

In the XMLHttpRequest prototype, onreadystatechange declared as a getter / setter, and by specifying your getter / setter you need not to break the XMLHttpRequest operation logic:

 var oldXMLHttpRequest = XMLHttpRequest; XMLHttpRequest = function() { var xhr = new oldXMLHttpRequest(); // получаем дескриптор прототипных setter/getter var descrGetSet = Object.getOwnPropertyDescriptor( Object.getPrototypeOf( xhr ), "onreadystatechange" ); var newSet = function( val ) { console.log ( "setter" ); descrGetSet.set.call( xhr, function() { // прототипный setter console.log( "Inject "+this.status ); // this.responseText return val.apply( xhr, arguments ); } ); } Object.defineProperty( xhr, "onreadystatechange", { set: newSet, // новый setter get: descrGetSet.get // старый getter } ); return xhr; } 

Now do:

 x = new XMLHttpRequest(); x.open( "GET", "/" ); x.send( null ) x.onreadystatechange = function () { console.log( this.statusText+' is 2' )}; 

Will see

 Inject 200 OK is 2 Inject 200 OK is 2 Inject 200 OK is 2 

What should be when changing the readyState .


Webkit Solution

Webkit - Safari, PhantomJS

The problem in this engine — onreadystatechange is the getter / setter of the XHR object, not XHR.prototype . As a result, you cannot override it. Inheriting from XHR also impossible, so you need to use a wrapper for XHR .
This wrapper is quite good:
https://github.com/ilinsky/xmlhttprequest