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.
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).
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:
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.
Based on Julien's prior work, his solution is scaled way down compared to FlashXMLHttpRequest. His single swf file is only 1k!
Although f4a was much better, it still shares two "weaknesses" with FlashXMLHttpRequest which I hope to alleviate:
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.
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:
Update See the aforementioned project homepage for installation and usage instructions.
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:
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!
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?
or, read what others have said...