Taking the Gloves Off XMLHttpRequest

Pow!Remember how the rapid enlightment around the potential of AJAX changed the web, and how swiftly it did so? It was 2004 / 2005, and though XMLHttpRequest had been viable for long before that, it took an advanced implementation of it by a few high profile web apps (notably, Gmail), combined with a meme-friendly naming, followed by swift support by the W3C and the major browsers to set web developers worldwide to work on rebuilding the web to deliver a decidedly more dynamic and desktop-software-like experience.

AJAX has always been hampered by an important restriction: due to the same-orgin policy implemented by the browsers (to prevent cross-site scripting attacks), XMLHttpRequest can only issue requests to resources on the same domain that it orginates from.

But oh what a world it would be if apps were empowered to make http requests to whichever domain they pleased. Recently, thanks to a new W3C standard and some ingenious hacks, the prospect of cross-orgin resource sharing (CORS) is becoming a reality.

Please Share

Please share... Rather than let the threat of XSS attacks prevent us all from enjoying the benefits of cross-site resource sharing, the wise owls at the W3C recently published a recomendation that would allow site publishers to opt-in to cross site requests. And the wise, oh let's say foxes, at the Mozilla foundation incorporated it whole-hog into Firefox 3.5. It's also in Safari 4, Chrome 2, and it may even see some traction in IE 8, though to no one's surprise Microsoft has their own idea about how to implement the standard.

That's not everybody. But someday soon, it may be close enough.

How it Works

CORS capability is established in the http headers. When the browser makes an http request, a compliant browser now includes an "Origin" header that tells the remote site where the request orginated from.

I'm going to use an example from the Mozilla docs to demonstrate. Here's the request in JS:

 

var invocation = new XMLHttpRequest();
var url = 'http://bar.other/resources/public-data/';
     
     function callOtherDomain(){
        if(invocation)
        {
            invocation.open('GET', url, true);
            invocation.onreadystatechange = handler;
            invocation.send();
        }

Let's look at the headers and see how a nice server should respond:

GET /resources/public-data/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer: http://foo.example/examples/access-control/simpleXSInvocation.html
Origin: http://foo.example


HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 00:23:53 GMT
Server: Apache/2.0.61 
Access-Control-Allow-Origin: *
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/xml

[XML Data]

The first chunk before the linebreak is what Firefox sends the server. Notice the origin value. The header reponse from the server follows. And the magic is in the "Access-Control-Allow-Origin: *" bit. Access-Control-Allow-Origin is the server part of the handshake demanded by the new standard. The wildcard value here allows access from any domain, but it's easy to restrict to a whitelist of trusted domains.

This method will allow for GET or POST methods with content types of application/x-www-form-urlencoded, multipart/form-data, and text/plain. For other requests or more nuanced relationships to the server, the standard gets more complex. (See Pre-flighted requests and Requests with credentials.)

CORS for the Rest of Them

Portland local Jesse Hallett revently spoke to a Javascript user group about these recent developments in cross orgin resource sharing and to address the prospect of trying to pragmatically implement XHR now, he introduced flXHR, a client-side proxy implemented in Flash (from a vendor that's historically proven to be a little too adventurous about this CORS business for their own good).

flXHR works by redirecting Http requests through an invisible flash movie, which makes the cross site request under the more permissive aucpices of the flash environment, and then sends the response back to the Javascript client.

But if that sounds a little hairy, and if you only need to make GET requests, look into JSONp or CSSHttpRequest.

So, the gloves are off. Now what are you going to swing at?

 

Tagged as: http, javascript

2 comments

Kyle Simpson (not verified) wrote 51 weeks 2 days ago

Cross-domain Ajax options

When I wrote flXHR, the key belief I was advancing was that standardizing on the existing native XHR API for cross-domain Ajax was the best approach.

The reason I believe this is because there are so many javascript frameworks and so much existing Ajax code, all using that API, and all of that code can benefit from improving the existing implementation without changing the API or the code that uses it. If we start fragmenting the APIs, we'll end up with more confusion, and lazy, poor programming that creates inefficient, complex, and ultimately less secure code than if we stay with the API that everyone already knows.

flXHR is intended to be a shim, to fill the gap until such a time as all browsers can support a standard way of doing secure, opt-in cross-domain Ajax. So I believe it's a great alternative. And I've taken a lot of effort to make it work as strongly and easily as possible.

But, I understand flash is not for everyone. So, building on the idea of "API is the key", I've now released another XHR API clone variant, called "jXHR". It's nearly the identical API, but implements the cross-domain Ajax with JSON-P calls. It also adds in rudimentary error-detection, which is not something most custom-rolled JSON-P solutions have.

jXHR Demo

In my opinion, a really strong robust cross-domain Ajax solution can now be achieved by using both flXHR and jXHR, where flXHR may be the primary transport, but falls back to slightly degraded performance using jXHR if flash isn't available. Because the API's are the same, your calling Ajax code shouldn't need to do hardly anything different.

Happy cross-domain Ajax'ing. :)

mcse 2008 certification (not verified) wrote 21 weeks 1 day ago

taking-gloves-xmlhttprequest

Thanks for post. It’s really informative stuff.I really like to read.Hope to learn a lot and have a nice experience here! my best regards guys!

Add your comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>. Beside the tag style "<foo>" it is also possible to use "[foo]".

More information about formatting options