javascriptiosajaxchrome-ios

Intercepting AJAX requests on Chrome for iOS?


I intercept AJAX requests in my site by altering the XMLHttpRequest.prototype open and send methods. This method worked without any troubles in all the browsers I tested. However, when it comes to Chrome for iOS (iPhone) the code has the weirdest bug: it's like it continuously fire the code I changed in the prototype (ending up crashing, obviously).

Here's a super-minimal example of what I am doing:

var open = XMLHttpRequest.prototype.open; // Caching the original
XMLHttpRequest.prototype.open = function(method, url, async, user, pass) {
    alert('open'); // Here is my code
    open.call(this, method, url, async, user, pass); // Calling the original
 };

I've assembled a little JSBin doing just that you can visit with your Chrome on iOS: Demo

According to this answer, the code I'm using (essentially the same as the one OP in that answer is going to use) is safe and there should be no reason to worry. And, as a matter of fact, Chrome for iOS is the only browser which behaves weirdly.

This has been driving me nuts for two days, any suggestion or workaround appreciated.


Solution

  • How to Intercept AJAX requests on Chrome for iOS

    This is XMLHttpRequest interception code that works on most browsers:

    (function(open) {
      XMLHttpRequest.prototype.open = function(method, url, async, user, pass) {
        // Intercept the open request here
        alert("Intercepted: " + url);
        open.apply(this, arguments);
      };
    })(XMLHttpRequest.prototype.open);
    
    xmlhttp = new XMLHttpRequest();
    xmlhttp.open("GET","http://google.com",true);
    xmlhttp.send();
    

    There is a problem in Chrome for iOS. It has been raised and investigated below. I will provide an explanation for the "repeated open() calls" bug, a demonstration, and a workaround.

    From the last reference:

    On page load, Chrome makes two asynchronous requests to services that it is presumably running locally. By the sound of the URLs it’s requesting, these services are used to ensure the safety of the page you are accessing.

    And here is a screenshot of one such local URL Chrome is trying to access (Demo):

    Repeated Chrome calls

    Chrome calls XMLHttpRequest.open() periodically on it's own. These repeated calls to the interception code are not caused by the interception code itself; they are caused by unrelated and repeated calls from the Chrome browser. I've identified two such URLs. There may be others.

    From my research, this workaround makes the XMLHttpRequest code interception work on Chrome for iOS. See this JSBin testing demo. It will demonstrate just how these repeated calls come about too. Essentially, the interception code should ignore URLs used by Chrome.

    (function(open) {
      XMLHttpRequest.prototype.open = function(method, url, async, user, pass) {
        var d1 = document.getElementById('urls');
    
        // Avoid intercepting Chrome on iOS local security check urls
        if(url.indexOf("/chromecheckurl") < 0 && url.indexOf("/chrome") !== 0) {
            // These are what we want to intercept
            d1.insertAdjacentHTML('beforeend', '<b>'+url+'</b><br/>');
        } else {
            // These are the internal Chrome requests - we can ignore them
            d1.insertAdjacentHTML('beforeend', '<i>'+url+'</i><br/>');
        }
    
        open.apply(this, arguments);
      };
    })(XMLHttpRequest.prototype.open);
    
    
    xmlhttp = new XMLHttpRequest();
    xmlhttp.open("GET","http://google.com",true);
    xmlhttp.send();
    

    This is my best attempt at an explanation about this "repeated open() calls" bug on Chrome for iOS, and a workaround.