Making cross domain JavaScript requests using XMLHttpRequest or XDomainRequest

12 Mar 2010

Cross domain requests (also known as Cross Origin Resource Sharing) can be made using JavaScript without trickery, as far as I can tell, in Firefox 3.5, Safari, Google Chrome and Internet Explorer 8. This is done with all browsers except IE8 using a standard XMLHttpRequest object. The only thing required to notify the browser that JavaScript is allowed to make this request is for the server to send a Access-Control-Allow-Origin response header. Internet Explorer 8 uses an object called XDomainRequest and requires the same HTTP header. If the value of the header is * then requests are allowed from all domains. You can be more restrictive if required.

I took the code that I'll use below from this CORS in action page but I couldn't find the code required to make this work in Internet Explorer so I've had to modify things a bit.

See it in action

The information below (when it appears) has been fetched using cross-site XHR.

The code

<script>
  var isIE8 = window.XDomainRequest ? true : false;
  var invocation = createCrossDomainRequest();
  var url = 'http://www.phobos7.co.uk/research/xss/simple.php';
  function createCrossDomainRequest(url, handler) {
    var request;
    if (isIE8) {
      request = new window.XDomainRequest();
      }
      else {
        request = new XMLHttpRequest();
      }
    return request;
  }

  function callOtherDomain() {
    if (invocation) {
      if(isIE8) {
        invocation.onload = outputResult;
        invocation.open("GET", url, true);
        invocation.send();
      }
      else {
        invocation.open('GET', url, true);
        invocation.onreadystatechange = handler;
        invocation.send();
      }
    }
    else {
      var text = "No Invocation TookPlace At All";
      var textNode = document.createTextNode(text);
      var textDiv = document.getElementById("textDiv");
      textDiv.appendChild(textNode);
    }
  }

  function handler(evtXHR) {
    if (invocation.readyState == 4)
    {
      if (invocation.status == 200) {
          outputResult();
      }
      else {
        alert("Invocation Errors Occured");
      }
    }
  }

  function outputResult() {
    var response = invocation.responseText;
    var textDiv = document.getElementById("textDiv");
    textDiv.innerHTML += response;
  }
</script>
<form id="controlsToInvoke" action="">
    <p>
        <input type="button" value="Click to Invoke Another Site" onclick="callOtherDomain()" />
    </p>
</form>
<div id="textDiv">
    The information below (when it appears) has been fetched using cross-site XHR.
</div>

And this is the code on the server

<?php
  header('Content-type: text/html');
  header('Access-Control-Allow-Origin: *');
  $uri = 'http'. ($_SERVER['HTTPS'] ? 's' : null) .'://'. $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
  echo('<p>This information has come from <a href="' . $uri . '">' . $uri . '</a></p>');