March 15th, 2010
Flash Files, Domains and Security Errors (Oh My)
To provide a better user experience, we often use content delivery solutions like Limelight or Akamai to host bigger files and reduce load time. (Although this cuts into the user’s time spent watching pretty loaders.)
During a recent project, we ran into a couple of security errors loading external module.swf files from a different domain than main.swf. The idea was to have a basic framework in main that controls IN and OUT animations of the modules and have all additional functionality in the module.swf itself. All loaded swf files extended Big Spaceships StandardInOut Class to be controllable from the main file, so we could easily cast the loaded modules.
It looked like this:
private function _onLoadComplete_handler($evt:Event):void{ var loadedFile:MovieClip = MovieClip($evt.target.content); var customInOut:StandardInOut = StandardInOut(loadedFile.customInOut); }
This worked without any problems until the Flash files were loaded from different servers, hence different domains. The following error appeared:
TypeError: Error #1034: Type Coercion failed: cannot convert com.bigspaceship.display::StandardInOut@475f7711 to com.bigspaceship.display.StandardInOut.
After a little research, we had a list of possible solutions. We made sure all crossdomain.xml files were in place and set up correctly, added Security.allowDomain(“*”); to each file and tried to set LoaderContext.applicationDomain = ApplicationDomain.currentDomain. Sadly, none of that helped.
What did the trick (in part) was setting the LoaderContext.securityDomain:
var l:Loader = new Loader(); l.contentLoaderInfo.addEventListener(Event.COMPLETE, _onLoadComplete_handler); var urlRequest:URLRequest = new URLRequest('http://domain.com/extFile.swf'); var context:LoaderContext = new LoaderContext(); context.securityDomain = SecurityDomain.currentDomain; l.load(urlRequest, context);
This worked fine once it was running on the server, but testing locally lead to the following error:
SecurityError: Error #2142: Security sandbox violation: local SWF files cannot use the LoaderContext.securityDomain property. file:///Macintosh%20HD/Users/xxx/loadExtSWFTests/bin/main.swf was attempting to load http://domain.com/extFile.swf.
A simple trick to get around that would be to use error handling:
try{ l.load(urlRequest, context); }catch($error:Error){ l.load(urlRequest); }
But thats not an ideal solution. What we really needed was a test to check if the main Flash file was running on a server or running locally and then use the corresponding path and only set context.securityDomain = SecurityDomain.currentDomain if running on the server.
To test that, we simply checked if Security.sandboxType == Security.REMOTE, which means that the file is from an Internet URL and operates under domain-based sandbox rules.
The final solution looked something like this:
var l:Loader = new Loader(); l.contentLoaderInfo.addEventListener(Event.COMPLETE, _onLoadComplete_handler); if(Security.sandboxType == Security.REMOTE){ var context:LoaderContext = new LoaderContext(); context.securityDomain = SecurityDomain.currentDomain; l.load(new URLRequest('http://domain.com/extFile.swf'), context); }else{ l.load(new URLRequest('extFile.swf')); }
Hope that helps everyone who has or might run into similar problems.
———————————–
*Sidenote on dynamically instantiating assets from the library that use the same export name in multiple loaded flash files: Loading a swf with loaderContext.applicationDomain set to ApplicationDomain.currentDomain overwrites the current library asset with the same export name. Otherwise Flash ignores newly loaded library assets and always uses the asset that is already in the main library.
