Cross-domain Ajax via Flash

From Jimbojw.com

Jump to: navigation, search
Tip: This is part of the Weekly Web Hack article series. If you like it, please subscribe to my blog. Thanks!

Update Please see SWFHttpRequest Flash/Ajax Utility for my latest work in this area!


The second in a four part series on cross-domain scripting, this Weekly Web Hack addresses the use of Flash as an intermediary for third-party cross-domain requests. I'll review Flash's cross-domain security policy, examine a few existing solutions, and finally present my own.

crossdomain.xml

First, a little about Flash's cross-domain policy and how it differs from the same-origin policy I harped on last time. In short, by adding a crossdomain.xml file to the root of a webserver, entities can permit requests from external domains. Some very high profile companies have historically utilized cross-domain policy files, including Flickr, Yahoo! and Amazon.

For example, here is the content of the Flickr API's policy file:

<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
  <allow-access-from domain="*" />
</cross-domain-policy>

Asterisks are wildcard characters, so the above indicates that incoming requests to the Flickr API will be accepted from any domain.

Though this is much better than the same-domain policy, it still falls far short of the true goal of cross-domain Ajax, since it requires third-party opt-in. If the server from which you'd like to request data does not have a crossdomain.xml file, or if it's not broad enough to cover your server, you're back where you started.

For more info on this subject, Lucas Adamski has some cross-domain policy file usage recommendations you might enjoy. For now though, let's get on to some implementations!

Note: If you're going to follow along and try this code out locally, make sure you serve it up through a webserver. Do not attempt to load the files via file:// URLs, as these will silently fail. Flash chokes when trying to do remote connections from a locally loaded SWF. (This HUGE gotcha cost me a lot of time - hope you can gain from my mistake).

FlashXMLHttpRequest

The first Flash-based implementation I came across in researching for this article was Julien Couvreur's FlashXMLHttpRequest. Check out his functional demo to get a feel for it.

Note: The pre-filled URL won't work due to yahoo's updated policy file, but this Flickr URL should work: http://api.flickr.com/services/rest/

Using something that's already out there is better than creating your own 9 times out of 10, so of course I downloaded the source to give it a try. Immediately I noticed several undesirable characteristics of this solution. As summarized in the blog post itself:

As you can see in the demo/index.html file, after including dojo.js and FlashXMLHttpRequest.js, you'll need to initialize dojo and the flash object by calling InitFlash with the name of a function. That function will be invoked once the flash object is loaded and ready to make requests.

So in addition to the two flash files (one targeting Flash 6 and the other targeting Flash 8), you have to have the dojo toolkit, the FlashXMLHttpRequest.js, and perform initialization code for each!

Furthermore, the download from the website includes pieces of dojo version 0.3. At the time of this writing, the dojo toolkit recently rolled out with version 1.0. Although I gave it an honest effort, I couldn't get it to work with the latest dojo.

f4a

In the comments to last week's web hack, Lloyd Dalton pointed me to his solution: f4a

Based on Julien's prior work, his solution is scaled way down compared to FlashXMLHttpRequest. His single swf file is only 1k!

In addition to the swf file, you need the supporting JavaScript and it is recommended that you use SWFObject to inject it into the page. In total, this is much improved over its predecessor. See the f4a demo to see it in action.

Isn't there a better way?

Although f4a was much better, it still shares two "weaknesses" with FlashXMLHttpRequest which I hope to alleviate:

  1. Both the aforementioned solutions require external JavaScript in addition to the SWF file, and
  2. More importantly, they introduce a new API for making requests

Regarding the first point, since Flash has the capability to execute arbitrary JavaScript in the context of the containing browser, there's no reason to maintain a separate JavaScript file. The SWF should be able to set up a favorable JS environment on-load, without any external script.

Secondly, the XMLHttpRequest() specification is well defined by the w3c, and well understood by developers far and wide. Additionally, every Ajax toolkit worth its salt has a wrapper for encapsulating this object, preventing the developer from having to work with it directly. An ideal solution to performing Flash-based XHRs would allow these third-party toolkits and libraries to be integrated easily by mimicking the native XHR interface.

Introducing SWFHttpRequest

I have recently finished my first stab at such a solution, called SWFHttpRequest, which is built using the haxe programming language. Here are all the relevant links:

  • SWFHttpRequest Flash/Ajax Utility - project homepage
  • SWFHttpReqeuest Demo - simple demonstration
  • - the embeddable swf file
  • SWFHttpRequest.hx - source code (includes compilation instructions)

Update See the aforementioned project homepage for installation and usage instructions.

Future Development

In retrospect, I really wish I had known about the f4a implementation prior to embarking on a journey through haxe. I think haxe has potential, but it's definitely its own language, with its own caveats, gotchas, and documentation lapses.

The SWF created by haxe is almost 14k compared to f4a's fantastic 1k. If I were to reimplement the design of SWFHttpRequest again, I'd probably use ActionScript 2 targeting Flash 8 and compiling with mtasc.

It is worth while to note that both haxe and mtasc compared quite favorably against both flex and OpenLaszlo with respect to compiled SWF size. A simple Hello World SWF was over 90k in OpenLaszlo and a whopping 130k in flex! Now, that's probably because both of those frameworks incorporate (compile in) a bunch of GUI widgetry into the base of any SWF - but it reinforced my notion that using a light-weight compiler was the best option.

Size isn't the only reason for migrating to ActionScript/mtasc. There are also huge functional gaps in my implementation that I'd be remiss in my duties not to divulge. Specifically, it lacks:

  • The ability to supply POST data
  • Capacity to read HTTP response headers
  • Capability to provide credentials or respond to HTTP auth challenges

Also, I have not yet tested whether Cookies for remote servers are preserved across SHR requests, so this may or may not work.

Update Sending POST data works as of version 0.2, and cookies appear to be preserved. Yay!

Special Thanks

As soon as I embarked on this journey, my very good friend Luke Pillow of deepthoughts.orsomethinglikethat.com provided me with a working Flex 2 prototype. I ended up going with haxe to build my project instead of flex due to the binary size issue mentioned in the previous section, but his example was very instructive on what I'd have to do. Thanks pillowfactory!

Enjoy! As always, I'll be happy to answer any questions.


Got something to say?

Leave a comment
Sorry, comments are disabled.

or, read what others have said...