The first note on security sandboxes. Security sandboxes have tripped up plenty of people, so this is well-trodden ground. This afternoon I ran into error 2123.
The scene of the crime
A certain list flash page needed to support gravatar avatars (gravatar’s cross-domain policy file lives at http://www.gravatar.com/avatar/crossdomain.xml). While loading the avatars they serve up, I hit a security sandbox violation, with this error:
SecurityError: Error #2123: Security sandbox violation:
Loader.content:http://www.\*\*\*\*\*\*\*\*\*\*/lib.swf cannot access http://www.gravatar.com/avatar/3b3be63a4c2a439b013787721dfce802.jpg?s=26&d=monsterid. Not authorized to access any policy file. at flash.display::Loader/get content() at org.mousebomb.srcloader::SwfLoader/onLoadComplete()
At first I assumed I needed a crossdomain file, so I threw in Security.loadPolicyFile(“http://www.gravatar.com/avatar/crossdomain.xml“); to try it — no luck. Actually it isn’t needed at all — I just want to read and display an image cross-domain after publishing to a website, and within a remote network domain that is directly allowed as read-only access to audiovisual media content.
The culprit
Later I wrote a separate file and tested it with Loader — it read and displayed the image just fine. That got me thinking: the real cause of the security error was the resource loader I was using. In the resource pool’s smallest unit of work, the Loader hands off the visual object each time it finishes loading one, then calls unload so it can pick up a new task. The snippet: _isFree = true; var _loadedData : DisplayObject = _loader.content; _loader.unload(); var outEvent : SrcloaderEvent = new SrcloaderEvent(SrcloaderEvent.COMPLETE, {key:_key, type:_type, data:_loadedData}); this.dispatchEvent(outEvent); Handing off the visual object like that (the error shows up on the _loader.content line) is treated by Flash Player as “cross-domain data handling”, which breaks the read-only permission and isn’t allowed.
The solution
Just swap this part out and use Loader to load and display. For displaying and reading cross-domain audiovisual media objects, Loader has to be the container directly.
[11.8 addendum]
As far as I understand it, to process an image from a remote network domain (draw and the like), all you need is a cross-domain policy file on the server that says it’s permitted and a loaderContext that has read that policy file — but in practice, you still can’t touch it. Maybe I just don’t understand the security policy well enough; I solved the problem last time but never dug into it.
Today a guy in the group (pickgliss), trying to solve this, proposed a way around the fact that images loaded with Loader can’t be drawn or have their BitmapData manipulated: first load the image as binary with URLLoader, then load it as a display object with Loader.loadBytes. I tacked on drawing to a bitmap and smoothing to test it, and sure enough, it works!
Note: this method applies when the remote server has a cross-domain security policy granting permission but you still can’t operate on the display object. It does not apply when there’s no cross-domain security policy, or when the policy file doesn’t allow it.
Example of getting around the security error: package { import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.DisplayObject; import flash.display.Loader; import flash.display.Sprite; import flash.events.Event; import flash.net.URLLoader; import flash.net.URLLoaderDataFormat; import flash.net.URLRequest; import flash.utils.ByteArray;
public class Test extends Sprite { public function Test() { var req : URLRequest = new URLRequest(“http://uc.discuz.net/data/avatar/001/29/18/69\_avatar\_middle.jpg“); var loader : URLLoader = new URLLoader(req); loader.dataFormat = URLLoaderDataFormat.BINARY; loader.addEventListener(Event.COMPLETE, __complete); }
private function __complete(e : Event) : void { var data : ByteArray = e.target.data; var loader : Loader = new Loader(); loader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageDataComplete); loader.loadBytes(data);
}
private function imageDataComplete(e : Event) : void { var dio : DisplayObject = e.target.content; var bmp : Bitmap = new Bitmap(new BitmapData(dio.width, dio.height),”auto”,true); bmp.bitmapData.draw(dio); bmp.x = 100; bmp.y = 100; bmp.width = 50; bmp.height = 50; addChild(bmp); } } }