Edit: see the second version of the code below (it is tested and working). The first has some limitations.
Since you cannot change any of these functions, it seems to you that you need to go after the XMLHttpRequest prototype. Here is one idea (untested, but you can see the direction):
(function() { var open = XMLHttpRequest.prototype.open; XMLHttpRequest.prototype.open = function(method, url, async, user, password) { var oldReady; if (async) { oldReady = this.onreadystatechange; // override onReadyStateChange this.onreadystatechange = function() { if (this.readyState == 4) { // this.responseText is the ajax result // create a dummay ajax object so we can modify responseText var self = this; var dummy = {}; ["statusText", "status", "readyState", "responseType"].forEach(function(item) { dummy[item] = self[item]; }); dummy.responseText = '{"msg": "Hello"}'; return oldReady.call(dummy); } else { // call original onreadystatechange handler return oldReady.apply(this, arguments); } } } // call original open method return open.apply(this, arguments); } })();
This makes the monkey patch for the XMLHttpRequest open() method, and then when it is called for the async request, it executes the monkey patch for the onReadyStateChange handler, since it must already be installed. This fixed function will then see the Text response before the onReadyStateChange handler is called so that it can assign it a different value.
And finally, since .responseText is only ready, it replaces the dummy XMLHttpResponse object before onreadystatechange handler. This will not work in all cases, but will work if the onreadystatechange handler uses this.responseText to get the response.
And here is an attempt that overrides the XMLHttpRequest object as our own proxy object. Since this is our own proxy object, we can set the responseText property to whatever we want. For all properties other than onreadystatechange , this object simply redirects the call to get, set, or function to the actual XMLHttpRequest object.
(function() { // create XMLHttpRequest proxy object var oldXMLHttpRequest = XMLHttpRequest; // define constructor for my proxy object XMLHttpRequest = function() { var actual = new oldXMLHttpRequest(); var self = this; this.onreadystatechange = null; // this is the actual handler on the real XMLHttpRequest object actual.onreadystatechange = function() { if (this.readyState == 4) { // actual.responseText is the ajax result // add your own code here to read the real ajax result // from actual.responseText and then put whatever result you want // the caller to see in self.responseText // this next line of code is a dummy line to be replaced self.responseText = '{"msg": "Hello"}'; } if (self.onreadystatechange) { return self.onreadystatechange(); } }; // add all proxy getters ["status", "statusText", "responseType", "response", "readyState", "responseXML", "upload"].forEach(function(item) { Object.defineProperty(self, item, { get: function() {return actual[item];} }); }); // add all proxy getters/setters ["ontimeout, timeout", "withCredentials", "onload", "onerror", "onprogress"].forEach(function(item) { Object.defineProperty(self, item, { get: function() {return actual[item];}, set: function(val) {actual[item] = val;} }); }); // add all pure proxy pass-through methods ["addEventListener", "send", "open", "abort", "getAllResponseHeaders", "getResponseHeader", "overrideMimeType", "setRequestHeader"].forEach(function(item) { Object.defineProperty(self, item, { value: function() {return actual[item].apply(actual, arguments);} }); }); } })();
Working demo: http://jsfiddle.net/jfriend00/jws6g691/
I tried it in the latest versions of IE, Firefox, and Chrome, and it worked with a simple ajax request.
Note. I have not considered all the advanced ways in which Ajax (for example, binary data, downloads, etc.) can be used to see that this proxy is thorough enough to make it all work (I would assume it would not be without any further work, but it works for basic queries, so it seems like the concept is capable).
Other unsuccessful attempts:
I tried to output the XMLHttpRequest object and then replace the constructor with my own, but this did not work, because the real XMLHttpRequest function will not allow you to call it as a function to initialize my derived object.
I tried just overriding the onreadystatechange handler and changing the .responseText , but this field is read-only, so you cannot change it.
I tried to create a dummy object that is dispatched as the this object when onreadystatechange called, but a lot of code does not reference this , but rather has the actual object stored in the local variable in closure - thus defeating the dummy object.